Add internationalisation (i18n) support to the platform UI
- Dominant language
- JavaScript
- Stars
- 400
- Forks
- 89
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 146
Description
### Description
### Problem
The FlowFuse platform UI is English-only and has no i18n infrastructure. On `main` at v3.0.0 (`56b076e7`), `frontend/src/i18n.js`, `frontend/src/locales/` and a root `locales/` directory do not exist, and there is no `i18n` or `polyglot` dependency in `package.json`.
Approximate translatable string counts across 542 `.vue` files (79,189 lines): ~1,049 bare template text nodes, ~358 `label`/`title`/`placeholder`/`header` attribute strings, ~155 `Alerts.emit` messages, plus 19 email templates in `forge/postoffice/templates/`.
There is also an inconsistency that non-English-speaking self-hosted teams hit immediately. **Node-RED already ships 10 editor locales** (`de`, `en-US`, `es-ES`, `fr`, `ja`, `ko`, `pt-BR`, `ru`, `zh-CN`, `zh-TW`), and because `nr-launcher` does not set `lang` in the generated `settings.js`, Node-RED falls back to the browser locale. So a user with a Chinese browser locale gets a fully localised Node-RED editor embedded inside an entirely English platform shell.
### Motivation
I run a self-hosted FlowFuse deployment for a Traditional Chinese (`zh-TW`) speaking team, and localising the platform shell is the remaining gap. I would rather contribute this upstream than maintain a private fork, so the work starts from the shared infrastructure and the `en` baseline rather than from my own locale.
### Reference
I reviewed [PR #5692](https://github.com/FlowFuse/flowfuse/pull/5692) and the `docs/contribute/i18n.md` contributor guide on its `feature/i18n-implementation` branch, and followed the architecture defined there — the library choices, the locale directory layout, and the hierarchical key-naming convention.
The implementation is written fresh against `main` rather than rebased from that branch, which is now ~4,700 commits behind and pins `fastify-i18n@^1` (Fastify 4 era) and `vue-i18n@^9`.
### Implementation
- **Frontend** — `vue-i18n@^11`, config at `frontend/src/i18n.js`, locales at `frontend/src/locales/.json`
- **Backend** — `fastify-i18n@^3` over `node-polyglot`, locales at `locales//common.json`. The two interpolation syntaxes differ (`{name}` vs `%{name}`); that is documented rather than papered over.
- **Both webpack entrypoints** — the plugin is registered on `setup.js` as well as `main.js`, so the first-run setup flow is translated too
- **Locale resolution** — stored `User.language`, then the request or browser locale, then `en`. The login and sign-up pages render before there is a session, so browser detection is what makes them translatable at all.
- **`User.language`** — a new nullable column, so this carries a DB migration and needs the `area:migration` label
One correction to what I wrote in #8311: I said `fastify-i18n@3` normalises `Accept-Language` and that browser detection would need no custom code on the backend. That is only half true. It narrows a regional tag onto its base language (`en-GB` finds `en`) but does not widen a script-qualified tag onto a regional one, so `zh-Hant-TW` fell back to English rather than finding `zh-TW` — and Chrome reports exactly that tag for Traditional Chinese on some platforms. A `LOCALE_ALIASES` map in `forge/i18n/locales.js` handles it, and a test covers it. I had assumed the library did this; a test proved otherwise.
### Status
Implemented and open as #8312 — 5 commits, 422 files, 2,879 locale keys with `en` and `zh-TW` in step.
Full build and test results are in the PR description: `lint` clean against the pre-change baseline, 3,346 forge unit tests, 886 frontend, 61 system, the migration verified on SQLite, and manual verification in both locales including the pre-session pages.
The PR grew well beyond the initial page set proposed here, because the infrastructure on its own left a signed-in user reading English on every page — setting a language preference did not visibly do anything. The PR offers to split that: the plumbing and the `en` extraction separately from the `zh-TW` values, whichever is easier to review.
Re-filed through this template because I originally opened #8311 as a blank issue, so it never picked up the `needs-triage` label and has been sitting outside the triage queue rather than waiting in it. Closing #8311 in favour of this one.
One small thing noticed while doing that: `.github/ISSUE_TEMPLATE/03-feature.yml` declares `labels: [needs-triage, feature-request]`, but there is no `feature-request` label in this repository — the nearest existing ones are `type:feature`, `customer request` and `sales request`. GitHub drops a template label that does not exist, silently, so every issue filed through that template gets only `needs-triage`. This one included. Either creating the label or pointing the template at `type:feature` would fix it.
### Which customers would this be available to
Everyone - CE/Starter/Team/Enterprise
### Have you provided an initial effort estimate for this issue?
I am not a FlowFuse team member
Contributor guide
Research direction
Start by reviewing the architecture in docs/contribute/i18n.md and the existing implementation in #8312, including frontend/src/i18n.js, frontend/src/locales/, locales/, forge/i18n/locales.js, and the User.language migration. Run the frontend and forge test suites described in the issue; done means the platform UI, pre-session pages, locale alias handling, and database migration work in both en and zh-TW.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- backend, database, frontend, internationalization
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 20/100