HTML国际化打包需构建时识别语言维度、按需产出、不增大主包且保留运行时切换能力;应采用单模板+动态templateParameters+语言键名映射,Vite需配置JSON动态导入插件或预加载,语言包须构建期生成异步模块并同步更新document.lang。

HTML国际化打包不是“把语言文件塞进 dist 就完事”,而是要让构建流程识别语言维度、按需产出、不污染主包体积、且保留运行时切换能力。硬编码多份 HTML 或把所有 JSON 打进 main.js,都会在后续迭代中卡住发布节奏。
html-webpack-plugin 怎么配多语言输出才不重复写模板
用多个 HtmlWebpackPlugin 实例是可行的,但模板不能每个语言一份——维护成本爆炸。正确做法是:单模板 + 动态 templateParameters + 语言键名映射。
- 模板里所有文案用
${title}、${welcome}这类插值,而不是data-i18n;这一步只用于构建时静态生成(CSR 场景不用) - webpack 配置中用
Object.keys(languages).map(lang => new HtmlWebpackPlugin({ ... }))循环注入 -
templateParameters必须包含lang字段(如'zh-Hans'),并确保它被写入<html lang="${lang}"> - 别在 templateParameters 里传整个语言对象,只传扁平键值对,避免嵌套导致插值失败
- 输出 filename 建议统一为
index.${lang}.html,配合 Nginx 或 CDN 的Accept-Language路由规则可实现零 JS 切换
为什么 Vite 构建时 i18n JSON 会 404 或加载为空
Vite 默认不处理 .json 文件的动态 import,尤其当路径含变量(如 import(`./locales/${lang}.json`))时,Rollup 静态分析会跳过,导致构建产物里没打包该文件,运行时 fetch 失败或返回空对象。
- 必须显式配置
vite-plugin-static-import或使用vite-plugin-json-import插件支持 JSON 动态导入 - 更稳的做法是:构建阶段预加载所有语言包为 ESM 模块,再通过
import.meta.glob('./locales/*.json', { eager: true })收集,避免运行时网络请求 - 若仍走 fetch,路径必须用绝对路径(
/locales/zh-Hans.json),相对路径在构建后易因 base 配置错乱 - 检查响应头:
Content-Type: application/json缺失会导致response.json()抛错,但控制台可能无提示
怎么让语言包不打进 main.js 又能按需加载
直接 import en from './locales/en.json' 会让 Webpack/Vite 把它当依赖打进去;而纯 fetch 又失去 tree-shaking 和构建期校验。折中解法是「构建期生成语言模块,运行时惰性引用」。
立即学习“前端免费学习笔记(深入)”;
- 用脚本预扫描
./locales/下所有 JSON,生成一个locales/index.ts,内容类似:export const zh = () => import('./zh.json'); - 构建工具会把它识别为异步 chunk,产出独立文件如
locales-zh.abc123.js - 切换语言时调用
zh().then(mod => i18n.set(mod.default)),既免去 HTTP 请求,又不增大主包 - 注意:JSON 文件本身不能有注释或尾逗号,否则构建时报错,且键名必须全项目一致,否则运行时查不到 key
- 如果用了 TypeScript,给 JSON 声明模块:
declare module '*.json' { const value: Record<string string>; export default value; }</string>
最常被忽略的是:构建产出的语言资源路径与运行时 fetch 路径不一致,或没同步更新 document.documentElement.lang 和所有带 lang 属性的子元素——这两点会导致屏幕阅读器读错、字体回退失效、标点间距混乱,而且问题只在辅助技术下暴露,开发时根本看不出来。



















