vue-i18n 架构瓶颈凸显,Intlayer 提出构建时预编译方案
译注:本文编译自 dev.to 文章《The Problem with vue-i18n and Why Intlayer Fixes It》,作者 Ay Pineau,原文发布于 2026 年 9 月 23 日。文中数据与观点均来自原文,链接见文末。
在 Vue 3 或 Nuxt 中构建国际化应用时,vue-i18n 长期是默认选择。Kazupon 与社区共同打造了一个成熟且功能丰富的生态,多年来一直是 Vue 应用本地化的标准方案。
要理解 vue-i18n 为何如此运作,需要回到它架构设计的年代:它诞生于经典的单页应用(SPA)时代,那时动态导入(import())与路由级代码分割尚未普及。在那种范式下,启动时把单个庞大的翻译对象一次性加载进内存完全合理。
然而现代前端开发围绕激进的页面体积优化展开,无论是使用 Nuxt、静态站点生成(SSG)还是细粒度的动态页面加载。在这一背景下,中心化的全局 provider 模型已成为严重的架构瓶颈。
库本身体积也出乎意料地大:一个仅导入 vue-i18n 的空组件,在渲染任何一个字之前就要付出 24.3 KB gzip(83.2 KB minified) 的代价。为什么这么大?因为它内置了一整套运行时引擎,在浏览器中即时处理消息格式逻辑,求值 {{number}} 或 {name} 这类动态插值、复数规则与列表格式化。此外,处理本地化路由与 URL 管理还需要额外的客户端逻辑,用于 cookie 存储、语言检测与 URL 前缀。
这还没算上更大的架构缺陷:跨路由的大规模文案泄漏。
在典型的 Vue 应用中,createI18n({ messages }) 会实例化一棵全局消息树,包含所有受支持语言的每一个翻译键。用户访问一个简单的 /contact 页面时,浏览器被迫下载 /dashboard、/pricing、/settings 以及应用其余部分的字符串。在一个标准的 10 路由、10 语言的 Vite + Vue 3 应用基准测试中,某个页面上下载的翻译负载有 90% 属于完全无关的路由。由于 useI18n() 将组件绑定到这个全局实例,单独编译一个组件平均会拖入 196 KB 的 JavaScript。
更进一步,由于 t("key.path") 依赖运行时动态字符串求值,Vite 和 Rollup 等打包工具无法静态追踪实际使用了哪些键。未使用的翻译无法被 tree-shaking,键名拼写错误会在运行时静默失败,而不是在构建期被 TypeScript 捕获。
Intlayer 如何解决?
Intlayer 的思路是在构建时消除这些额外逻辑,通过静态转换把内容直接连接到相关组件,而不是依赖臃肿的运行时解析器与 provider。
1. 构建时预编译(无运行时解析开销)
不再把沉重的解析器发送到浏览器去求值 {{number}} 这类消息插值,或在运行时管理 cookie 存储与 URL 前缀,Intlayer 在构建期就解析并优化这些逻辑。浏览器收到的是精简的预编译代码,所有额外机制都被剥离,运行时体积降至 3.9 KB(使用兼容适配器则为 7.9 KB)。
2. 组件与内容直接绑定
不再把所有字符串倾倒进庞大的 locales/en.json,Intlayer 将字典就近放置在消费它的组件旁边(例如 Footer.content.ts 与 Footer.vue 并列)。因此,未被导入的组件永远不会加载未使用的内容。死代码与未渲染组件不携带任何翻译体积。
3. 借助 Vite 实现零瀑布式动态加载
更进一步,Intlayer 利用了 Vite 的高级模块转换能力。即使使用动态页面加载与代码分割,Intlayer 也只把该 chunk 中实际消费的本地化内容直接附加进 bundle。没有额外的网络请求或瀑布去等待远程 JSON 字典再渲染。组件与其精确的本地化字符串在同一个 chunk 中一起到达。
4. 严格的编译期安全
Intlayer 直接从内容声明生成严格的 TypeScript 定义。你可以获得键名的 IDE 自动补全,缺失翻译或拼写错误会在构建期立即报错,从而消除生产环境中的运行时回退意外。
5. 0% 泄漏与 3 倍更小的 bundle
在构建期,Intlayer 编译器静态分析调用点并拆分字典,使每个路由只下载它实际渲染的字符串。在基准测试中,页面文案泄漏从 90% 降至 0%,每页 JavaScript 从 134.9 KB 降至 47.0 KB(gzip)。作为参照,不含任何 i18n 的基线应用为 41.3 KB。
6. 通过 @intlayer/vue-i18n 直接迁移
如果你已有 Vue 代码库,无需重写组件。@intlayer/vue-i18n 兼容适配器暴露与 vue-i18n 完全相同的 API(useI18n、t()、d()、n()、$t、v-t)。只需添加 Vite 插件并去掉庞大的 messages 导入,现有的 t("key") 调用就会自动绑定到编译后、已拆分的字典,在零 .vue 文件改动的前提下将运行时缩小 3 倍、组件缩小 23 倍。
如果你在生产环境运行本地化的 Vue 或 Nuxt 应用,不妨在任意子页面查看浏览器的 Network 面板:你很可能会发现,下载的 JavaScript 中大部分是用户永远不会读到的翻译文案。
完整的分析、基准测试与迁移指南见:
- https://intlayer.org/blog/vue-i18n-vs-intlayer
- https://intlayer.org/blog/vue-i18n-vs-intlayer-vue-i18n