Localization Overview
Architecture
Translations live in packages/i18n/locales/ as JSON files, organized by language-country directory:
locales/├── en/ ← Source locale (ground truth)│ ├── common.json│ ├── commerce.json│ ├── account.json│ └── legal.json├── nl-NL/│ ├── common.json│ └── ...├── de-DE/└── ...Source locale: en
English (en/) is the universal source. All other locales are translations FROM English. The source directory has no country suffix — it’s the canonical reference.
English variants like en-GB or en-IE are treated as regular target locales (not source).
Namespaces
| Namespace | Content |
|---|---|
common | UI chrome: buttons, navigation, labels, errors, empty states |
commerce | Cart, checkout, shipping, payment, orders, returns |
account | Login, register, profile, addresses, preferences |
legal | Cookie consent, privacy policy, terms & conditions |
Each namespace is a separate JSON file per locale.
Placeholder syntax
One format: {name} (curly braces).
{ "empty.no_results": "No results found for \"{query}\""}Forbidden formats: {{name}}, %s, %d. The check script validates placeholder parity between source and target.
Workflow
- Add or change keys in
en/(the source) - Translate to target locales
- Run
pnpm i18n:checkto validate - Run
pnpm i18n:reportto update the coverage page
See Add a String for step-by-step instructions.
Tooling
| Command | Purpose |
|---|---|
pnpm i18n:check | Validate all locales (missing keys, placeholders, empty values) |
pnpm i18n:report | Generate coverage report for docs |