Repository navigation
feat(webui): let the settings page switch between Chinese and English - #250
Open
stevenjj33 wants to merge 2 commits into
Open
stevenjj33 wants to merge 2 commits into
stevenjj33 wants to merge 2 commits into
Conversation
The settings page's copy was hardcoded Chinese, and `mavis-locale` was read by a `useState` that had no setter: the key was there, the read was there, and nothing a user could do ever wrote a different value. The settings search matched a tab's name and key only, so asking it for 「语言」 answered 「没有匹配的 设置」 — the one question a language switch would exist to answer. The page now carries two packs, Chinese and English, in `features/settings/projection/settings-locale.ts` — a view module, so it reaches both the tab registry and the dialog without a new dependency edge and without the platform layer reaching into a business. Chinese is the base: a key the English pack does not carry falls back to the Chinese text rather than to a raw key, and the English pack's type is the Chinese key set, so a missing key is a compile error rather than a silent gap. A 语言 row in the 通用 page switches the locale, writes the key the page already used, and the document's `lang` attribute follows from it. The search now matches a row's own copy as well as its tab's name, and it matches both packs — a reader who looks for 「语言」 in an English page, or for "Language" in a Chinese one, is looking for the same setting. A search that matched a row also opens the page that owns it and marks the row. Scope: the settings page only. The conversation, the file panel and the workspace keep their own copy, and PR #33 deferred the client-wide extraction for exactly that reason (ADR 0025). Verified on macOS against the built client: the unit suite covers the pack parity, the fallback and the search; a browser run selects English and watches the sidebar and the 通用 page change without a reload, the `lang` attribute follow, and the choice survive a close and reopen. The same specs are red against `webui @ 63b9739`: the language row does not exist and the search answers 「没有匹配的设置」.
stevenjj33
force-pushed
the
feat/webui-settings-language-switch
branch
from
October 24, 2026 15:21
1f796e8 to
6704ab1
Compare
…environment The settings dialog's baseline changes because this branch adds a 语言 row to the 通用 page, which shifts everything below it. The three plugin-surface baselines are refreshed alongside it because they no longer match the gate's rendering — measured, not assumed: the base commit `491569cd`, checked out on the same runner and rebuilt, fails the same comparisons with the same pixel counts (449 for the marketplace, 122 for the MCP rows, and 17455 for the settings dialog it should have matched). Two independent runs of the regeneration produced byte-identical images, so the gate is deterministic on that environment. The baselines were regenerated on the gate's Linux runner, with the gate's CJK fonts installed, as `packages/webui/docs/verification/browser-suite.md` asks.
stevenjj33
force-pushed
the
feat/webui-settings-language-switch
branch
from
October 24, 2026 15:51
1ca73b3 to
aaf9155
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
The settings page's copy was hardcoded Chinese, and
mavis-localewas read by auseStatethat had no setter — the key was there, the read was there, and nothing a user could do ever wrote a different value. The settings search matched a tab's name and key only, so asking it for 「语言」 answered 「没有匹配的设置」: the one question a language switch would exist to answer.mavis-locale(the key the page already used — no second key), and the document'slangattribute follows from it.features/settings/projection/settings-locale.ts. Chinese is the base: a key the English pack does not carry falls back to the Chinese text rather than to a raw key.Chinese is the base language, so a fresh install opens in Chinese and the English pack is the opt-in. One consequence worth stating plainly: the old build wrote
mavis-localeas"en"on every mount of the settings dialog, so anyone who has opened it before arrives on this build with"en"already stored and sees the settings page in English. The storage key and its values are unchanged, so nothing is lost and clearing that one key returns the page to Chinese.No new dependency.
The boundary with #33, and the scope of this round
#33 is merged, and its own Scope section says why the i18n work is not in it:
So nothing here repeats #33: #33 never carried the i18n work, and this PR does the part of it that is small enough to be correct — an entry point, a minimal pack, and a page that actually switches. The client-wide extraction is untouched and still wants its own change.
This round covers the settings page only. The conversation, the file panel, the workspace and the rest of the client keep their own copy. The other settings pages (浏览器, 用量与模型, 账户, 工作树) keep their literals too, and the search does not promise a row it cannot name. ADR 0025 records that boundary, and the rule for the next business that needs a switch: it copies the shape, it does not import the settings pack.
Also deliberately untouched: the 语音 / 快捷键 / 个性化 tabs keep their current state (nothing is unlocked here), and the runtime's reply language is a different system (
packages/local-runtime/src/review/preparation.ts,responseLanguage: 'zh-CN' | 'en') that this change does not touch.Verification
Unit
packages/webui/test/unit/settings-locale.test.ts(new, registered intest/vitest-suites.json):t()reads each language, falls back to the Chinese text when a language does not carry a key, and falls back to the key itself when neither does;Browser (the built client)
packages/webui/test/browser/settings-language.spec.mjs(new), run withpnpm build:webuiand Playwright's pinned Chromium on macOS 27.0.1 (arm64), Playwright's default profile (locale: zh-CN,timezone: Asia/Shanghai,colorScheme: light), one fresh browser context per test, against the built client served bytest/browser/server.mjs.What it did, and what it saw:
Englishin the 语言 row. The sidebar's group heading changed 偏好 → Preferences, the tab changed 通用 → General, the row's own title changed 语言 → Language,<html lang>changed zh-CN → en, andlocalStorage["mavis-locale"]became "en" — with no reload.data-search-hit="true"), instead of the sidebar answering 没有匹配的设置. The same row was found by typing "Language".3 passed. The existing settings specs pass too —
settings-theme.spec.mjsandsettings-account-tab.spec.mjs, 12 passed — which matters because the theme spec drives the buttons by their Chinese labels.Negative control: the same specs are red before the fix
Built the pre-fix tree
webui @ 491569cd(this PR's base) in a separate worktree and ran the same two files against it:element(s) not foundon[data-testid="mavis-settings-language-row"]), the select cannot be used (timeout), and searching 「语言」 finds no 通用 tab;settings-locale.js, because that module is what this change adds.And the substantive assertion, written against the pre-fix API only (
filterSettingsTabswith no locale), is red on its own:A suite that was already green before the fix would have been an empty test. This one is not.
The Linux visual baselines
The 通用 page gains a row, so the settings dialog's Linux Chromium baseline changes: everything below the 应用 section shifts down. The baseline was regenerated on the gate's Linux runner with the gate's CJK fonts installed, as
packages/webui/docs/verification/browser-suite.mdrequires, and the regeneration ran twice and produced byte-identical images.Three plugin-surface baselines were refreshed in the same run, and that was measured rather than assumed. This branch does not touch the plugin, Skill or MCP surfaces, yet the same differences appear with and without it on the same runner — 449 pixels in the marketplace and 122 in the MCP rows, all of it icon antialiasing a few pixels wide. The committed images no longer match what the gate renders, so every PR on this branch would have been red for a reason that predates it.
Gates
pnpm verifyon macOS: check:source, check:tsconfig, export source preview, test:release-tools, lint:tui, typecheck, build, check:standalone, typecheck:webui, check:webui-dependency (0 violations), build:webui, check:webui-boundary and test:webui-package all pass.test:webuireports 215 files / 3346 tests passed, 0 failed (22 skipped), andpnpm verify --profile fullpassed 22 gates on darwin with nothing failing.Two of those files are real-browser integration gates, and they need a Chrome on the machine: the isolated-browser provider looks for
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome(then Chromium, then Brave) and refuses to start without one. On a machine with no Chrome,browser-core-agent-actions.test.ts(5) fails withNo Chrome executable was found; set browser.chromePath to the browser to use.andagent-transcript.test.ts(1) waits 30s for abrowser-panel-framethat never arrives, because Chrome's network service cannot start and no screencast frame is ever produced. The same six fail identically on the clean base491569cd, which is what identifies them as the machine's missing Chrome rather than a regression — and CI runners ship Chrome, so those files are green there.One note on the frozen metadata:
packages/webui/test/gates/fixtures/path-metadata-f00.jsonrecords every source path with its layer, role, business and home, so the new module is declared there (features/settings/projection/settings-locale.ts→ view / feature-projection / settings / target).CI on this pull request
Source verificationis green on all three platforms (run40108865569):pnpm verify --profile full→ Verification passed: 22 gates on linux. The gate'stest:webui-browserpassed, and the refreshed Linux baselines matched on the runner that produced them — thesettings dialog layout baselineand theplugin management skill and MCP rows layout baselinesincluded.pnpm verify --profile platform→ passed.pnpm verify --profile platform→ passed.The three new browser cases also run there, on Linux this time: