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 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/<locale>.json
- Backend —
fastify-i18n@^3 over node-polyglot, locales at locales/<locale>/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
Description
Problem
The FlowFuse platform UI is English-only and has no i18n infrastructure. On
mainat v3.0.0 (56b076e7),frontend/src/i18n.js,frontend/src/locales/and a rootlocales/directory do not exist, and there is noi18norpolyglotdependency inpackage.json.Approximate translatable string counts across 542
.vuefiles (79,189 lines): ~1,049 bare template text nodes, ~358label/title/placeholder/headerattribute strings, ~155Alerts.emitmessages, plus 19 email templates inforge/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 becausenr-launcherdoes not setlangin the generatedsettings.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 theenbaseline rather than from my own locale.Reference
I reviewed PR #5692 and the
docs/contribute/i18n.mdcontributor guide on itsfeature/i18n-implementationbranch, 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
mainrather than rebased from that branch, which is now ~4,700 commits behind and pinsfastify-i18n@^1(Fastify 4 era) andvue-i18n@^9.Implementation
vue-i18n@^11, config atfrontend/src/i18n.js, locales atfrontend/src/locales/<locale>.jsonfastify-i18n@^3overnode-polyglot, locales atlocales/<locale>/common.json. The two interpolation syntaxes differ ({name}vs%{name}); that is documented rather than papered over.setup.jsas well asmain.js, so the first-run setup flow is translated tooUser.language, then the request or browser locale, thenen. 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 thearea:migrationlabelOne correction to what I wrote in #8311: I said
fastify-i18n@3normalisesAccept-Languageand 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-GBfindsen) but does not widen a script-qualified tag onto a regional one, sozh-Hant-TWfell back to English rather than findingzh-TW— and Chrome reports exactly that tag for Traditional Chinese on some platforms. ALOCALE_ALIASESmap inforge/i18n/locales.jshandles 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
enandzh-TWin step.Full build and test results are in the PR description:
lintclean 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
enextraction separately from thezh-TWvalues, 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-triagelabel 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.ymldeclareslabels: [needs-triage, feature-request], but there is nofeature-requestlabel in this repository — the nearest existing ones aretype:feature,customer requestandsales request. GitHub drops a template label that does not exist, silently, so every issue filed through that template gets onlyneeds-triage. This one included. Either creating the label or pointing the template attype:featurewould 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