切换语言需同步更新lang属性、显式标注data-i18n及后缀、手动翻译动态DOM、用fetch加载校验JSON语言包并降级,默认语言fallback优先navigator.language而非localStorage。

只改 document.documentElement.lang 不会让页面真正“变成”另一种语言——文字不变、屏幕阅读器读错、标点间距乱、字体回退失效,这是绝大多数人踩的第一个坑。
data-i18n 属性必须覆盖所有可翻译属性,不只是 textContent
常见错误现象:<input placeholder="Search"> 切换语言后仍是英文;<img alt="user avatar"> 的替代文本没更新;<label for="email">Email</label> 文字翻了但 for 属性没同步,点击 label 失效。
data-i18n 默认只作用于元素的 textContent,对 placeholder、title、alt、aria-label 等属性完全无效。
- 必须显式加对应后缀:如
data-i18n-placeholder="search_hint"、data-i18n-alt="avatar_desc"、data-i18n-title="tooltip_info" -
value属性一般不翻译(属于用户输入数据),跳过处理;但button和input[type="submit"]的显示文案建议统一用textContent更新,避免value被意外提交 - 含 HTML 结构的文案(如“请阅读服务条款”)必须用
innerHTML替换,且语言包里对应值要是可信纯 HTML 片段(不能带用户输入、不执行 JS),否则有 XSS 风险
lang 属性必须逐层显式设置,不能依赖继承
只执行 document.documentElement.lang = 'en' 是无效的。屏幕阅读器、字体渲染引擎、标点间距规则都依赖每个元素自身的 lang 属性,而不是继承值。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
切换语言时,必须遍历所有已带 lang 属性的元素(如 <p lang="en">、<pre lang="bash">),把它们的 lang 值也同步更新(除非明确要保留原语言)。
- 所有含文本的语义化标签(
<h1>、<p>、<section>、<footer>等)都应显式加lang属性,值与当前语言包一致(如lang="zh-Hans") - 已有
lang的特殊元素(如<pre lang="bash">、<code lang="sql">)切换语言时保留原值,这是多语言混排的合法场景 -
<script>和<style>内部不要写lang,它们不参与文本渲染,设了也白设
动态插入的 DOM 必须手动触发翻译,不会自动监听
AJAX 加载的弹窗、表格行、懒加载模块插入后,如果没调用翻译函数,里面的 data-i18n 标记就只是字符串,不会变成对应语言文本。
点击按钮打开的 <modal>,内部 <h2 data-i18n="modal_title"> 不会自动更新;分页表格每页 AJAX 获取新 <tr>,新行里的 data-i18n 保持原始键名。
- 动态插入内容(如弹窗、表格行)必须在
appendChild()后立即调用翻译函数,不能依赖全局扫描 - 不要依赖
MutationObserver自动监听——它无法可靠识别语义边界,也无法处理 SVG 中的<text>节点 - SVG 内嵌文本(如
<text>下载</text>)需额外加data-i18n并在 JS 中识别SVGTextElement类型做特殊处理
语言包加载必须用 fetch + try/catch,且检查响应头
把语言包直接写进 JS 里,会导致构建产物体积膨胀、无法按需加载、热更新困难;用 XMLHttpRequest 老式写法又容易忽略 HTTP 状态码和 MIME 类型校验,遇到 404 或服务器返回 text/plain MIME 时静默失败。
- 语言包路径统一为
./locales/${lang}.json,例如./locales/zh-HK.json、./locales/en-US.json - 加载必须用
fetch(),外层包try/catch,内部检查response.ok和response.headers.get('content-type')?.includes('application/json') - fetch() 加载失败时必须降级到默认语言:先试完整码(如
zh-HK),再截主语言(zh),最后 fallback 到内置对象(如{"header_title": "Welcome"}) - 不要依赖
localStorage存“上次选的语言”来决定首次加载——用户可能清过缓存,或在新设备打开,此时navigator.language更可靠
最易被忽略的点是:HTML 结构层级本身会影响 i18n 工具识别作用域的能力——从 body 到目标 data-i18n 元素的嵌套深度若超过 6 层,部分工具会漏扫;冗余 div 应尽早替换为 <main>、<section> 等语义标签,既天然中断嵌套深度,又让翻译逻辑更可控。


















