0070. The UI is English only, with a light/dark switch

Status: Accepted · Date: 2026-10-26 · Design section: UI, Roadmap phase 10 Decided: The UI has one language, English. The ja dictionary, the language selector, and language detection and storage are removed; en stays in ui/src/lib/i18n.ts behind t() / useT(); dates and sizes use Intl with en, not the browser locale; the page header carries a light/dark switch that follows prefers-color-scheme until the user chooses, then keeps the choice in localStorage Supersedes: 0064

Context

ADR 0064 localised the UI in English and Japanese and picked the language from navigator.languages. The user asked for an English-only UI; a Japanese browser should not produce a Japanese page. The user also asked for a dark/light switch; index.css already had the dark custom variant and token block.

Decision

1. English only. ja, Lang, langs, langNames, detectLang, lang.ts, the LanguageSelector/LanguageSwitch component and the common.language key are deleted. The English strings are unchanged. t(key, params) lives in i18n.ts and replaces {name} markers; useT() stays so the roughly 220 call sites do not change, but returns t without subscribing to anything. enumName and formatBytes / formatDate / formatTimestamp lose their lang parameter and use en.

2. Light/dark switch. ui/src/lib/theme.ts has the pure chooseTheme(saved, prefersDark): a saved light or dark wins, otherwise the system preference. The choice is kept in localStorage["ichor-ui-theme"] (read and written in try/catch) and applied as the dark class on <html>. A small inline script in ui/index.html applies it before first paint to avoid a light flash. The header button is the preactcn Button and says which mode it switches to.

Consequences

  • Nothing in the UI follows the browser language. Reintroducing a language means a new ADR.
  • The typed-dictionary indirection remains although only one dictionary exists; it keeps strings in one place and the call sites unchanged.
  • The theme logic exists twice (TypeScript and the inline script); theme.ts says so.

Search the docs

Search pages and headings