Skip to main content

Internationalisation

The frontend is fully resource-based through i18next/react-i18next. English UK is canonical; American English is derived at runtime.

Frontend Locales

['en', 'en-US', 'fr', 'fi', 'cy', 'pl', 'et']
UI tagPersisted BCP-47
enen-GB
en-USen-US
frfr-FR
fifi-FI
cycy-GB
plpl-PL
etet-EE

English JSON defines typed namespace keys. en-US applies a UK-to-US spelling transform rather than maintaining duplicate JSON.

Detection and Persistence

Order:

  1. ?lng=
  2. localStorage i18nextLng
  3. browser navigator
  4. HTML language

Fallback is en. Base/region variants normalize through nonExplicitSupportedLngs.

useChangeLocale():

  • changes i18next immediately,
  • lets the detector cache locally,
  • best-effort updates users.locale when authenticated,
  • updates auth-store profile,
  • does not roll back UI on DB failure.

Marketing forces the selector available. In-app selector visibility follows multilingual_enabled, with system-admin bypass.

Namespaces

Resources are split into typed domains such as:

common
taxonomy
formats
components.*
pages.auth.*
pages.dashboard
pages.session*
pages.company_admin
pages.system_admin
pages.overview
pages.multiplayer
pages.oauth_consent
titles

Add copy to the narrowest appropriate namespace. Avoid dynamic key construction that defeats compile-time checking.

Audit

Run:

cd frontend
npm run i18n:audit

The script compares French, Finnish, Welsh, Polish, and Estonian against English:

  • every English file/key exists,
  • missing keys fail,
  • i18next {{variable}} and React <0> token counts match,
  • en-US is excluded because it is derived.

Extra keys are reported so drift can be cleaned.

Server Locale

_shared/locale.ts normalizes:

en-GB, en-US, fr-FR, de-DE, es-ES, fi-FI, cy-GB, pl-PL, et-EE

German and Spanish are recognized for server prompt/voice normalization even though complete frontend UI catalogues are not checked in. Do not advertise them as fully supported UI locales.

Server helpers:

  • load users.locale,
  • normalize loose/base tags,
  • default to en-GB,
  • provide a human-readable prompt language,
  • fall Welsh voice audio back to English where unsupported.

Email

Invitation templates exist for English, French, Finnish, Welsh, Polish and Estonian. Locale is normalized and base language selected; unknown values fall back to English.

Template interpolation escapes HTML/attributes, removes line breaks from subjects, and validates role codes. Preserve both HTML and plain-text output.

Guided Demo and Voice

Committed guided-demo narration exists for:

en, fr, fi, pl, et

Welsh and unsupported demo narration fall back to English. Billy narration is English only.

TTS/live voice language capability is not identical to UI translation capability. Document each surface separately.

Formatting

Use locale-aware utilities for:

  • dates/times
  • numbers and token counts
  • currency estimates
  • pluralization

Do not concatenate translated fragments. Provide complete sentences with named interpolation values.

Adding a Locale

  1. Add every English JSON file with identical key shape.
  2. Add imports/resources and locale tag.
  3. Add BCP-47 persistence mapping.
  4. Update audit target list.
  5. Add marketing/legal content.
  6. Add server normalization/language name only when intended.
  7. Decide email, demo, text AI, Live voice and TTS support separately.
  8. Test long text, plurals, dates, keyboard/screen-reader language.
  9. Verify lang attributes and fallback.

Troubleshooting

  • Literal {{count}}: interpolation token drift; run audit.
  • UI changes but AI remains English: DB locale save failed or server fallback.
  • en-US folder missing: expected; it is runtime-derived.
  • Welsh voice is English: intentional provider fallback, UI can remain Welsh.