-
-
Notifications
You must be signed in to change notification settings - Fork 0
Internationalisation
The operator/management SPA supports English, German, French, Spanish, and Chinese. English is the source language and the inline fallback; backend output, server logs, and the login screen stay English regardless of the user's choice.
A user's preferred language is stored on their IAM account (AppUser.language, default en) so
it follows them across devices. The browser caches it in localStorage (owcs.lang) for an
instant first paint before the server round-trip completes.
A language picker lives in the top bar next to the warehouse switcher. Each option is labelled in its own script (Deutsch, Français, Español, 中文) so a user who cannot read the current language can still find theirs. Selecting a language:
- Updates the
<html lang>attribute immediately. - Writes the choice to
localStorage(cache for next load). - Persists it to the IAM account via
PUT /api/iam/me/language(best-effort; a network failure still changes the language for the current session).
Both endpoints are resolved from the X-Auth-User header forwarded by the gateway.
| Method | Path | Description |
|---|---|---|
GET |
/api/iam/me/language |
Returns { "language": "en" } for the signed-in user. Falls back to en when the user has no row. |
PUT |
/api/iam/me/language |
Body { "language": "de" }. Unknown codes are coerced to en. Auto-provisions the AppUser row if the user has never been managed in IAM, so the preference still sticks. |
Supported codes: en · de · fr · es · zh.
The i18n layer is dependency-free (no i18n library):
| File | Role |
|---|---|
config.ts |
Lang union type, LANGS array, DEFAULT_LANG = 'en', LANG_STORAGE_KEY. |
LanguageContext.tsx |
React context + LanguageProvider. Reads the server preference once on mount; exposes lang + setLang. |
useT.ts |
useT(ns) hook — returns t(key, english). When lang === 'en' or the key is absent, the inline English is returned verbatim (no raw key ever leaks). |
dictionaries.ts |
Auto-discovers every locales/<lang>/<namespace>.ts via import.meta.glob. No central registry — parallel namespace work is conflict-free. |
LanguageSwitcher.tsx |
Top-bar <Select> wired to LanguageContext. |
locales/<lang>/<namespace>.ts |
One default-export { key: 'translated text' } object per language × namespace. English needs no files. |
The table below covers all 24 namespaces (≈ 1,700 keys) shipped in de, fr, es, and zh.
The whole SPA is now fully translated — every screen in the sidebar is covered; no screen falls
back to English-only rendering.
| Namespace | Screen / area | Introduced |
|---|---|---|
nav |
Sidebar labels and section headers (AppShell.tsx) |
#289 |
users |
Users admin screen | #290 |
access |
Access Control admin screen | #290 |
warehouseaccess |
Warehouse Access admin screen | #290 |
admindb |
Database Console admin screen | #290 |
systeminfo |
System Info admin screen | #290 |
dashboard |
Dashboard home screen (Dashboard.tsx) |
#291 |
help |
In-app help drawer chrome + per-screen content (HelpButton.tsx) |
#291 |
process |
BPMN process designer (ProcessDesigner.tsx) |
#291 |
reporting |
Reporting screens — Material flow, ASRS, Stock, Inbound, Outbound + shared charts | #291 |
inbound |
Inbound orders screen (InboundScreen.tsx) |
#292 |
outbound |
Outbound orders screen (OutboundScreen.tsx) |
#292 |
counting |
Stock counting / cycle-count screen (CountingScreen.tsx) |
#292 |
stocktxn |
Stock transactions screen (StockTxnScreen.tsx) |
#292 |
inventory |
Stock overview + Handling units screens (StockOverviewScreen.tsx, HandlingUnitsScreen.tsx) |
#292 |
gtpops |
GTP operator console — launcher, queue/exceptions drawers, count/pick/put panels (GtpOpsScreen.tsx) |
#292 |
gtpconfig |
GTP configuration — workplace/node CRUD dialogs, location picker (GtpConfigScreen.tsx, LocationPicker.tsx) |
#292 |
transport |
Transport overview — tiles, filters, task table, trace dialog (TransportScreen.tsx) |
#292 |
twin |
Hardware twin — page chrome, stat chips, legend, level select, detail panels (HardwareTwinScreen.tsx) |
#292 |
masterdata |
Master data catalogs — warehouses, SKUs, storage blocks, locations, equipment, HU types, label templates + guided block builder (MasterDataScreen.tsx); 297 keys |
#293 |
settings |
Settings — slotting policy, cubing, counting, stock rules, integrations, system status, demo mode, hardware emulator (SettingsScreen.tsx); 196 keys |
#293 |
slotting |
Slotting — pick faces + block slotting screen (SlottingScreen.tsx); 40 keys |
#293 |
topology |
Automation topology editor — TopologyEditor, AutomationTopology3D (UI only; 3D geometry/mesh/colour untouched), RoutingGraphTables, RouteTest, PlanEditor2D: tabs, toolbar, level controls, equipment library, properties panel, function-point and connection dialogs, node-link panel, routing-graph tables, 2D plan editor, all status/hint text; 273 keys |
#294 |
AppShell.tsx uses useT('nav') to translate sidebar items. The keys are the screen's stable
key property (e.g. inbound, gtp-ops). Section header keys use the prefix section: followed
by the English section name (e.g. section:Master data).
All 32 screen labels and 6 section headers are covered in locales/<lang>/nav.ts for de, fr,
es, and zh. When you add a new screen to SCREENS, also add its key to each nav.ts file;
until you do, the English label is shown as a fallback.
// src/i18n/locales/de/nav.ts (excerpt)
export default {
inbound: 'Wareneingangsaufträge',
'section:Master data': 'Stammdaten',
// ...
}The help namespace is shared across all screens and uses compound keys rather than the single-level keys used by other namespaces.
Drawer chrome keys (always translated):
| Key | English default |
|---|---|
help |
Help |
helpFor |
Help for {screen} |
closeHelp |
Close help |
tips |
Tips |
Per-screen content keys (the English source stays in help/content.ts; HelpButton.tsx calls t(key, english) so untranslated screens degrade to English automatically):
| Key pattern | Example |
|---|---|
{screenKey}.summary |
dashboard.summary |
{screenKey}.s{i}.heading |
dashboard.s0.heading |
{screenKey}.s{i}.body |
dashboard.s0.body |
{screenKey}.tip{i} |
dashboard.tip0 |
Section headings (s{i}.heading) are translated for all 33 screens. Full body copy is translated for the priority screens (dashboard, processes, and all five reporting entries). The remaining screens' summaries, bodies, and tips fall back to English automatically.
// src/i18n/locales/de/help.ts (excerpt)
export default {
"help": "Hilfe",
"closeHelp": "Hilfe schließen",
"dashboard.s0.heading": "Was Sie hier tun",
"dashboard.summary": "...", // priority screen — body copy translated
"transport.s0.heading": "Was Sie hier tun",
// transport summary/body omitted → falls back to English
}-
Import and call
useTwith a namespace (one per screen / feature area):import { useT } from '../i18n/useT' const t = useT('inbound') return <h1>{t('title', 'Inbound orders')}</h1>
The second argument is the English source text and the fallback — wrapping a string with
t(...)never changes the English UI. Missing translations degrade to English, not a raw key. -
Add locale files for each of
de,fr,es,zh:// src/i18n/locales/de/inbound.ts export default { title: 'Wareneingangsaufträge', }
dictionaries.tspicks up the file automatically — no registry edit needed.
Do not wrap: data values, codes (SKU/HU/location codes), log text, or anything the backend owns. Keep numbers, units, and identifiers out of translated strings; interpolate them in the component.
- Backend output and API responses.
- Server logs (all Java / Go services).
- The Keycloak login screen (rendered outside the
LanguageProvider) — including its self-service change-password form. - Error codes and identifiers shown in the UI (HU codes, location codes, SKU codes, etc.).
- Service health status codes (
UP/DOWN/UNKNOWN) — these are API data values, not UI copy. - The screen-permission catalog labels in the Access Control matrix — they mirror the nav catalog and are intentionally kept in sync with the English screen keys rather than translated separately.
openWCS — open-source Warehouse Control System · summarized from build.md & docs/AS-BUILT.md (the repo docs are authoritative).
Design
Flows
- Inbound and Inventory
- Slotting and Replenishment
- Goods-to-Person Stations
- Outbound Flow
- Equipment Integration
- Transport Overview
- Hardware Visualisation
- Host Integration
Reporting & Dashboards
Operations