| 1 | # crates/tui/locales — agent guidance |
| 2 | |
| 3 | UI packs. `en.json` is the reference. Which packs are **complete** (held to |
| 4 | exact raw key parity with English) and which are intentionally partial is |
| 5 | defined by the tests, not by this file — read them rather than a list that goes |
| 6 | stale on the next locale PR. |
| 7 | |
| 8 | ## Adding or changing a string |
| 9 | |
| 10 | 1. Add the `MessageId` variant, the `ALL_MESSAGE_IDS` entry, and the `en.json` |
| 11 | key — all three, or `message_id_list_english_pack_stay_in_exact_sync` fails. |
| 12 | 2. Translate into every complete pack, or |
| 13 | `shipped_complete_packs_have_raw_key_parity_with_english` fails. Do not "fix" |
| 14 | that test by copying English into a pack — the silent English fallback is |
| 15 | invisible at runtime, so the gate is the only thing between users and |
| 16 | untranslated UI. |
| 17 | 3. If you change an **existing English value**, retranslate it everywhere. Value |
| 18 | drift is invisible to the key gates; say what you changed in the commit body. |
| 19 | |
| 20 | ## Translation conventions |
| 21 | |
| 22 | - `{named}` placeholders stay literal; call sites substitute with `.replace()`. |
| 23 | - Product terms stay English per pack convention: Fleet, Plan / Act / Operate, |
| 24 | Ask / Auto-Review / Full Access. Plain words ("read only", phase words) |
| 25 | translate naturally and must stay short — footers and row controls render them |
| 26 | in tight budgets. |
| 27 | - Key names, commands, and glyphs are never in translations; they are composed |
| 28 | in code. |
| 29 | - Preserve intentional leading/trailing spaces (pane titles, `Rule `, the |
| 30 | slash-menu hint). |
| 31 | - Script rules: ru/uk prose is Cyrillic only (uk uses і/ї/є/ґ, never ы/э/ъ); hi |
| 32 | prose is Devanagari. Latin appears only in product terms, commands, key names, |
| 33 | placeholders, and URLs. Script-purity fixtures in `localization.rs` enforce |
| 34 | this for high-visibility strings. |
| 35 | |
| 36 | ## Adding a locale |
| 37 | |
| 38 | Pack JSON with full parity, `Locale` variant + tag/display/parse arms in |
| 39 | `localization.rs`, onboarding picker entry (`language.rs` — a test forces every |
| 40 | shipped locale to be offered), the typed `UiLocale` schema in `config_ui.rs`, |
| 41 | setup-wizard match arms, and locale display arms in the config/change commands. |
| 42 | The `/config` hint and invalid-locale error derive from `Locale::shipped()` |
| 43 | automatically; the schema agreement test keeps `UiLocale` aligned with that |
| 44 | registry. Picker hotkeys run `1..=9` then `a`, `b`, … so more than nine locales |
| 45 | stay single-keystroke selectable. |
| 46 | |
| 47 | Translated READMEs (repo root) are separate from these packs but follow the same |
| 48 | discipline: `scripts/check-readme-translations.py` fails when English changes |
| 49 | without the translations being refreshed and restamped. |
| 50 |