Skip to content

Internationalization (i18n)

Maxwell's Wallet ships in 10 locales. The UI is fully localized with locale-aware date and currency formatting, powered by next-intl.

Supported Locales

Locale Language
en-US English (US) — source
en-GB English (UK)
es-ES Spanish
fr-FR French
it-IT Italian
pt-PT Portuguese
de-DE German
nl-NL Dutch
aa-ER Afar
pseudo Pseudo-locale (QA only)

Users pick a language in Settings, or leave it on "browser" to follow the Accept-Language header. Any translation key missing from a locale falls back to the English (en-US) string, so the UI never shows a raw key.

The Golden Rule

Only frontend/src/messages/en-US.json is hand-edited. Every other locale file is managed by Crowdin and synced automatically — do not edit them by hand (a CI guard rejects PRs that do).

Adding Translatable Strings

  1. Add the English string to frontend/src/messages/en-US.json using dot-notation keys (e.g. admin.backups.createButton).
  2. Use it in code via useTranslations:
import { useTranslations } from 'next-intl';

const t = useTranslations('admin.backups');
return <button>{t('createButton')}</button>;
  1. Commit and push to main. A GitHub Action uploads the new source strings to Crowdin; completed translations come back as a pull request.

Just Recipes

Command Description
just i18n::upload Push en-US.json source strings to Crowdin
just i18n::download Pull translations from Crowdin
just i18n::status Show translation progress
just i18n::pseudo Regenerate the pseudo-locale for QA

CI Safety Gates

Translation completeness is enforced by tests in frontend/src/test/i18n.test.ts, which verify that every shipped locale has all keys from en-US.json and that ICU {placeholder} tokens are preserved. A separate guard workflow blocks direct edits to Crowdin-managed locale files.

For the complete workflow — including Crowdin configuration, handling sync PRs, and providing translator context — see the in-repo i18n workflow guide.