# Translating Tanemaki Tanemaki is multilingual **by design** — international, not any-country-first (see the golden rules in [`../CLAUDE.md`](../CLAUDE.md)). Translations live as one JSON file per locale, a format Weblate (and any translation platform that speaks nested JSON) handles natively. ## Where strings live ``` apps/app_seeds/lib/i18n/ en.i18n.json ← base locale (source of truth for keys) es.i18n.json pt.i18n.json strings*.g.dart ← generated, do not edit ``` - Placeholders use braces: `"{count} entries added"`. Keep them verbatim. - Keys are code and never change per locale; only values are translated. - Missing keys fall back to English at runtime (`fallback_strategy: base_locale` in [`slang.yaml`](../apps/app_seeds/slang.yaml)), so a partial translation is shippable from day one. ## Adding a locale 1. Copy `en.i18n.json` to `.i18n.json` (e.g. `fr.i18n.json`) and translate what you can. 2. Regenerate the Dart bindings: ```bash cd apps/app_seeds && dart run slang ``` 3. Add a language tile in [`settings_screen.dart`](../apps/app_seeds/lib/ui/settings_screen.dart) (label = the language's own name, e.g. "Français") plus the `langXx` key in every locale file. 4. Run the tests: `flutter test` (an i18n test guards against hardcoded strings; the RTL smoke test guards right-to-left layouts). ## RTL and scripts Right-to-left locales (Arabic, Hebrew, Persian) are first-class: layouts use directional insets and are exercised by [`rtl_smoke_test.dart`](../apps/app_seeds/test/ui/rtl_smoke_test.dart). Locale-specific resources ship with their locale, never hardcoded: OCR language packs (`assets/tessdata/`), PDF fonts (`assets/fonts/`), and species common names (`assets/catalog/species.json`, a locale-keyed map). ## Weblate The JSON-per-locale layout is Weblate-ready (component per file, base `en.i18n.json`). Hosting is not set up yet; when it is, this page will link to the project. Until then, translation PRs/patches are welcome directly on the files above.