Internationalization¶
Status: ๐ง Partial โ Backend translation API, database models, and both frontends are wired for i18next with all 6 languages; โ
MultilingualAIServiceis now called fromfirst_login_service.py(lazily, with sentinel guard) and fromaria_personal_intelligence_service.py.npm run extract-stringsandnpm run validate-translationsnow ship in the player-client package (the admin-ui equivalent is offered to the admin-ui instance โ its lane โ via CROSS-CLAUDE). Remaining gaps: DB not seeded with all 510 keys in non-English locales on a fresh deploy; German partial; reserved namespaces (ai,marketing,errors,validation) not yet loaded by either frontend. (updated 2026-06-16)
Six-language i18next setup spanning the player client, admin UI, AI dialogue, and translation-management endpoints (English / Spanish / French / Portuguese / Chinese launch-complete; German Partial). Translations ship as bundled JSON namespaces and are also exposed via a database-backed admin API for live editing.
1. Languages¶
| Language | Code | Keys | Status |
|---|---|---|---|
| English | en |
510 | Base (100%) |
| Spanish | es |
510 | Complete (100%) |
| French | fr |
510 | Complete (100%) |
| Chinese Simplified | zh |
510 | Complete (100%) |
| Portuguese | pt |
510 | Complete (100%, Brazilian conventions) |
| German | de |
~135 | Partial โ declared in services/player-client/src/i18n.ts |
Total: ~2,040 translations across 4 namespaces (common, auth, admin, game).
Translations were authored via AI linguistic generation and adapted for gaming terminology (e.g. Comandante / Commandant / ๆๆฅๅฎ / Comandante; Nave Exploradora / Vaisseau รclaireur / ไพฆๅฏ่น / Nave Explorador).
2. Delivery model¶
Translations live in the gameserver database (translation_keys table) and are served to clients over HTTP. The frontends use i18next-http-backend to fetch namespaces lazily from /api/v1/i18n/{lang}/{namespace}; results are cached in localStorage with a versioned cache-bust key.
Namespace breakdown:
| Namespace | Keys (English base) |
|---|---|
common |
121 |
auth |
69 |
admin |
154 |
game |
166 |
Per-language frontend wiring lives at:
- services/admin-ui/src/i18n.ts + components/common/LanguageSwitcher.tsx
- services/player-client/src/i18n.ts + components/common/LanguageSwitcher.tsx
Both apps use i18next 23.16, react-i18next 13.5, i18next-http-backend, and the browser language detector.
Language detection¶
Detection order is ['localStorage', 'navigator', 'htmlTag'] โ the player's persisted choice wins, then the browser's navigator.language, then a <html lang="โฆ"> declaration as last resort. The chosen code is cached in localStorage under the key i18nextLng.
English-fallback payload¶
When the backend /i18n/{lang}/{namespace} fetch fails (network error, server unreachable, or backend not yet seeded), the player client falls back to a hardcoded 14-key English minimum-viable vocabulary (welcome, dashboard, login, logout, loading, error, ship, sector, credits, cargo, trade, combat, planets, galaxy) so every screen still renders something legible. This is the only player-visible string fallback โ once any namespace successfully loads from the backend, the cache replaces the hardcoded payload.
3. Backend¶
Service & models¶
services/gameserver/src/models/translation.pyโlanguages,translation_keys,user_language_preferencestables.services/gameserver/src/services/translation_service.pyโ fallback handling, caching, user-preference persistence.services/gameserver/src/services/multilingual_ai_service.pyโ multilingual context for AI responses.
API (/api/v1/i18n/)¶
Public
| Method | Path | Purpose |
|--------|------|---------|
| GET | /i18n/languages | List supported languages |
| GET | /i18n/detect | Auto-detect from request |
| GET | /i18n/{lang} | All translations for a language |
| GET | /i18n/{lang}/{namespace} | Namespace-scoped translations |
User
| Method | Path | Purpose |
|--------|------|---------|
| GET | /i18n/user/preference | Get preferred language |
| POST | /i18n/user/preference | Set preferred language |
| GET | /i18n/user/ai-context | Get AI language context |
Admin
| Method | Path | Purpose |
|--------|------|---------|
| GET | /i18n/admin/progress/{lang} | Translation completion |
| POST | /i18n/admin/translation/{lang}/{ns} | Update single translation |
| POST | /i18n/admin/bulk/{lang}/{ns} | Bulk import |
| POST | /i18n/admin/initialize | Initialize system |
11 endpoints total (4 public, 3 user, 4 admin).
Database¶
languages(id, code, name, native_name, direction, is_active, completion_percentage)
translation_keys(id, key, language_id, namespace_id, value, context, is_verified)
user_language_preferences(id, user_id, language_id, manual_override)
4. Adding new translatable content¶
1. Pick a namespace¶
common (shared UI), auth, admin, game, plus reserved-but-not-yet-loaded ai, marketing, errors, validation.
2. Add the key¶
Add it via the admin API or import (English base, admin namespace):
{
"newFeature": {
"title": "New Feature",
"description": "Description of the new feature",
"actions": { "enable": "Enable", "disable": "Disable" }
}
}
3. Use it in components¶
import { useTranslation } from 'react-i18next';
const { t } = useTranslation('admin');
return <h2>{t('newFeature.title')}</h2>;
Patterns:
- Interpolation: t('welcome', { name: 'John' })
- Pluralization: t('items', { count: 5 })
- Fallback: t('key', { defaultValue: 'Default' })
4. Push to the database (optional)¶
curl -X POST /api/v1/i18n/admin/bulk/en/admin \
-H "Authorization: Bearer $TOKEN" \
-d '{"translations": {...}, "overwrite": true}'
The database path supports admin-managed dynamic translations; the file path is the day-to-day default for static text bundles.
5. Translator workflow¶
Admin UI¶
- Log into admin with translator permissions.
- Settings โ Translation Management.
- Pick language + namespace.
- Edit; check "Verified" once reviewed.
Direct API¶
curl -X POST /api/v1/i18n/admin/translation/es/admin \
-H "Authorization: Bearer $TOKEN" \
-d '{
"key": "dashboard.title",
"value": "Panel de Control Central",
"context": "Main dashboard page title"
}'
Quality bar¶
- Translate meaning, not words.
- Use established gaming terminology.
- Watch character-length constraints on UI elements.
- Preserve tone / formality per language conventions.
- Test in actual interface.
Per-language conventions¶
| Language | Notes |
|---|---|
| Spanish | Formal usted for system messages; balance formal/informal in UI; consider regional variants |
| French | Maintain language purity; correct accent marks; formal address; consider French-Canadian forks if needed |
| Chinese | Simplified character set; appropriate formality; gaming-context terminology |
| Portuguese | Brazilian conventions by default; gaming idioms |
6. Community contributions¶
- Create account, request translator permissions.
- Complete style-guide training.
- Start with simple/common translations.
- Peer review in language teams.
- Native-speaker validation before promoting to verified.
Recognition: translation credits, language-team leaderboards, contributor badges.
7. Progress tracking¶
curl -X GET /api/v1/i18n/admin/progress/es \
-H "Authorization: Bearer $TOKEN"
Returns completion %, verified vs unverified counts, per-namespace breakdown, last-updated timestamps.
8. Tooling¶
โ
Shipped (player-client) โ services/player-client/package.json now includes the scripts below. The identical admin-ui equivalent is offered to the admin-ui instance (admin-ui is its exclusive lane โ see CROSS-CLAUDE) rather than committed cross-lane.
npm run extract-stringsโ scanssrc/**/*.{ts,tsx}fort('โฆ')call sites and emits a sorted JSON array of unique keys to stdout. Use as a draft checklist when adding new content.npm run validate-translationsโ checks that everyuseTranslation()call declares a namespace in the known set (common/game/authfor player-client;common/admin/authfor admin-ui), and validates the structural integrity of any static seed JSON files found undergameserver/i18n/en/. Exits non-zero on hard errors (parse failures, unknown namespaces).
Scripts live at services/player-client/scripts/validate-translations.js and services/player-client/scripts/extract-strings.js.
Note: Because translations live in the DB (not static locale files), key-set completeness can only be verified against a running gameserver. The server-side /i18n/admin/bulk/{lang}/{ns} endpoint validates shape on import; the validate-translations script covers the offline/CI subset. Draft keys are added via the admin API or the Translation Management page.
Right-to-left languages are not currently in scope; adding one (e.g. Arabic) will require RTL layout work in both UIs.