|
82 | 82 | end |
83 | 83 | end |
84 | 84 |
|
85 | | - # Folds the downloaded GlotPress translations (human) plus AI machine translations into Localizable.xcstrings, |
86 | | - # the future regular-string backing store, as `human ?? existing-machine ?? AI ?? English` (see CatalogStrings). |
| 85 | + # Builds Localizable.xcstrings, the future regular-string backing store, end to end: |
| 86 | + # 1. scan the code into the English catalog (generate_strings_catalog), |
| 87 | + # 2. download the current GlotPress translations and fold them in (human => translated), |
| 88 | + # 3. AI-fill the cells GlotPress left empty (=> needs_review) — see CatalogStrings.fold_translations!. |
| 89 | + # Uploading the AI drafts back to GlotPress as needs-review for human review (the eventual "step 4") is a |
| 90 | + # separate step, not done here — it builds on the existing GlotPress import integration (cf. |
| 91 | + # gp_update_metadata_source). For now the machine cells live in the catalog as needs_review. |
87 | 92 | # |
88 | | - # STAGED, NOT SHIPPED: the catalog isn't the runtime store yet (the app still ships Localizable.strings), so |
89 | | - # this only pre-populates it for the eventual cutover — it changes nothing users see. |
| 93 | + # STAGED, NOT SHIPPED: Localizable.xcstrings isn't the runtime store yet (the app still ships |
| 94 | + # Localizable.strings), so this only pre-populates it for the cutover — it changes nothing users see. |
90 | 95 | # |
91 | | - # MANUAL ONLY — deliberately NOT wired into download_localized_strings or any CI step: it runs xcstringstool |
92 | | - # extraction, calls the translation API (cost), and commits a large catalog, so it's run on demand, not on |
93 | | - # every release. Run `download_localized_strings` first (so the per-locale `.strings` exist) and, for the AI |
94 | | - # rung, set ANTHROPIC_API_KEY. |
95 | | - desc 'Folds GlotPress + AI translations into Localizable.xcstrings (staged backing store; run manually, not in CI)' |
96 | | - lane :download_localized_catalog do |
97 | | - generate_strings_catalog # refresh the English source + reconcile (creates the catalog on first run) |
98 | | - catalog = JSON.parse(File.read(LOCALIZABLE_CATALOG)) |
| 96 | + # MANUAL ONLY — deliberately not wired into download_localized_strings or any CI step: it runs xcstringstool |
| 97 | + # extraction, downloads from GlotPress, calls the translation API (cost), and commits a large catalog. Set |
| 98 | + # ANTHROPIC_API_KEY for step 3; scope a cheap run with `locales:fr` (and add `skip_download:true` to reuse the |
| 99 | + # committed .strings instead of re-downloading). |
| 100 | + desc 'Builds Localizable.xcstrings: scan code, fold GlotPress translations, AI-fill the rest (staged; manual, not CI)' |
| 101 | + lane :download_localized_catalog do |options| |
| 102 | + resources_dir = File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Resources') |
| 103 | + locales = catalog_target_locales(options[:locales]) # all ship locales, or the `locales:fr,de` subset |
| 104 | + |
| 105 | + # 1. Scan the code into the English catalog (create / update + reconcile changed sources). |
| 106 | + generate_strings_catalog |
| 107 | + |
| 108 | + # 2. Download the current GlotPress translations for those locales (skip to reuse the committed .strings). |
| 109 | + download_catalog_strings(resources_dir, locales) unless catalog_flag?(options[:skip_download]) |
99 | 110 |
|
| 111 | + # 2b + 3. Fold the human translations in (=> translated), then AI-fill the cells GlotPress left empty. |
| 112 | + catalog = JSON.parse(File.read(LOCALIZABLE_CATALOG)) |
100 | 113 | written = CatalogStrings.fold_translations!( |
101 | 114 | catalog, |
102 | | - translations_by_locale: catalog_translations_by_locale(File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Resources')), |
103 | | - locales: GLOTPRESS_TO_LPROJ_APP_LOCALE_CODES.values.uniq, |
| 115 | + translations_by_locale: catalog_translations_by_locale(resources_dir), |
| 116 | + locales: locales.values.uniq, |
104 | 117 | ai_translator: catalog_ai_translator |
105 | 118 | ) |
106 | 119 | File.write(LOCALIZABLE_CATALOG, "#{JSON.pretty_generate(catalog)}\n") |
107 | | - UI.success("Folded translations into #{File.basename(LOCALIZABLE_CATALOG)} (#{written} cells across locales).") |
| 120 | + UI.success("Built #{File.basename(LOCALIZABLE_CATALOG)}: folded #{written} cell(s) across #{locales.values.uniq.size} locale(s).") |
108 | 121 |
|
109 | 122 | git_add(path: LOCALIZABLE_CATALOG, shell_escape: false) |
110 | 123 | git_commit(path: [LOCALIZABLE_CATALOG], message: 'Update Localizable.xcstrings translations (staged)', allow_nothing_to_commit: true) |
@@ -229,6 +242,31 @@ def report_catalog(path, extracted_count:, reconciled_count:) |
229 | 242 | UI.success(message) |
230 | 243 | end |
231 | 244 |
|
| 245 | + # The { glotpress => lproj } locale map to operate on: all ship locales, or the subset named in `locales:` |
| 246 | + # (a comma-separated list of lproj codes, e.g. `locales:fr,de`) for a cheap scoped run. |
| 247 | + def catalog_target_locales(spec) |
| 248 | + return GLOTPRESS_TO_LPROJ_APP_LOCALE_CODES if spec.to_s.strip.empty? |
| 249 | + |
| 250 | + wanted = spec.to_s.split(',').map(&:strip) |
| 251 | + selected = GLOTPRESS_TO_LPROJ_APP_LOCALE_CODES.select { |_glotpress, lproj| wanted.include?(lproj) } |
| 252 | + UI.user_error!("No known ship locales among #{spec.inspect} (use lproj codes, e.g. fr,de,pt-BR)") if selected.empty? |
| 253 | + selected |
| 254 | + end |
| 255 | + |
| 256 | + # Step 2: download the current GlotPress translations for the given locales into their `*.lproj` dirs. |
| 257 | + def download_catalog_strings(resources_dir, locales) |
| 258 | + ios_download_strings_files_from_glotpress( |
| 259 | + project_url: GLOTPRESS_APP_STRINGS_PROJECT_URL, |
| 260 | + locales: locales, |
| 261 | + download_dir: resources_dir |
| 262 | + ) |
| 263 | + end |
| 264 | + |
| 265 | + # A fastlane CLI flag, which arrives as a string ("true"/"1"/"yes") or a real boolean. |
| 266 | + def catalog_flag?(value) |
| 267 | + %w[true 1 yes].include?(value.to_s.strip.downcase) |
| 268 | + end |
| 269 | + |
232 | 270 | # { lproj => { key => human value } } from the downloaded translation `.strings`. The flat plural keys present |
233 | 271 | # in these files aren't catalog keys, so the fold ignores them (they belong to Plurals.xcstrings). |
234 | 272 | def catalog_translations_by_locale(dir) |
|
0 commit comments