# Shared i18n architecture (frontend + backend) ## Scope Issue #175 requires one shared i18n contract for MVP host/player flows across frontend and backend. ## Source of truth - Catalog: `shared/i18n/lobby.json` - Locales: - supported: `en`, `da` - default/fallback: `en` Both Angular (`frontend/angular/src/app/lobby-i18n.ts`) and Django (`lobby/i18n.py`) read from this catalog. ## Key naming convention - Domain-first namespaces: - `frontend.ui.common.*` - `frontend.ui.host.*` - `frontend.ui.player.*` - `frontend.errors.*` - `backend.errors.*` - `backend.error_codes.*` - UI lookup keys in Angular are shortened aliases mapped under `frontend.ui`, e.g.: - `host.start_round` - `player.submit_guess` - `common.session_code` - Backend API errors return stable code + localized message: - `error_code` = machine-stable key from `backend.error_codes` - `error` = localized message from `backend.errors` - `locale` = resolved request locale ## Fallback model (robust) 1. Resolve requested locale (`Accept-Language` on backend, user/browser preference on frontend). 2. If locale unsupported -> use default `en`. 3. If key missing -> return key and log warning. 4. If locale translation missing for key -> fallback to `en` translation. ## Audio-routing policy - Catalog capability: `frontend.capabilities.client_has_no_audio_output = true` - Host/player clients expose this as a read-only capability flag. - Policy: phone clients must not play audio directly; only primary/host output is allowed. ## Verification - Backend tests: `lobby/tests.py` i18n coverage for locale selection + fallback + error-code/message matrix. - Frontend smoke/e2e-level unit coverage: - `frontend/angular/src/app/lobby-i18n.spec.ts` - `frontend/angular/src/app/i18n-mvp-flow-smoke.spec.ts` - `frontend/angular/src/app/features/host/host-shell.component.spec.ts` - `frontend/angular/src/app/features/player/player-shell.component.spec.ts`