i18n — Internationalization Guide
v3.8.1Last updated: 2026-05-13
Was this page helpful?
Loading OmniRoute...
Last updated: 2026-05-13
Was this page helpful?
30 languages with full dashboard UI translation, translated documentation, and RTL support for Arabic and Hebrew.
Languages: 🇺🇸 English | 🇧🇷 Português (Brasil) | 🇪🇸 Español | 🇫🇷 Français | 🇩🇪 Deutsch | 🇮🇹 Italiano | 🇷🇺 Русский | 🇨🇳 中文 (简体) | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇸🇦 العربية | 🇮🇳 हिन्दी | 🇹🇭 ไทย | 🇹🇷 Türkçe | 🇺🇦 Українська | 🇻🇳 Tiếng Việt | 🇧🇬 Български | 🇩🇰 Dansk | 🇫🇮 Suomi | 🇮🇱 עברית | 🇭🇺 Magyar | 🇮🇩 Bahasa Indonesia | 🇲🇾 Bahasa Melayu | 🇳🇱 Nederlands | 🇳🇴 Norsk | 🇵🇹 Português (Portugal) | 🇷🇴 Română | 🇵🇱 Polski | 🇸🇰 Slovenčina | 🇸🇪 Svenska | 🇵🇭 Filipino | 🇨🇿 Čeština
through OmniRoute Cloud):
# Run translations (incremental — only touches changed sources) npm run i18n:run # Limit to one locale npm run i18n:run -- --locale=pt-BR # Specific files (comma-separated, repo-relative paths) npm run i18n:run -- --files=CLAUDE.md,docs/architecture/ARCHITECTURE.md # Force retranslate everything (expensive) npm run i18n:run -- --force # Preview what would happen (no API calls, no writes) npm run i18n:run:dry # CI gate — exits non-zero if state is drifting npm run i18n:check
Source of truth. lists every locale (UI + docs) plus
the RTL set and the codes. The runtime config in
is a thin adapter over that JSON.
Backend. Configured via env (set in , never committed):
State tracking. (committed) keeps SHA-256 hashes per
source + per locale. Drift detection is automatic and deterministic — no API
calls in .
Output shape. Each translated file gets a top-level line, a bar, an separator, and the
translated body. That layout matches what
already enforces for and mirrors.
) and the
Google-Translate-backed generator ()
still exist with a deprecation banner. They will be removed in v3.10. The
and modes of (UI strings + root
README variants) are not yet handled by the new pipeline and are still used.
| (preferred — incremental, hash-based) | |
diagrams/i18n-flow.mmd
(English source, ~2800 keys)
- Locale files:
(30 translations)
- Framework:
with cookie-based locale resolution
- Config:
— defines all 30 locales, language names, flags
header → fallback :
// Add to LOCALES array
"xx",
// Add to LANGUAGES array
{ code: "xx", label: "XX", name: "Language Name", flag: "🏳️" },
— add entry to :
{
code: "xx",
googleTl: "xx",
label: "XX",
flag: "🏳️",
languageName: "Language Name",
readmeName: "Language Name",
docsName: "Language Name",
},
node scripts/i18n/generate-multilang.mjs messages
auto-translated from via Google Translate.
, etc.)python3 scripts/i18n/validate_translation.py quick -l xx python3 scripts/i18n/validate_translation.py diff common -l xx
node scripts/i18n/generate-multilang.mjs docs
Primary auto-translation engine — uses Google Translate free API to generate translations for UI strings, READMEs, and documentation.
node scripts/i18n/generate-multilang.mjs [messages|readme|docs|all]
from |
|
into all locales as in project root |
|
into |
|
Features:
), inline code (), markdown links/images (), HTML tags, tables, and ICU placeholders (, , , etc.) before translation, then restores them
- Chunked batching: Joins multiple strings with
delimiters to minimize API calls (max 1800 chars per request)
- In-memory cache: Avoids redundant API calls for repeated strings within a session
- Retry logic: Exponential backoff (up to 5 attempts with 300ms × attempt delay) for 429/5xx errors
- Timeout: 20 seconds per request
- Skip existing: If target file already exists, it is NOT overwritten
Important behaviors:
)Secondary translator — uses any OpenAI-compatible LLM API (including OmniRoute itself) to translate existing markdown files. Best for polishing or re-translating docs with better quality than Google Translate.
python3 scripts/i18n/i18n_autotranslate.py \ --api-url http://localhost:20128/v1 \ --api-key sk-your-key \ --model gpt-4o
Features:
CLI has its own i18n layer separate from the Next.js dashboard.
.
- — 42 ship out-of-the-box.
- for any missing key, so partial translations are valid.
- (shared with the dashboard).
| flag | ||
| env var | ||
| system env | ||
| system env | ||
| system env | ||
) are normalized to hyphen form ().
Locale codes are validated against — path traversal is rejected.
# Set language and save to ~/.omniroute/.env (persists across sessions) omniroute config lang set pt-BR # View current language omniroute config lang get # List all 42 available languages omniroute config lang list # JSON output omniroute config lang list --output json
and is loaded by the CLI bootstrap before any command runs.
# Override for one command only (not persisted) omniroute --lang de providers list
flag does NOT write to the env file — it only affects the current
invocation. Use to persist.
. Full translations: , .
Scaffold-only (all keys fall back to ): , , , , , , , , , , .
All other 29 locales have + keys translated.
; other files are best-effort.Translation validator — compares any locale JSON against and reports issues.
# Quick check (counts only) python3 scripts/i18n/validate_translation.py quick -l cs # Output: # Missing: 0 # Untranslated: 0 # Ignored (UNTRANSLATABLE_KEYS): 236 # Detailed diff by category python3 scripts/i18n/validate_translation.py diff common -l cs python3 scripts/i18n/validate_translation.py diff settings -l cs # Export to CSV python3 scripts/i18n/validate_translation.py csv -l cs > report.csv # Export to Markdown python3 scripts/i18n/validate_translation.py md -l cs > report.md # Full report (default) python3 scripts/i18n/validate_translation.py -l cs
Detects:
but not in locale file
- Extra keys — keys in locale file but not in
- Untranslated keys — keys where locale value equals English source (excluding allowlist)
- Placeholder mismatches — ICU placeholders that don't match between source and translation
Exit codes:
Environment: Set or use flag.
Code-to-JSON key checker — scans and for calls and verifies all referenced keys exist in .
# Basic check python3 scripts/i18n/check_translations.py # Verbose output python3 scripts/i18n/check_translations.py --verbose # Auto-fix (adds missing keys to en.json) python3 scripts/i18n/check_translations.py --fix
Static analysis QA — scans Next.js page files for i18n risk metrics and generates a Markdown report.
node scripts/i18n/generate-qa-checklist.mjs
Checks:
, , , )Output:
Visual QA via Playwright — takes screenshots of all dashboard routes in multiple locales and viewports, then evaluates page health.
# Default: es, fr, de, ja, ar on localhost:20128 node scripts/i18n/run-visual-qa.mjs # Custom base URL and locales QA_BASE_URL=http://staging.example.com QA_LOCALES=de,fr node scripts/i18n/run-visual-qa.mjs # Custom routes QA_ROUTES=/dashboard/settings,/dashboard/providers node scripts/i18n/run-visual-qa.mjs
Detects:
Output: + JSON report
File:
to avoid false-positive "untranslated" warnings.
{
"description": "Keys that should remain untranslated...",
"keys": [
"common.model",
"common.oauth",
"health.cpu",
...
]
}
What belongs here:
- ,
,
- ,
- ,
- ,
,
- ,
To add a key: Edit the array in and re-run validation.
job — dynamically discovers all locale files (excluding )
job — runs for each locale in parallel
job — aggregates results into a dashboard summary
# i18n-matrix: discovers languages
LANGS=$(ls src/i18n/messages/*.json | xargs -n1 basename | sed 's/.json$//' | grep -v '^en$')
# i18n: validates each language
python3 scripts/i18n/validate_translation.py quick -l '${{ matrix.lang }}'
Dashboard output:
first — it's the source of truth
- Run
to propagate new keys to all locales
- Review auto-translations — Google Translate is a starting point, not final
- Validate before committing —
- Update
if a key should remain in English
, , ) must be preserved exactly
- ) must maintain structure
-
// Use namespaced keys
const t = useTranslations("settings");
t("cacheSettings"); // maps to settings.cacheSettings in JSON
// Run check_translations.py to verify keys exist
python3 scripts/i18n/check_translations.py --verbose
) are RTL locales
- /
CSS — use / logical properties
Fix (deprecated Google Translate code) for Hindi instead of the correct ISO 639-1 . This created an orphaned duplicate of . Fixed by changing to in and removing the orphaned file.
Audit (2026-05-13): The directory still exists on disk (full duplicate of ). Translation generator no longer writes to it, but the historical tree was not pruned. Safe to delete with after confirming no external links reference the old path.
file is completely regenerated by . Any manual edits will be lost. Use (this file) for hand-written documentation that should persist.
allowlist was moved from an inline Python set in to an external JSON file for easier maintenance. The validator loads it at runtime.
(deprecated Google Translate code) for Hindi instead of the correct ISO 639-1 . This was introduced in upstream commit by . Fixed by changing to in the array and removing the orphaned file.
check now displays the count of ignored keys from :