构建时内联语言包比运行时fetch更稳更快易维护,因避免网络抖动白屏、CSP拦截、SEO失效及localStorage版本错乱等问题,且需确保多语言JSON字段严格对齐、data-i18n精准标记可渲染节点并校验双向一致性。

直接用 data-i18n + 构建时内联语言包,比运行时 fetch 更稳、更快、更易维护。
为什么运行时加载语言包容易失控
每次切换语言都 fetch('./locales/zh.json'),看似灵活,实则埋雷:网络抖动时白屏、CSP 策略拦截、SEO 抓取不到翻译后内容、localStorage 里存的是旧版本 JSON 导致 fallback 失效。更麻烦的是,多人同时改语言包字段名,没校验机制,上线就留空。
- 语言包必须是纯 JSON,且所有语言文件字段严格对齐——
en.json有"btn_submit",zh.json就不能少,哪怕值为空字符串"" - 构建阶段就把
./locales/en.json和./locales/zh.json打包进 HTML,用<script type="application/json" id="i18n-data">内联,避免运行时 IO 不确定性 - 不推荐把整个语言包塞进 JS 变量里硬编码,一来体积难控制,二来更新需全量发版
怎么让 data-i18n 标记不漏、不冗余
data-i18n 不是装饰,是翻译契约的锚点。漏标一个 alt 或 placeholder,切换语言后那里就是空白;乱标 <script> 或 <style> 里的文本,则白忙一场。
- 只标记可渲染节点:
<h1>、<p>、<button>、<label>、<legend> - 属性级翻译要显式后缀:
data-i18n-placeholder、data-i18n-title、data-i18n-alt——value永远跳过(用户输入不属于文案) - 含 HTML 的文案(如“请阅读使用条款”)必须用
innerHTML渲染,且语言包对应字段值需经DOMPurify.sanitize()过滤,否则 XSS 风险直线上升
lang 属性同步不是“设一次就完事”
document.documentElement.lang = 'zh-CN' 只改了根节点,但页面里可能有 <p lang="en"> 引用英文术语、<pre lang="bash"> 代码块、第三方组件 iframe 里的子文档——它们的语言不会自动继承,屏幕阅读器会读错,字体回退也失效。
立即学习“前端免费学习笔记(深入)”;
- 切换语言时,必须遍历所有带
lang属性的元素,按需保留或重置:el.lang = el.hasAttribute('data-lang-keep') ? el.lang : newLang - 给需要锁定语言的节点加
data-lang-keep,比如技术术语段落、代码示例、嵌入的 YouTube 字幕容器 - 第三方评论框(如 Disqus)、统计脚本(如 GA4)无法控制其内部
lang,得靠data-lang-sync属性标记父容器,加载后手动同步
最易被忽略的其实是语言包和 DOM 标记的双向一致性——没人检查新增的 data-i18n="form.email_hint" 是否在所有语言 JSON 里都有对应键,也没人验证某个键被删了但 HTML 还挂着。这得靠构建脚本跑一遍 jq -r 'keys[]' en.json | sort 和 jq -r 'keys[]' zh.json | sort 对比,而不是靠人眼扫。



















