Internationalization (i18n)
This project ships a shared, full-stack localization setup for three locales:
enzh-Hanszh-Hant
The product follows the browser language by default, but users can override the locale manually in Settings. That page also exposes the current browser-facing workspace posture (API base, theme, timezone) so operators can verify what context their local session is actually using. The frontend and backend stay aligned so API error messages, active-run surfaces, and formatted dates match the effective UI language.
Design Principles
- Keep one source of truth for supported locales in
locales/manifest.json. - Store copy as stable translation keys, not inline UI strings.
- Prefer whole-sentence translations over string concatenation.
- Keep user-controlled locale selection above browser negotiation.
- Use locale-aware formatting (
Intl, translated backend errors,Content-Languageheaders). - Treat technical identifiers (
provider.type, model IDs, dataset paths) as data, not translatable copy.
Repository Layout
manifest.json: shared locale registry and native names.frontend.json: all React UI copy rendered throughreact-i18next.backend.json: API-side messages translated by FastAPI middleware/helpers.
Runtime Behavior
Frontend
frontend/src/i18n/index.tsinitializesi18next.frontend/src/app/locale-provider.tsxresolves the effective locale and keeps<html lang>in sync.frontend/src/i18n/locale.tscontains locale detection, browser matching, persistence, and manual override helpers.frontend/src/api/client.tssendsX-Eval-Localeon API requests.- SSE requests use
?locale=becauseEventSourcecannot send custom headers.
Backend
backend/src/eval_752/i18n/__init__.pyloadslocales/manifest.json, resolves locales, and translates backend messages.LocaleMiddlewareapplies this precedence:X-Eval-Localelocalequery parameterAccept-Language- default locale from
manifest.json
- Responses emit
Content-Languageso clients can verify which locale was applied.
Adding Or Updating Copy
Frontend copy
- Add a stable key to
locales/en/frontend.json. - Add the same key to every other
frontend.json. - Use
useTranslation()in React components ori18n.t(...)in non-React utilities/hooks. - Prefer interpolation:
- Prefer locale-aware formatting for dates/numbers. Reuse existing helpers where possible.
Backend copy
- Add a stable key to
locales/en/backend.json. - Mirror the key in every other
backend.json. - Use
translate("path.to.key", value=name)in routes, validators, and backend response builders. - Do not return new user-facing
str(exc)messages unless the text is intentionally raw upstream output.
Adding a New Language
- Add the locale code and native name to
locales/manifest.json. - Create
locales/<locale>/frontend.json. - Create
locales/<locale>/backend.json. - Copy the English key structure exactly before translating values.
- Register the frontend resource import in
frontend/src/i18n/resources.ts. - Verify locale detection logic in
frontend/src/i18n/locale.tsif the new language needs custom browser mapping rules. - Verify backend locale matching in
backend/src/eval_752/i18n/__init__.pyif the new language needs custom negotiation rules. - Confirm the language appears in Settings and that browser matching behaves as expected.
Contributor Checklist
When a PR changes user-facing copy:
- Update all locale catalogs, not just English.
- Keep translation keys stable; rename keys only when semantics change.
- Avoid building sentences from fragments across multiple keys.
- Keep placeholders (
{{name}},{{count}}) consistent across languages. - Verify browser-follow mode and manual override mode.
- Verify at least one backend-translated error or validation path.
Tests And Verification
Run the relevant checks after changing i18n:
Automated coverage already includes:
- locale negotiation tests in
backend/tests/app/test_i18n.py - locale catalog parity checks in
backend/tests/test_locale_catalogs.py - frontend locale helper tests in
frontend/src/i18n/locale.test.ts - API client locale-header coverage in
frontend/src/api/client.test.ts
Common Pitfalls
- Do not add user-facing fallback English directly inside components.
- Do not localize persisted identifiers or API enum values unless they are presentation-only.
- Do not concatenate translated fragments around punctuation when one sentence key is possible.
- Do not add a locale to the manifest without also adding both catalogs and frontend resource registration.
See also:
