最轻量可行路径是data-i18n标记+json语言包+localstorage持久化;需显式为所有文本节点及placeholder/title/alt等属性添加对应data-i18n后缀,语言包扁平结构、bcp 47命名,切换时同步更新document.documentelement.lang、localstorage及动态节点。

直接用 data-i18n 标记 + 独立 JSON 语言包 + localStorage 持久化,是当前最轻量、不依赖构建工具、且能绕过框架锁定的可行路径。硬编码文案、只改 document.documentElement.lang、或靠 class/id 推断翻译键,都会在后续维护中出问题。
怎么给 HTML 元素打 data-i18n 标记才不漏不乱
所有要换语言的文本内容,必须显式加 data-i18n 属性,值为语言包里的键名,比如 "header_title" 或 "form_email_required"。
-
data-i18n只影响元素自身的textContent,不会动placeholder、title、alt这类属性——得用data-i18n-placeholder、data-i18n-title等带后缀的写法 - 表单控件、SVG 文本、按钮文字都要单独加,不能指望父容器一统到底
- 别在
<script></script>、<pre class="brush:php;toolbar:false;"></pre>、<style></style>里加——这些节点不渲染为用户可见文本,加了没效果 - 如果某段文案含 HTML(比如“请阅读服务条款”),就得用
innerHTML替换,但语言包里对应值必须是可信的纯 HTML 片段,否则有 XSS 风险
为什么必须同步更新 document.documentElement.lang 和子元素 lang
只改根节点的 lang,对已渲染的子元素完全无效。浏览器和屏幕阅读器按每个节点自己的 lang 属性决定语音、字体回退、标点间距——不是继承来的。
- 页面加载时,应设
document.documentElement.lang = 'zh-Hans'(注意:必须符合 BCP 47,zh_CN或chinese会被忽略) - 切换语言后,要遍历所有带
lang的元素,把非根节点的lang值也同步更新,比如一段日文引用<p lang="ja">...</p>,不能跟着主语言切成lang="en" - 局部多语言内容(如代码块、英文术语、引文)必须显式写
lang="bash"或lang="en",不能指望全局覆盖
locales/zh.json 这类语言包怎么组织才不翻车
结构扁平、键名一致、路径可预测,是稳定运行的前提。别把所有语言塞进一个大对象里,也不要把键名嵌套成 {"ui": {"header": {"title": "Home"}}。
- 每种语言一个文件:
locales/zh.json、locales/en.json、locales/ja.json,内容全是顶层键值对 - 所有文件键名必须严格一致;某语言暂未翻译,也要留空字符串或占位符,否则 JS 查不到 key 就留白
- 加载失败时必须有 fallback:
fetch失败或 key 不存在,一律退到en或你设定的主语言 JSON,否则整页文案消失 - 避免在 JSON 里放需要运行时计算的内容(如用户昵称、时间格式),这类得用插值语法(如
"hello {name}")+ JS 运行时替换,别硬塞进静态语言包
最容易被忽略的是:语言包键名一旦定下,就很难重构;data-i18n 不是“写了就生效”,它依赖 JS 扫描、查表、赋值三步闭环;而 lang 属性若没随语言切换同步更新,对无障碍和字体渲染的影响是静默且不可逆的。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











