Internationalization
Games use i18next keys instead of inline English strings.
Files
| Path | Content |
|---|---|
locales/en/apgames.json |
English source — game names, descriptions, UI strings |
locales/en/apresults.json |
English source — move result / chat log strings |
locales/{de,fr,it,es-US}/*.json |
Translations only (Weblate + CI) |
locale-src/{de,fr,it,es-US}/*.json |
English snapshot for machine-translation diffing (CI only) |
Community partial locales (es, uk, ta, etc.) live under locales/ with no sidecars.
locale-src/ sidecars
Managed locales (de, fr, it, es-US) are machine-translated by scripts/translate.mjs when English changes. The script compares each key against a flat English snapshot in locale-src/ to detect stale translations.
- Weblate syncs only
locales/— neverlocale-src/ - CI updates both
locales/andlocale-src/on auto-translate commits — iflocale-src/is still dirty after translate, the auto-commit step failed and the next run will retranslate the same keys - S3 publish uploads
locales/directly (no_srcstripping needed)
One-time migration: node scripts/split-locale-src.mjs (already run; kept for reference).
Weblate merges
- Merge migration before accepting Weblate PRs that strip
_src - Close bulk "Cleanup translation files" PRs — they delete metadata and unrelated keys
- Small human-editing PRs merge normally;
locale-src/is never in the diff - In hosted Weblate: disable the "Cleanup translation files" add-on for managed components
Weblate key naming
Weblate's i18next parser treats a bare key as conflicting with siblings whose names look like plural or context suffixes (_one, _other, _2, _11, etc.) in the same JSON object. For example, do not place INSTRUCTIONS alongside INSTRUCTIONS_one — rename the non-plural key (e.g. INSTRUCTIONS_ANY).
npm run lint runs check-weblate-keys against locales/en/*.json and fails on conflicts. Use a distinct stem for each purpose (e.g. nowhere_what vs nowhere_count_one/nowhere_count_other).
In game code
description: "apgames:descriptions.complica"
Add keys when introducing new user-visible text. Variant names in gameinfo also reference apgames.json.
addResource
Front end merges bundles via APGames.addResource(lang) — see API.
Scripts
| Script | Purpose |
|---|---|
npm run translate |
Gemini incremental translate en → de/fr/it/es-US |
npm run check-weblate-keys |
Fail on Weblate plural-stem key conflicts in English locales |
npm run check-locale-readiness |
Audit locales vs English |
node scripts/publish-locales.mjs --stage dev|prod |
Upload supported locales to S3 |
Example games
- Complica — typical
apgames:key usage