ci(i18n): enforce controlled crowdin localization workflow and pr validation

Add Crowdin pull request validation script, centralize locale configuration, and update GitHub workflows to enforce sparse target catalog validation.
This commit is contained in:
neon
2026-08-06 00:00:04 +00:00
parent 6a0a9a3d53
commit b9e041d1b7
16 changed files with 608 additions and 71 deletions
+14
View File
@@ -7,6 +7,7 @@ Thanks for your interest in contributing to BookOrbit. Whether you are fixing a
- [DEVELOPMENT.md](DEVELOPMENT.md) - Local setup, architecture, commands, and technical reference.
- [TESTING.md](TESTING.md) - Test architecture, E2E suites, coverage thresholds, and harness details.
- [COMMIT_GUIDELINES.md](COMMIT_GUIDELINES.md) - Commit message format, types, scopes, and examples.
- [LOCALIZATION.md](LOCALIZATION.md) - User-facing copy, ICU messages, Crowdin, and adding languages.
---
@@ -109,6 +110,18 @@ Refer to [DEVELOPMENT.md](DEVELOPMENT.md) for architecture details, project stru
- **No unapproved dependencies.** Propose new dependencies in the linked issue first (see [Adding Dependencies](#adding-dependencies)).
- **Keep the scope tight.** If you discover something unrelated that needs fixing, open a separate issue for it.
#### Localizing User-Facing Text
BookOrbit uses Vue I18n, with English as the complete source catalog and Crowdin as the source of truth for every other language.
- Add every new user-facing message, including accessibility labels and transient states, to `client/src/locales/en.json` and reference it through Vue I18n.
- Do not add the key or an English fallback to any non-English catalog. Target catalogs are intentionally sparse, and missing messages fall back to English at runtime.
- Do not create or improve target-language translations in a feature pull request. Translate them in [Crowdin](https://crowdin.com/project/bookorbit); the controlled translation workflow will open a separate PR.
- Run `pnpm --filter client validate:locales` after changing `en.json`.
- Read [LOCALIZATION.md](LOCALIZATION.md) before changing ICU plural structure, changing the meaning of an existing message, or adding a language.
CI rejects edits to existing non-English catalogs in ordinary pull requests. A deliberate new-language setup may add only an empty target catalog until Crowdin export is enabled.
### Phase 7: Write and Run Tests
Testing expectations depend on what you changed:
@@ -218,6 +231,7 @@ Before marking your PR ready for review, confirm:
- [ ] Tests included per the [testing expectations table](#phase-7-write-and-run-tests)
- [ ] Full-stack behavior manually validated
- [ ] UI changes include screenshots, plus a recording when behavior or interaction changed
- [ ] User-facing text uses keys added only to `client/src/locales/en.json`; non-English catalogs are unchanged
- [ ] PR template fully completed
- [ ] No unintended files (build artifacts, `.env`, personal configs)
- [ ] No unapproved new dependencies
+4 -2
View File
@@ -39,6 +39,8 @@ Feature branches must:
Do not add the key to target catalogs. Target catalogs are sparse and contain only real Crowdin translations. Vue I18n resolves an absent target key through the complete English catalog, including English ICU plural rules.
CI rejects changes to existing target catalogs in ordinary pull requests. The validated `l10n_main` Crowdin PR is the only routine writer. A normal issue-linked pull request may add an empty catalog only as part of the new-language setup described below.
Do not create or improve target-language translations directly in Git. Crowdin does not continuously import repository translations after initial setup, so a later Crowdin export would overwrite those changes. Apply any emergency target-catalog fix in Crowdin before the next export.
When an English edit changes meaning rather than wording, prefer a new message key. If the key must remain, explicitly invalidate or clear the affected translations in Crowdin so an outdated translation is not exported for the new meaning.
@@ -187,9 +189,9 @@ Update `crowdin.yml`:
- Add the exact Crowdin language ID to `export_languages`.
- Add `languages_mapping` when the desired filename is not the language's unique `%two_letters_code%` output.
Add the Crowdin language ID and application locale mapping to `TARGET_CATALOGS` in `client/scripts/sync-crowdin-translations.mjs`.
`TARGET_CATALOGS` is derived from `SUPPORTED_LOCALES`. If the Crowdin language ID differs from the application locale, add the exception to `CROWDIN_LANGUAGE_ID_OVERRIDES` in `client/scripts/locale-configuration.mjs`.
Update `scripts/classify-crowdin-pr.sh` to allow the new target catalog path. Do not allow `en.json` or broaden the rule to the whole locales directory.
Add the new target catalog path to `.github/workflows/crowdin-translations.yml` and `scripts/classify-crowdin-pr.sh`. Do not allow `en.json` or broaden either rule to the whole locales directory. The synchronization script checks these lists and `crowdin.yml` against the shared locale configuration before contacting Crowdin.
Before merging, add the target language in Crowdin while the current `main` configuration still excludes it from `export_languages`, or pause translation synchronization. Merge the repository support before allowing the first export. After Crowdin synchronizes the new English source, dispatch `Crowdin Translation Sync` manually and confirm that the generated pull request changes only explicitly allowed target catalogs.