feat(i18n): config-driven per-deployment locale whitelist
What & why
Replaces the content-fork locale-culling pattern (deleting 12 of 14 locale files per deployment) with a config-driven whitelist: a deployment restricts active locales without deleting files. Converts a content fork (modify/delete conflicts on every rebase) into a config fork (clean additive merges).
Unset = all locales; set = restrict. Additive, backward-compatible, no locale-file content changes.
Layers
| Layer | Variable | Mechanism |
|---|---|---|
| Web | VUE_APP_AVAILABLE_LOCALES |
runtime-injected via docker-entrypoint.sh → window.APP_CONFIG; filters vue-i18n messages (src/i18n/whitelist.js) + language pickers |
| Mobile | KeycloakConfig.supportedLocaleCodes |
per-flavor list (default = all shipped); drives I18nService.supportedLanguages
|
| Keycloak | KEYCLOAK_SUPPORTED_LOCALES |
envsubst into genie-realm.yaml supportedLocales (default curated 9, JSON array) |
Tests (all green)
-
applyLocaleWhitelistunit tests (web) -
Locale deep key-parity regression guard — committed baseline; fails only when fragmentation grows vs
en. The 14 locale files are not yet fully aligned onmain(pre-existing); enforcing strict parity would fail CI, so full alignment is tracked separately. - Mobile whitelist group + subset-aware
locale_consistencytest - config-validator assertions for both new compose vars
Local gates: frontend 1209 tests / ESLint / Prettier; mobile 444 tests + flutter analyze clean on changed files; config-validator 25 tests.
Scope note
El Salvador agri-key alignment and the el_salvador flavor values (['en','es']) are release-branch only (Track 2). This MR adds the generic mechanism to main and changes no locale-file content.
Verification
-
CI pipeline green before merge