diff --git a/Makefile b/Makefile index 5fa605ec554..b98753f1784 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ ARTIFACT_DESTINATION_FILE ?= ./tmp/idp.tar.gz lint_analytics_events_sorted \ lint_country_dialing_codes \ lint_erb \ + lint_font_glyphs \ lint_lockfiles \ lint_new_typescript_files \ lint_optimized_assets \ @@ -87,6 +88,8 @@ endif # Other @echo "--- lint yaml ---" make lint_yaml + @echo "--- lint font glyphs ---" + make lint_font_glyphs @echo "--- lint Yarn workspaces ---" make lint_yarn_workspaces @echo "--- lint new TypeScript files ---" @@ -110,6 +113,15 @@ lint_erb: ## Lints ERB files lint_yaml: normalize_yaml ## Lints YAML files (! git diff --name-only | grep "^config/.*\.yml$$") || (echo "Error: Run 'make normalize_yaml' to normalize YAML"; exit 1) +lint_font_glyphs: ## Lints to validate content glyphs match expectations from fonts + scripts/yaml_characters \ + --exclude-locale=zh \ + --exclude-gem-path=faker \ + --exclude-gem-path=good_job \ + --exclude-gem-path=i18n-tasks \ + > app/assets/fonts/glyphs.txt + (! git diff --name-only | grep "glyphs\.txt$$") || (echo "Error: New character data found. Follow 'Fonts' instructions in 'docs/frontend.md' to regenerate fonts."; exit 1) + lint_yarn_workspaces: ## Lints Yarn workspace packages scripts/validate-workspaces.mjs diff --git a/app/assets/fonts/glyphs.txt b/app/assets/fonts/glyphs.txt new file mode 100644 index 00000000000..4c552993112 --- /dev/null +++ b/app/assets/fonts/glyphs.txt @@ -0,0 +1 @@ + !"#$%&'(),-./0123456789:;>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ «»¿ÀÁÈÉÊÎÓÚàáâãçèéêëíîïñóôùúû ‑—‘’“”…‹中体文简 diff --git a/app/assets/fonts/public-sans/PublicSans-Black.woff b/app/assets/fonts/public-sans/PublicSans-Black.woff deleted file mode 100644 index 8174446d892..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Black.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Black.woff2 b/app/assets/fonts/public-sans/PublicSans-Black.woff2 index 656549ff192..28de4cbb742 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Black.woff2 and b/app/assets/fonts/public-sans/PublicSans-Black.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff b/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff deleted file mode 100644 index 4b3f2495856..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff2 index a77821ca359..891b65c5319 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-BlackItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Bold.woff b/app/assets/fonts/public-sans/PublicSans-Bold.woff deleted file mode 100644 index a330a13dcf0..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Bold.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Bold.woff2 b/app/assets/fonts/public-sans/PublicSans-Bold.woff2 index eaffd02816e..3fad30fba01 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Bold.woff2 and b/app/assets/fonts/public-sans/PublicSans-Bold.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff b/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff deleted file mode 100644 index d03f7ca2295..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff2 index bdd712d81eb..172dd572175 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-BoldItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff b/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff deleted file mode 100644 index 33ceeb2fa59..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff2 b/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff2 index 0caaa499cc2..91d6ecbee2b 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff2 and b/app/assets/fonts/public-sans/PublicSans-ExtraBold.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff b/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff deleted file mode 100644 index a89787fd384..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff2 index 774fe32b0a3..4bcd956a1b6 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-ExtraBoldItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff b/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff deleted file mode 100644 index 7ae600def7e..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff2 b/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff2 index 219329aba5b..42af48d4b86 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff2 and b/app/assets/fonts/public-sans/PublicSans-ExtraLight.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff b/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff deleted file mode 100644 index 30b9103786e..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff2 index f0e21c92195..9321da5e3f8 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-ExtraLightItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Italic.woff b/app/assets/fonts/public-sans/PublicSans-Italic.woff deleted file mode 100644 index 319cb1e8939..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Italic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Italic.woff2 b/app/assets/fonts/public-sans/PublicSans-Italic.woff2 index a96fa977705..d1bb5d63b8e 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Italic.woff2 and b/app/assets/fonts/public-sans/PublicSans-Italic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Light.woff b/app/assets/fonts/public-sans/PublicSans-Light.woff deleted file mode 100644 index 740c94d3387..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Light.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Light.woff2 b/app/assets/fonts/public-sans/PublicSans-Light.woff2 index 87fc6df1e36..5ded7cd94f4 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Light.woff2 and b/app/assets/fonts/public-sans/PublicSans-Light.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-LightItalic.woff b/app/assets/fonts/public-sans/PublicSans-LightItalic.woff deleted file mode 100644 index 9172ccc83a8..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-LightItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-LightItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-LightItalic.woff2 index bc9b5f7edd7..263a8a0e884 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-LightItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-LightItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Medium.woff b/app/assets/fonts/public-sans/PublicSans-Medium.woff deleted file mode 100644 index 47a26564c40..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Medium.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Medium.woff2 b/app/assets/fonts/public-sans/PublicSans-Medium.woff2 index 5896b823bdf..907a110e323 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Medium.woff2 and b/app/assets/fonts/public-sans/PublicSans-Medium.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff b/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff deleted file mode 100644 index d0eaa44d398..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff2 index 0314b97c16e..ef248d4ea6e 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-MediumItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Regular.woff b/app/assets/fonts/public-sans/PublicSans-Regular.woff deleted file mode 100644 index 8c1da26dbe4..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Regular.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Regular.woff2 b/app/assets/fonts/public-sans/PublicSans-Regular.woff2 index 5f5fcd86111..f787a12e540 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Regular.woff2 and b/app/assets/fonts/public-sans/PublicSans-Regular.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-SemiBold.woff b/app/assets/fonts/public-sans/PublicSans-SemiBold.woff deleted file mode 100644 index 7c530b68836..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-SemiBold.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-SemiBold.woff2 b/app/assets/fonts/public-sans/PublicSans-SemiBold.woff2 index 14e63ab7528..260aeac6556 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-SemiBold.woff2 and b/app/assets/fonts/public-sans/PublicSans-SemiBold.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff b/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff deleted file mode 100644 index ea23cad8b31..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff2 index 77447b4feb7..b14cc0eaa03 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-SemiBoldItalic.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-Thin.woff b/app/assets/fonts/public-sans/PublicSans-Thin.woff deleted file mode 100644 index 74d7727bd67..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-Thin.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-Thin.woff2 b/app/assets/fonts/public-sans/PublicSans-Thin.woff2 index bdc7449f203..9587c72b5d7 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-Thin.woff2 and b/app/assets/fonts/public-sans/PublicSans-Thin.woff2 differ diff --git a/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff b/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff deleted file mode 100644 index 04dbf4147a6..00000000000 Binary files a/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff and /dev/null differ diff --git a/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff2 b/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff2 index b8b1fbb51a9..cad2b41d0dc 100644 Binary files a/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff2 and b/app/assets/fonts/public-sans/PublicSans-ThinItalic.woff2 differ diff --git a/docs/frontend.md b/docs/frontend.md index 6dd47a3eb65..6a2d28baf8a 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -390,6 +390,24 @@ Debugging these stack traces can be difficult, since files in production are min The output of the `sourcemap-lookup` command should include "Original Position" and "Code Section" of the code which triggered the error. +## Fonts + +Font files are optimized to remove unused character data. If a new character is added to content, the font files must be regenerated: + +1. [Download Public Sans](https://public-sans.digital.gov/) and extract it to your project's `tmp/` directory +2. Install [glyphhanger](https://github.com/zachleat/glyphhanger) and its dependencies: + 1. `npm install -g glyphhanger` + 2. `pip install fonttools brotli` +3. Scrape content for character data: + 1. `make lint_font_glyphs` +4. Subset the original Public Sans fonts to include only used character data: + 1. `glyphhanger app/assets/fonts/glyphs.txt --formats=woff2 --subset="tmp/public-sans-v2/fonts/ttf/PublicSans-*.ttf"` +5. Replace font files with new subset fonts: + 1. `cd tmp/public-sans-v2/fonts/ttf` + 2. `find . -name "*-subset.woff2" -exec sh -c 'cp $1 "../../../../app/assets/fonts/public-sans/${1%-subset.woff2}.woff2"' _ {} \;` + +At this point, your working directory should reflect changes to all of the files within `app/assets/fonts/public-sans`. + ## Devices The application should support: diff --git a/scripts/yaml_characters b/scripts/yaml_characters new file mode 100755 index 00000000000..9be80fe72b1 --- /dev/null +++ b/scripts/yaml_characters @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'pathname' +require_relative '../config/environment' + +excluded_locales = [] +excluded_gem_paths = [] +OptionParser.new do |opts| + opts.banner = <<~TXT + Usage + ======================= + + #{$PROGRAM_NAME} [OPTIONS] + + Prints all unique characters from Rails loaded I18n data, which can be used in combination + with font subsetting to optimize font sizes. + + TXT + + opts.on('--exclude-locale=LOCALE', 'Disregard characters from the given locale') do |locale| + excluded_locales << locale.to_sym + end + + opts.on('--exclude-gem-path=GEM', 'Disregard characters loaded by the given gem') do |gem| + excluded_gem_paths << Gem.loaded_specs[gem].full_gem_path + end + + opts.on('-h', '--help', 'Prints this help') do + STDOUT.puts opts + exit + end +end.parse!(ARGV) + +def sanitize(string) + string.gsub(/<.+?>/, '').gsub(/%{.+?}/, '').gsub(/[\n\r\t]/, '') +end + +def hash_values(hash) + hash.values.flat_map do |value| + case value + when Hash + hash_values(value) + when Array + value + else + [value] + end + end +end + +I18n.load_path.reject! do |load_path| + excluded_gem_paths.any? { |gem_path| load_path.start_with?(gem_path) } +end + +I18n.backend.eager_load! + +data = I18n.backend.translations.slice(*I18n.available_locales - excluded_locales) +strings = hash_values(data) +joined_string = strings.join('') +sanitized_string = sanitize(joined_string) +characters = sanitized_string.chars.to_a.uniq.sort.join('') + +STDOUT.puts characters