Daniel, 2026-10-02: “Please do localization in English, German and Chinese. Please make light/dark mode or better yet themes. Do it whenever you see fit.”
What is wanted
- The UI in three languages — English, German, Chinese (Simplified) — chosen in Settings → You, defaulting to the system language (desktop:
LANG/the OS locale; web:navigator.languages; Android: the device locale), falling back to English for anything not translated. Switching applies without a restart. - Themes, not only light/dark: a theme is a named set of colours (and maybe fonts) for the whole app — workbench, editors (CodeMirror, Milkdown, the Rust editor, xterm, the Rust terminal), the graph view, the flow canvas, tables, KaTeX. At least Dark, Light, and Follow system (
prefers-color-scheme); more themes as files, so users and extensions can add their own.
Where things stand (checked 2026-10-02)
- Text: every UI string is a Rust literal in the panels, menus, the palette and the status bar (about 130 in
shell/srcalone, more in each editor and in the JS bundles’ own strings). No translation layer exists. - Themes:
Settings.themeexists ("dark"by default) but only the Rust code editor reads it; the shell’s CSS uses dioxus-workbench’s--wb-*variables and our--mk-*ones, with about 580 hard-coded hex colours across the stylesheets; CodeMirror ships the one-dark theme; the graph renderer has its own colours.
Design notes (for whoever does it)
- Strings: a
t!("key")-style lookup with Fluent (fluent-bundle, Mozilla’s format; plural and gender rules for German, no inflection trouble for Chinese) or a smaller key → string table per language; files underpackages/shell/locales/{en,de,zh-CN}/*.ftl. Each extension brings its own strings (a contribution, like settings), so the catalogue split of Milestone 18 - Library Refactor phase 4 is the natural moment. Keys, not English text, are the ids, so a changed English wording does not orphan a translation. - JS bundles keep no strings of their own where possible (rule of
packages/js: Rust owns the text); the few they have (CodeMirror’s search panel, Milkdown’s menus) get their phrases from Rust atinit. - Chinese: a CJK font in the font stacks (Noto Sans CJK / system), and the IME paths that issue #19 already flags (Enter during composition must not send).
- Themes: one token set (
--mk-bg,--mk-fg,--mk-accent,--mk-border, syntax colours, graph palette, the eight source colours of spec 009) defined per theme, mapped onto--wb-*for the workbench; every stylesheet uses tokens only (a CI check can grep for hex colours outside theme files). CodeMirror, xterm and Milkdown get their themes generated from the same tokens; the graph renderer takes its palette as data. Theme files as TOML/JSON in the user’s config directory and as an extension contribution. - Both are settings that belong in the state store (Internal State), synced across devices.
Done when
The three languages switch live in Settings, with every built-in panel, menu, command title and dialog translated (German and Chinese reviewed by a native speaker — Daniel for German); Dark, Light and Follow-system work everywhere listed above with no hard-coded colour left outside the theme files; a fourth theme can be dropped into the config directory and selected. E2E: a suite switches language and theme and checks a few labels and computed colours.
Outcome (2026-10-03)
Done on the spec-030 branch in three parts — Fluent strings for the shell and the workspace, every extension in three languages, themes. How it works and the rules: Languages and Themes. Problems met: P-151 (subscribing inside a command effect), P-152 (dynamic text in a style element breaks hydration).
Open from Done when: the German and Chinese texts are drafts that still need a native speaker’s review; the JS bundles’ own phrases (CodeMirror’s search panel) are English; the IME composition case of issue #19 is unchanged.