emrg: GUI i18n Stage 1 — i18n.js + static text + language switcher (rant 21:19) - #503
Conversation
ec6ce6c to
ec96e40
Compare
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-221133 (emrg-00c41753, author self-check, 1/3)
Verified after rebasing onto master 5700da0 (#501):
- Conflicts resolved: index.html growth-card co-exists with data-i18n; copywriting.js absorbs #501 P3 keys (growthCount/growthNote/evolutionToast*) into the i18n dict (zh+en parity kept); app.js exports merged
- GUI tests 75 pass (63 baseline + 8 i18n + 4 #501 P3); Python 480 pass; node --check all green
- CI Test workflow green (run 31110928611)
- Behavior: en system → English static UI out of the box; zh system → unchanged; Settings language switcher applies instantly
- Stage 2 (dynamic strings in chat/sidebar/dialogs/result-panel/markdown/utils) tracked in rant 21:19 progress
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-223007 (emrg-00c41753, 2/3)
Re-verified the rebased branch (ec96e40, onto master 5700da0): 9 files, +755/-140, GUI-only. Conflicts from the #501 merge are fully resolved (growth-card co-exists with data-i18n; P3 copy keys absorbed into the i18n dict with zh/en parity). CI Test workflow green (run 31110928611). Ready for the third vote.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260806-222810 (emrg-00c41753, 3/3 independent review)
Reviewed in an isolated worktree at head ec96e40 (no interference with the author's Stage 2 work in progress):
- i18n.js: clean zero-dependency design matching rant 21:19 constraints (no framework, no bundler). All browser APIs (navigator/localStorage/document) guarded — safe in vm test sandbox. detectLocale/getLocale/setLocale/t/apply all sensible; zh fallback + {var} interpolation; localStorage override persists and applies instantly.
- Dict parity is enforced by a test (zh vs en key sets identical) — the classic drift hazard for hand-maintained dictionaries is covered.
- Static text via data-i18n/data-i18n-placeholder/data-i18n-title; copywriting.js rebuilt as locale-aware EMRG_Copy IIFE with refresh(); command hints resolved through t() at display time; example cards send the localized prompt.
- Tests: 75/75 pass in the isolated worktree (63 baseline + 8 i18n + 4 #501 P3). Initial failures were purely environmental (fresh worktree lacked .venv/node_modules) — resolved by symlinking, zero code changes needed.
- Note (non-blocking): head ec96e40 is based on 5700da0; master has since moved to ba540f7 (#502). A rebase onto master will be needed before merge — the author's ongoing Stage 2 work should carry that (app.js conflict expected).
…ant 21:19)
- New emrg/gui/renderer/js/i18n.js: zero-dependency dict {zh,en},
detectLocale() (navigator.language, zh* → zh), getLocale/setLocale
(localStorage "emrg.locale": ""=follow system / zh / en), t(key, params)
with {var} interpolation + zh fallback, apply() for data-i18n /
data-i18n-placeholder / data-i18n-title
- index.html: data-i18n on sidebar/composer/empty-state/settings/welcome/
confirm/rename/help/sessions/rewind/memory/skills/rant/tasks static text
(labels with embedded inputs wrapped in spans so textContent doesn't wipe inputs)
- Settings dialog: new Language selector (System / 中文 / English), instant
apply via I18N.setLocale + EMRG_Copy.refresh + App.refreshLocale
- copywriting.js: COPY + tool phrases now resolve via i18n dict; TOOL_FAIL_TEXT
becomes a getter (chat.js assigns it as a string)
- commands.js: hints become i18n keys, getCompletions/hintText resolve per locale
- app.js: boot applies locale; refreshLocale re-renders model switcher + cmd menu;
example-card click uses localized textContent
- +8 i18n unit tests (detectLocale/t/插值/setLocale/apply/词典键一致性);
GUI tests 71 pass (63 + 8), Python 480 pass
ec96e40 to
4d08b81
Compare
Summary
GUI i18n Stage 1 (rant 21:19): zero-dependency internationalization infrastructure + static text migration + language switcher.
Changes
1. New
i18n.js(renderer, zero deps){ zh, en }covering sidebar, composer, empty state, result panel, all dialogs, command hints, copywriting, tool phrases (~80 keys)detectLocale()—navigator.language:zh*→ Chinese, anything else → EnglishgetLocale()/setLocale()— manual override persisted inlocalStorage(""= follow system /zh/en)t(key, params)— lookup with{var}interpolation, zh fallbackapply()— appliesdata-i18n/data-i18n-placeholder/data-i18n-title, then refreshesEMRG_CopyandApp.refreshLocale()2.
index.html— every static string getsdata-i18n(labels wrapping inputs use<span data-i18n>so textContent replacement doesn't wipe the input)3. Settings → Language selector — System / 中文 / English, instant apply (no restart, no save needed)
4.
copywriting.js— COPY + tool phrases resolve through the i18n dict;refresh()rebuilds on locale change;TOOL_FAIL_TEXTbecomes a getter (chat.js assigns it as a string)5.
commands.js— hints become i18n keys;getCompletions()/hintText()resolve per current locale (help dialog + autocomplete both localized)6.
app.js— boot applies locale;refreshLocale()re-renders model switcher + open command menu; example-card clicks send the localized prompt textBehavior
Tests
detectLocale/t/ interpolation /setLocalepersistence /apply/ dict key parity zh↔en)emrg --helpverified