Skip to content

Internationalization

Status: ๐Ÿšง Partial โ€” Backend translation API, database models, and both frontends are wired for i18next with all 6 languages; โœ… MultilingualAIService is now called from first_login_service.py (lazily, with sentinel guard) and from aria_personal_intelligence_service.py. npm run extract-strings and npm run validate-translations now 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_preferences tables.
  • 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

  1. Log into admin with translator permissions.
  2. Settings โ†’ Translation Management.
  3. Pick language + namespace.
  4. 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

  1. Create account, request translator permissions.
  2. Complete style-guide training.
  3. Start with simple/common translations.
  4. Peer review in language teams.
  5. 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 โ€” scans src/**/*.{ts,tsx} for t('โ€ฆ') 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 every useTranslation() call declares a namespace in the known set (common/game/auth for player-client; common/admin/auth for admin-ui), and validates the structural integrity of any static seed JSON files found under gameserver/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.