国际化资源加载慢的根源在于首屏全量加载所有语言包,正确做法是依据accept-language请求头动态加载当前locale文件,并通过brotli压缩、内联小数据、服务端fallback等手段优化ttfb。

国际化资源加载慢,八成是因为所有语言包在首屏就全量下载、解析并挂载,哪怕用户只看中文页面。关键不是“怎么翻译”,而是“怎么让浏览器只加载当前需要的语言资源”。
language negotiation 之后才加载对应 locale 文件
浏览器的 Accept-Language 请求头是真实可靠的信号,但多数工程化方案忽略它,直接在构建时把所有 zh-CN、en-US、ja-JP 全打进 bundle。正确做法是服务端或边缘层(如 Cloudflare Workers、Vercel Edge Functions)根据该 header 动态返回对应 locale 的 HTML 或内联脚本。
- Node.js/Express 示例:用
req.acceptsLanguages()[0]匹配最优先语言,再读取对应messages.zh-CN.json并注入到<script type="application/json" id="i18n-data"></script> - 纯静态部署时,可用
<link rel="preload" as="fetch" href="/i18n/zh-CN.json" crossorigin>配合fetch()按需拉取,但必须加crossorigin,否则跨域失败 - 绝对不要用
import('./locales/' + lang + '.js')动态导入后eval()或new Function()执行——这绕过 CSP,且无法被预加载或缓存策略控制
JSON messages 必须压缩 + Brotli 服务端启用
未压缩的 en-US.json 常超 200KB(尤其含富文本、复数规则),gzip 后仍 >80KB;Brotli 可压到 40–60KB,但前提是服务器明确开启且响应头带 Content-Encoding: br。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- Nginx 配置必须包含:
brotli on;、brotli_types application/json;、brotli_comp_level 6; - 验证方式:Chrome DevTools → Network → 查看响应头是否有
Content-Encoding: br,且 size 显示为 “br” 字样 - 若用 Vercel/Netlify,Brotli 默认启用,但需确认 JSON 文件后缀为
.json(非.js),否则不触发压缩
i18n 初始化时机卡在 DOMContentLoaded 之前
很多框架(如 i18next)默认等 document.readyState === 'complete' 才开始初始化,此时 HTML 已解析完、CSSOM 构建完、甚至 LCP 都可能完成了——但用户看到的是占位符或英文 fallback。
- 解决方案:把 locale 数据内联进 HTML 的
<script></script>标签(体积 ≤1KB),用同步脚本立即初始化,例如:<script>window.I18N_DATA = {hello: "你好"};</script> - 超过 1KB?改用
<script type="module"></script>+await import(),模块脚本天然 defer,且支持顶层 await,可等数据 fetch 完再挂载 - 避免在
window.onload或 ReactuseEffect(() => {}, [])里初始化——它们太晚,CLS(布局偏移)和 FCP 都已定型
fallback 语言不能触发二次请求
用户语言为 zh-TW,但你只提供了 zh-CN 和 en-US,理想路径是:尝试 zh-TW.json → 404 → 回退 zh-CN.json → 成功。但现实中常变成:404 → 再发一次请求 → 等待 → 渲染延迟。
- 服务端应主动做 fallback:收到
zh-TW,先查zh-TW.json,不存在则查zh-CN.json,存在则直接返回,状态码仍是 200 - 客户端 fallback 要预设链:配置
fallbackLng: ['zh-CN', 'en-US'],但必须配合load: 'languageOnly'避免请求zh.json这类模糊匹配(易 404) - 所有 fallback 请求都必须加
cache-control: public, max-age=31536000,因为内容不变,不该反复试探
真正难的不是多语言切换,而是让浏览器在 TTFB 阶段就拿到正确的字符串——这要求服务端参与、压缩不可省、初始化不能拖,任何一环掉链子,用户第一眼看到的就是“Loading…”或者英文词。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










