fix(workspace): respect browser language on first use - #4156
Conversation
Signed-off-by: Green hats <183933879+Green-hats@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
评审绑定 exact head:5046019c2cb95e59d153fa2747fa47f6dd839198。
动机
这个 PR 修复的用户问题真实且高频:Personal Workspace 在没有有效本地语言选择时固定落到中文,因此英语浏览器的新用户第一屏语言错误。目标行为是继续让已有 loopx-pw-locale 明确选择拥有最高优先级;只有首次使用或存储值无效时,才按 navigator.languages 的顺序选择英文或简体中文,并在没有受支持语言时回退英文。更长的英文摘要标签在窄屏上的换行也属于同一首屏可用性问题。
改动思路
实现放在既有 i18n owner 中是合适的:WorkspaceI18nProvider 仍由 readWorkspaceLocale 初始化,持久化 key、Settings 写入和 document.documentElement.lang 更新都没有形成第二套状态。正向路径是“有效存储值 → 直接使用;否则扫描浏览器语言 → 首个 en/zh 命中;否则 en”;负向路径覆盖存储读写异常、空/不支持语言和无效存储值。四行响应式 CSS 让摘要卡片与统计胶囊在 720px 以下换行,直接服务英语首屏。
具体改动
关键代码讲解
apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx:1789的readWorkspaceLocale将原来“只有存储值是 en 才用英文,否则固定 zh-CN”改为精确接受已存的en/zh-CN,再按浏览器偏好顺序匹配主语言。它不会把自动检测结果写回,因此不会把环境推断冒充用户选择。- 同文件的
WorkspaceI18nProvider继续拥有会话语言与显式选择持久化;存储写失败时仍可在当前会话切换,刷新后重新检测,和 README 的公开说明一致。 workspace-locale-browser-smoke.mjs增加 13 组真实浏览器场景,并覆盖双向 Settings/reload、存储异常以及 390px 视口的统计标签越界;personal-workspace-browser-smoke.mjs把它接入开发与 packaged smoke。- README 明确披露了旧默认、新默认、同源存储边界和 WebView/端口变化后的重新检测;packaged Chat JS/CSS/index 由同一源码重建。
对主干的风险
源码行为本身通过了反例验证:同一浏览器 harness 在 base 081ff998f 的 fresh en-US 场景得到 zh-CN 并失败,在本 head 上 13 个语言场景、双向持久化和移动端边界全部通过;Personal Workspace contract、TypeScript 检查、两次 Vite build 与 diff hygiene 也通过,构建后工作树保持干净。一次默认端口运行命中了已有旧服务而超时,换到隔离端口后完整通过,未复现产品缺陷。
当前阻塞是集成状态:GitHub 报告 CONFLICTING/DIRTY,对最新 main 的 git merge-tree 也在 loopx/web/chat/index.html 产生内容冲突。源文件可以自动合并,但生成 index 引用的是旧 base 上的 hashed assets;如果手工保留错误一侧,packaged /chat 可能引用不匹配的资源。请 rebase 到当前 main,从合并后的源码重新 build packaged Chat,并重跑 build 与 locale browser smoke。
我的整体评价
结论是 REQUEST CHANGES,唯一阻塞是当前 exact head 不能安全集成;locale 设计、既有状态 owner、默认行为披露和 mutation-sensitive 浏览器覆盖都成立。范围也与问题成比例:手写运行时代码很小,主要体积来自真实浏览器回归和必须提交的 packaged assets。修复不需要新框架,只需 rebase、重新生成资源并在新 head 上复审。
English verdict: REQUEST_CHANGES — exact head 5046019c2cb95e59d153fa2747fa47f6dd839198 correctly fixes first-use browser locale selection and passes the real browser/build checks, but it conflicts with current main in the generated packaged Chat index; rebase, rebuild the packaged assets, and rerun validation on the new head.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> # Conflicts: # apps/presentation/dashboard/package.json # examples/personal-workspace-browser-smoke.mjs # loopx/web/chat/index.html
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
动机
当前主干首次打开 Personal Workspace 时,即使浏览器首选英文也固定显示中文。对英文用户,第一屏的导航和操作含义需要先猜;对长期使用者,显式选过的语言又必须继续优先。本 PR 把这两个行为同时闭环:新用户按浏览器偏好进入,已有选择按原存储键读回,受限存储环境仍可使用。它完成了这个首次体验问题的可独立验证切片。
改动思路
readWorkspaceLocale 仍由现有 i18n provider 拥有:先读取合法的显式值,再按 navigator.languages 的顺序寻找英文或中文,最后退回英文;不把语言决策移到后端或另建配置源。移动端的统计标签只在窄屏换行。原分支针对旧单文件浏览器脚本的改动,合入时迁到现行可选择的场景目录;原有中文文案场景显式使用中文浏览器上下文,让默认语言变化不会悄悄改写它们的测试前提。
具体改动
确切 head 193db9947ff81ad1e82cbfe86d3f10544edfe872 相对当前主干改动 7 个文件。产品代码只改变首次语言选择和 720px 以下统计布局;README 双语说明首次检测、同源保存、WebView/来源切换及存储失效。浏览器场景覆盖 13 种首选语言、已保存偏好与存储异常,并检查设置页双向切换、刷新读回和 390px 首屏。
关键代码讲解
readWorkspaceLocale先认en/zh-CN的显式选择,再解释浏览器语言列表;无匹配或无法读到有效语言时使用英文,存储读取异常不会阻塞页面。.personal-digest-stats在窄屏换行,使较长英文标签留在可视宽度内,不改变桌面布局。verifyWorkspaceLocales通过真实浏览器和共享合成 API 检查首次进入、存储拒绝、设置更改与刷新;被拒绝写入时只承诺当前会话的语言。- 场景 runner 对原有中文断言显式传入中文 locale,新的语言场景则接收未改写的浏览器,以免测试基线受到默认语言变化的偶然影响。
对主干的风险
这是有意改变默认行为,不能把它写成纯重构;README 与 PR 正文均已披露英文回退规则。最强反例是旧中文场景被英文浏览器默认值误导,或显式选择被自动检测覆盖。完整工作区源码浏览器场景、13 个语言用例以及新打包 Chat 的同组用例均通过;中文旧场景使用固定 locale,显式选择在刷新后仍优先。浏览器测试使用合成状态响应,因此证明前端入口和存储行为,不证明真实远端服务。新代码不授予额外权限,也不改变 Goal/Todo 内容;若未来新增语言,仍需在同一 provider 扩展规则与对应用例。确切差异的 premerge 通过 17/17 项及 3 项差异检查,公开边界扫描通过;本地无失败、跳过或手工 hold。按当前托管评审配置,远端 CI 不作为本次评审证据。
我的整体评价
长线使用和首次用户体验都改善:英文用户能直接读懂第一屏,老用户的保存选择不丢,无法保存时页面仍可交互。七文件差异中测试与说明占主要体积,产品机制仍落在既有 i18n 所有者,没有第二套语言状态或权限模型。源码、打包版与移动宽度的证据覆盖了这次承诺;全量发布资格仍需在最终标签提交上单独执行。我批准当前确切 head 合入。
English verdict: APPROVE - exact head 193db99; browser-first locale with saved-choice precedence, storage fallback, mobile fit, source and packaged browser validation.
|
Thank you, @Green-hats, for making the first-run workspace language follow the browser while preserving explicit choices and checking the mobile layout. I’m sorry I left this PR waiting for so long and overlooked the work needed to bring its browser tests onto the current codebase. I’ve now integrated, reviewed, and merged it. I’ll credit your contribution in the upcoming release notes. |
First-time users now see the Personal Workspace in their browser's first supported language. An explicit English or Simplified Chinese choice still wins and survives same-origin reloads; when storage is unavailable, the workspace remains usable and follows the browser for that session. The English summary statistics also wrap on narrow screens.
Fixes #3543.
The fork branch is integrated with current
main. Its locale logic remains in the existing Personal Workspace i18n provider, and the original browser matrix is registered as a selectable scenario in the current modular smoke runner. Obsolete tracked Chat build assets were dropped because the current build generates the packaged bundle.Validation on the integrated head:
npm run buildpassed TypeScript and both current production builds.git diff origin/main...HEAD --checkpassed. Exact-head canary/CI status is recorded separately on this PR.The change affects workspace chrome, not user-entered content or backend language policy. A new origin or webview has separate browser storage. The related dashboard-wide storage-access failure is addressed in #4159.
Future-facing pass: the existing i18n provider and browser scenario runner remain the owners; no new language framework or preference store was added.