Skip to content

Latest commit

 

History

History
33 lines (21 loc) · 4.29 KB

File metadata and controls

33 lines (21 loc) · 4.29 KB

Internationalisation

DataLab-Web ships a working internationalisation framework. English is the source language (the msgid) and French is the first translated locale. The UI auto-detects the user's regional preference and renders fully in their language, including the labels that come from Python (Sigima / guidata) through the Pyodide bridge.

How it works for users

The active locale is resolved once per page load in this order (first match wins):

  1. ?lang=<code> URL query parameter (handy for sharing links and E2E tests);
  2. an explicit choice persisted in localStorage["datalab-web:lang"] (set via the language selector in the menu bar);
  3. the browser's regional preference (navigator.languages);
  4. English (DEFAULT_LOCALE) as the fallback.

Switching language from the menu-bar selector persists the choice and triggers a full page reload, because the Pyodide instance pins its LANG at boot and Sigima/guidata cache their gettext labels at import time — so a fresh instance must boot with the new locale.

Architecture

There are two translation surfaces, kept in sync:

  • TypeScript/React strings go through a lightweight t() helper (src/i18n/translate.ts). The English string is the key; for English the helper is the identity function (no en.json is shipped), and {name} placeholders are interpolated from a vars argument. Catalogs live in src/locales/<code>.json and are merged in src/i18n/catalogs.ts. React components read the locale via useTranslation() from src/i18n/I18nProvider.tsx; non-React code (the action registry, runtime.ts) reads it directly from src/i18n/locale.ts.
  • Python-origin labels (signal/image creation types, processing/operations/analysis menu entries, parameter-dialog field labels) are translated by Sigima/guidata's own gettext .mo catalogs. The active locale is mapped to a LANG value by pyodideLang() (English → POSIX C, i.e. untranslated msgid; any other locale → its bare code such as fr) and exported into the Pyodide environment before the first guidata/sigima import in src/runtime/runtime.ts, src/runtime/macroWorker.ts and src/runtime/notebookWorker.ts.

Applying t() to a Python-origin label is safe: a label that Sigima already owns in French has no key in fr.json, so t() returns it unchanged; only the English override strings defined in src/runtime/processor.py and the React-owned strings get looked up.

Contributing translations (developer workflow)

  1. Wrap every new user-facing string in t("…") (import from src/i18n/translate). Use t("Delete {count} objects?", { count }) for interpolation. Do not translate brand names (e.g. DataLab Web) or AI-assistant system prompts.
  2. Extract the keys. Run npm run i18n:extract to merge newly discovered t("…") keys into src/locales/fr.json (existing translations are preserved; new keys get empty placeholders). Keys referenced only through a variable (never as a string literal) must be listed in src/locales/_dynamic-keys.json so the extractor seeds them.
  3. Fill in the translations in src/locales/fr.json.
  4. Verify with npm run i18n:check (fails on missing or empty keys; this also runs the static scan). It is wise to run it in CI.
  5. Add a new locale by: adding its code to SUPPORTED_LOCALES and LOCALE_LABELS in src/i18n/locale.ts, registering its catalog in src/i18n/catalogs.ts, adding the code to LOCALES in scripts/i18n-extract.mjs, and creating src/locales/<code>.json. Python-side labels are picked up automatically if the matching .mo catalogs are bundled in the Sigima/guidata wheels.

Coverage is enforced by Vitest unit tests (tests/ts/i18n/i18n.test.ts) and an end-to-end Playwright spec (tests/e2e/i18n.spec.ts) that boots the app with ?lang=fr and asserts both a translated UI menu and a French Sigima label coming through the Pyodide bridge.