核心是语言包加载失败必须fallback、切换不重绘整页、首屏不等JSON加载完才渲染;需内联最小化语言包、按需动态加载、并行拉取、合理缓存与CDN配置,并纳入CI/CD校验。

怎么让多语言页面在生产环境不崩、不白屏、不卡顿
核心是「语言包加载失败必须 fallback,切换过程不能重绘整页,首屏不能等 JSON 加载完才渲染」。硬编码 fallback 语言(如 en)比抛错或留空更关键——用户看到英文总比看到空白文案强。
- 所有
fetch('locales/zh.json')必须带.catch(() => loadFallback('en')),不能只靠 try/catch 包裹整个函数 - 首次渲染用内联的最小化语言包(如
<script type="application/json" id="i18n-inline">{"home.title":"首页"}</script>),避免白屏 - 语言包体积控制在 50KB 以内;超过就拆成
common.json+form.json,按需import()动态加载 - 不要在
DOMContentLoaded里串行加载多个语言包——用Promise.all([fetch(zh), fetch(en)])并行拉取,但只初始化当前语言的那一个
CDN 和缓存怎么配才不翻车
语言包是静态资源,但必须禁用 aggressive 缓存策略。浏览器一旦缓存了旧版 zh.json,改了文案用户也看不到。
-
locales/*.json的 HTTP 响应头设为Cache-Control: public, max-age=3600(1 小时),别用max-age=31536000 - 构建时给 JSON 文件加 hash:
locales/zh.abc123.json,HTML 中通过构建脚本注入真实路径 - 如果用 Nginx,加配置防止未授权访问:
location ^~ /locales/ { deny all; }—— 语言包不该被直接 URL 访问 - CDN 缓存键要包含
Accept-Language头(仅限 SSR 场景);纯前端方案则忽略该头,统一回源
怎么和 CI/CD 流水线对齐
语言包不是代码,但它的缺失、key 错位、格式错误会直接导致线上文案消失。必须进流水线卡点。
- PR 提交前跑校验脚本:检查所有
locales/*.json是否合法 JSON、各文件 key 数量是否一致、空值字段是否全为""而非null - 部署阶段加 smoke test:用 Puppeteer 打开页面,断言
document.querySelector('[data-i18n="home.title"]').textContent不为空 - 禁止手动上传 JSON 到服务器——全部走 CI 构建产物,确保
zh.json和 HTML 引用的版本严格对应 - 灰度发布时,把语言切换按钮的 target 属性指向灰度域名下的
/locales/zh.json,验证无误再全量
为什么不能把语言包全量打包进 JS bundle
看似省事,实则破坏缓存粒度、拖慢首屏、无法按需加载。尤其当新增一门语言(如 ja)时,所有用户都得重新下载整个 bundle。
立即学习“前端免费学习笔记(深入)”;
- JS bundle 里存语言包 → 修改任一语言文案 → bundle hash 变 → 所有用户丢失长期缓存
- 移动端弱网下,200KB 的 bundle 比 5KB 的
zh.json更容易超时或中断 - 服务端 SSR 渲染需要同步读取 JSON,而打包进 JS 的语言包只能异步解包,造成 CSR/SSR 不一致
- 正确做法:语言包放独立域名(如
https://i18n.example.com/zh.json),HTTP/2 下复用连接,且可单独压测



















