> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/features/multilingual-ui.md).

# Multilingual UI

The ODD Platform UI ships with **seven locale translations** loaded at SPA bootstrap. Users switch the active locale from the **user-account menu** in the top-right of the toolbar; the choice persists per browser device in `localStorage`. The platform's API surface remains English-only — the localisation applies to the UI shell (toolbar labels, page titles, button captions, form field labels, error messages); operator-authored content (entity descriptions, glossary terms, custom-metadata field names, namespaces, tag names) is rendered verbatim regardless of the active locale.

## Supported locales

The platform's translation table currently includes seven entries, sourced from `odd-platform-ui/src/locales/translations/`:

| Code | Language             |
| ---- | -------------------- |
| `en` | English (default)    |
| `es` | Spanish              |
| `ch` | Chinese              |
| `fr` | French               |
| `ua` | Ukrainian            |
| `hy` | Armenian             |
| `br` | Brazilian Portuguese |

The default is `en` — a fresh browser session with no prior locale selection lands on English. The `br` locale (Brazilian Portuguese) ships from platform release 0.28.0 — a community contribution ([`odd-platform#1564`](https://github.com/opendatadiscovery/odd-platform/pull/1564)); deployments on earlier releases offer the original six.

## How users switch

The active locale is changed from the **user-account menu** in the top-right of the toolbar — the area showing your username next to a dropdown arrow. Click it to open the account dropdown (the same menu that holds **Logout**), then click the **Select language** entry — it shows the current language and a chevron. That opens a **Select language** dialog with one searchable entry per supported locale. Picking a locale takes effect immediately on the current page; subsequent SPA navigation continues in the chosen locale.

## Persistence model — per-device, not per-user-account

The chosen locale is stored in the browser's `localStorage` under the key `i18nextLng`. The implications operators should know:

* **Per browser device.** The locale preference is bound to the browser profile, not to the user's catalog account — signing in from a different browser, a different machine, or an incognito session starts from the default (`en`) until the user picks again.
* **Survives logout and re-login.** The `localStorage` value is not cleared by sign-out; the next sign-in from the same browser resumes the prior locale choice.
* **No server-side propagation.** The platform does not record the user's locale preference on the server, does not honour an `Accept-Language` HTTP header, and does not push the choice to other devices the same user is signed in on.

If the deployment serves a user population that uses multiple devices and expects a single, account-bound locale choice — for example a company-managed account propagating across the user's laptop and phone — this is a known absence; the per-device localStorage model is the only persistence path today.

## Known caveat — how missing translations behave (and the 0.28.0 catch-up)

Each locale's translation table uses the English text itself as the lookup key (for example `"Activity": "Activity"`). When a key a component asks for is missing from the active locale, i18next falls back to **English** (the `fallbackLng: 'en'` setting) — the English label renders with no warning and no visible marker. A locale can therefore look fully translated and still show English wherever its table trails the code.

**As of 0.28.0 every shipped locale table is complete.** Earlier releases carried a real gap: a June 2026 sweep found code-referenced keys (about 70, growing to 84 as more UI surfaces landed) absent from *every* non-English catalog — confirmation dialogs, the Data Quality dashboard headlines, lookup-table and query-example labels, the activity-feed actor tooltips — so a non-English locale showed English in those spots. [`odd-platform#1748`](https://github.com/opendatadiscovery/odd-platform/issues/1748) fixed the first slice (the three top-level navigation tabs — Data Quality, Data Modelling, Master Data — which had been absent from every bundle); [`odd-platform#1751`](https://github.com/opendatadiscovery/odd-platform/issues/1751) completed the rest, translating the remaining 84 keys into all six non-English catalogs (`es`, `ch`, `fr`, `ua`, `hy`) and the seventh, `br` — which had separately trailed by eight keys, including the **Master Data** tab. **All seven catalogs (`en`, `es`, `ch`, `fr`, `ua`, `hy`, `br`) now carry the same key set.** A separate gap was also closed in 0.28.0: a number of UI strings were hardcoded in the source with no translation lookup at all (so they showed English under every locale, independent of the catalogs) — these were wrapped so they pass through the translation layer and were translated across all seven locales. Two automated build checks now keep this from regressing: a key-parity check (every locale must carry the English key set) and a no-untranslated-string check (a new user-facing label that skips the translation layer fails the build — covering both JSX text and component attributes such as placeholders and labels). So the gap should not silently reopen as new screens are built.

These bulk catch-up translations were contributed in one pass; native-speaker refinements to any string are welcome — correcting an existing translation is the same workflow as adding a new locale (see [How to contribute a new locale](#how-to-contribute-a-new-locale) below), applied to the value already in the JSON.

The fallback **mechanism** remains by design: a future code change that introduces a new `t('...')` string renders the English label under any locale whose table has not yet caught up. For completeness audits, treat the translation-table JSON files as the source of truth, not the running UI — because a missing key shows the English text, an English-locale UI always looks complete. On releases that predate 0.28.0, the gaps described above are present.

## How to contribute a new locale

Adding an eighth locale (or any subsequent locale) is a contributor-facing workflow on the UI repository ([`odd-platform`](https://github.com/opendatadiscovery/odd-platform)). The shape:

1. Create a new translation file at `odd-platform-ui/src/locales/translations/{code}.json` (where `{code}` is the locale code — typically the 2-letter ISO 639-1 code, or the project's own short code such as `ch` for Chinese or `br` for Brazilian Portuguese). The file mirrors the structure of the existing translation files; the simplest start is to copy `en.json` and translate each value.
2. Register the locale in the bootstrap module at `odd-platform-ui/src/locales/i18n.ts` — add the import and add the entry to the `resources` map (and, to keep it consistent with the others, add the code to the `fallbackLng` array). The `resources` map is what populates the picker, so this step is what makes the locale selectable.
3. Add the new code to **both** maps in `odd-platform-ui/src/lib/constants.ts` — `LANGUAGES_MAP` (code → display name, shown in the picker) and `LANG_TO_COUNTRY_CODE_MAP` (code → flag country code). These are required: the **Select language** dialog renders each row by looking the code up in these maps, and a code that is missing from `LANGUAGES_MAP` will break the picker. The `Lang` type is derived from `LANGUAGES_MAP`, so adding the key here is also what makes the rest of the code recognise the new locale.
4. Open a pull request against the UI repository. The contribution does not require platform-API changes, and the **Select language** dialog needs no edits — it builds its list from the registered locales automatically. [`odd-platform#1564`](https://github.com/opendatadiscovery/odd-platform/pull/1564), which added Brazilian Portuguese, is a complete worked example of exactly this shape — three files, no other changes.

The build-and-run workflow for the platform (including the frontend UI) is documented at [Build and run ODD Platform](/developer-guides/build-and-run/build-and-run-odd-platform.md).

## Where to next

* [Management](/features/management.md) — the operator surface inside the platform UI; the localisation applies to the Management section's tab labels and form controls.
* [Main Concepts → Terms & Aliases](/introduction/main-concepts.md#terms-and-aliases) — the alias registry where "Multilingual UI", "i18n", "internationalisation", and "locale switching" point at this page.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opendatadiscovery.org/features/multilingual-ui.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
