- 状态:Accepted
- 日期:2026-08-12
- 关联:ADR-0006(保留现有 Web 页面并通过适配层对接 API)
设置中心早就有「界面语言」下拉,但它只是一个不生效的控件。要让英文真正可用,需要在 不破坏界面基线的前提下翻译整个产品外壳。
约束来自现状:14 个页面由 apps/web/src/legacy/openmathmodel-ui.ts 一次性生成中文
markup,该文件超过 3000 行、含约 730 行中文,且属于 ADR-0006 列出的受保护入口。把它
改写成 key 驱动的模板,意味着对每一处文案做机械替换——改动面覆盖全部页面结构,回归
风险与收益完全不成比例。
同时,界面上并存两类文本:一类是产品文案(按钮、标题、状态、提示),另一类是真实数据 (项目名、赛题标题、论文题目、用户输入的论文正文)。本地化只能作用于前者。
新增 apps/web/src/i18n/:
en-US.ts:中文原文 → 英文译文的词典;dom-translator.ts:按整段完全匹配替换文本节点与placeholder、title、aria-label、alt、data-title、data-subtitle属性;locale.ts:读写openmathmodelSettings.interfaceLanguage,应用语言并广播变更。
这与 ADR-0006 的适配层方向一致:后端语义、真实数据和现在的界面语言,都是在既有 DOM 上 做原位适配,而不是另建一套页面。
只有修剪空白后与词典键完全相等的文本才会被替换。项目名、赛题标题、论文编号这类真实
数据不会出现在词典里,因此不可能被改写。这条规则同时决定了本地化的能力上界:由变量拼接
出的句子匹配不到词典,需要在代码里显式调用 t()。
<script>、<style>、<code>、<pre>、<textarea> 以及任何
contenteditable 子树整体跳过。论文正文是用户数据:若用户恰好写下与词典键相同的词,
替换会直接篡改他的内容。
词典缺项时保留中文,不显示占位符、不报错。宁可少译,不可错译。
设置中心内选择即时预览,保存后写入 openmathmodelSettings,未保存就关闭会还原为打开
前的语言。启动时在首屏渲染前应用,避免先闪一帧中文。切回中文时用记录的原文还原,不刷新
页面。
赛题库与论文库中的真实竞赛题面、论文标题,以及方法库的中文技术条目,保持原语言。这些是 数据而不是界面文案,机器翻译它们等于伪造内容。
正向结果:
- 界面语言开关真实生效,覆盖外壳、设置中心、账户与安全、任务流程六页与知识库页面框架;
- 受保护的页面结构、样式与路由零改动;
- 真实数据与用户内容不受影响;
- 新增页面无需接入 i18n 框架即可工作,补词典即可获得英文。
代价与约束:
- 词典以中文原文为键,改动界面文案时必须同步更新词典,否则该条回落中文;
- 由变量拼接的句子必须显式
t(),否则不会翻译; - MutationObserver 常驻,需在自身写入时暂停观察以避免回环。
- 切换到 English 后,侧栏、设置中心、账户与安全、六个流程页面与知识库页面框架显示英文;
- 切回简体中文后完全还原,无残留英文、无重复文本;
- 项目名、赛题标题、论文题目与用户输入的论文正文在两种语言下都保持原样;
- 未保存就关闭设置中心时语言还原;刷新页面后保存过的语言仍然生效;
<html lang>随语言变化;- 词典质量门禁(
en-US.test.mjs)通过:无空译、无原样返回、无重复键、无残留中文。