add-localizationlisted
Install: claude install-skill NarekManukyan/flutter-mobx-kit
# Add a localized string
Governed by [ADR-0012](../../../docs/adr/0012-mandatory-localization.md). **No string that a user can see or a screen reader can read may be a literal in `lib/`.**
That includes: labels, buttons, hints, validation messages, error text, empty-state copy, snackbars, dialog titles, and `Semantics` labels.
## The loop
1. Add the key to `assets/translations/en-US.json`.
2. Run `melos run translations` — regenerates `lib/gen/locale_keys.g.dart`.
3. Use `LocaleKeys.key.tr()` in the widget.
```dart
// ❌
Text('Continue with email')
// ✅
Text(LocaleKeys.loginPage_continueWithEmail.tr())
```
Never hand-edit `lib/gen/locale_keys.g.dart`.
## Key naming
Nested JSON; `_` in the generated Dart key marks each level.
```json
{
"keywords": { "cancel": "Cancel", "retry": "Retry" },
"loginPage": { "title": "Sign in", "emailHint": "Email" },
"homePage": { "emptyTitle": "Nothing here yet" }
}
```
- **`keywords`** — strings reused across features: Cancel, Close, Save, Retry, Continue. Check here first; do not add a second "Cancel".
- **`{feature}Page`** — everything scoped to one screen. Match the page name (`loginPage`, `homePage`, `todoDetailsPage`).
- **`enums`** — one sub-object per enum, keyed by the enum value's name.
Key names describe the **role**, not the text. `emptyTitle`, not `nothingHereYet` — the copy will change, the role will not.
## Interpolation
```json
{ "homePage": { "greeting": "Hello, {name}", "counter": "{done} of {total} done"