使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本如果您有改善此文档的想法,请随时通过在GitHub上提交拉取请求来贡献。
文档的 GitHub 链接复制文档 Markdown 到剪贴板
vue-i18n VS Intlayer
vue-i18n 是 Vue 的参考 i18n 库。Intlayer 是一个基于编译器、按组件作用域划分内容的替代方案,并提供 Vue 集成(vue-intlayer)。本文关注的是应用构建完成后,每个库各自的成本。
数据来自 Benchmark Bloom,这是一个开源套件,它用每个库构建同一个应用程序,并记录浏览器实际下载和执行的内容。
tl;dr:在同一个 Vite + Vue 3 应用上,vue-i18n每页交付 134.9 KB 的 gzip 压缩 JavaScript,而无 i18n 的应用为 41.3 KB。Intlayer 交付 57.1 KB。仅vue-i18n的运行时就重达 24.3 KB gzip(是 Intlayer 3.9 KB 的 6 倍),每个页面携带 90% 的其他页面字符串,而单独编译的组件会拖入 196 KB,因为它绑定到全局消息树。@intlayer/vue-i18n适配器保留了vue-i18n的 API,测得每页 47.0 KB。
简而言之
- vue-i18n - Vue 2 / Vue 3 事实上的 i18n 库,也是
@nuxtjs/i18n的核心。ICU 风格的消息、SFC<i18n>块、v-t指令、d()/n()格式化器、庞大的生态系统。消息在createI18n()时注册到全局实例上;按语言的懒加载是手动的setLocaleMessage()模式,按路由拆分需要你自己构建。 - Intlayer - 以组件为中心的内容模型。
.content.ts字典与其服务的组件放在一起,构建时编译器(vite-intlayer)按组件、按语言进行 tree-shaking 和懒加载,从你的内容生成严格的 TypeScript 类型,缺失的翻译在构建时报错。附带路由 / SEO 辅助工具、可视化编辑器 / CMS 以及 AI 辅助翻译。
在弹窗中打开表格以清晰地查看所有数据
徽章会自动更新。快照会随时间变化。
功能逐项对比
在弹窗中打开表格以清晰地查看所有数据
| 功能 | vue-intlayer (Intlayer) | vue-i18n |
|---|---|---|
| 翻译靠近组件 | ✅ 是,.content.ts 与每个组件放在一起 | ✅ 通过 SFC <i18n> 块(可选);全局目录是常见的配置 |
| TypeScript 集成 | ✅ 从内容自动生成严格类型 | ✅ 类型良好;严格的键安全需要为 schema 定义类型并保持纪律 |
| 缺失翻译检测 | ✅ TypeScript 错误 + 构建时错误/警告 | ⚠️ 运行时回退 + 控制台警告 |
| 富内容(组件 / Markdown) | ✅ 直接支持 | ⚠️ <i18n-t> 组件插值;Markdown 需外部插件 |
| ICU 支持 | ⚠️ 进行中 | ✅ 是 |
| 格式化(日期、数字、货币) | ✅ 基于 Intl 的格式化器 | ✅ d() / n() 配合 datetimeFormats / numberFormats |
| 本地化路由 | ✅ Vue Router / Nuxt 辅助工具,getMultilingualUrls | ⚠️ 非核心(@nuxtjs/i18n 或自定义路由配置) |
| SEO 辅助工具(hreflang、sitemap、robots) | ✅ 内置辅助工具 | ❌ 非核心 |
| Tree-shaking(只交付使用的内容) | ✅ 按组件、按语言,由编译器自动完成 | ⚠️ 手动:拆分目录,按路由调用 setLocaleMessage() |
| 懒加载 | ✅ importMode: 'dynamic'(一行配置) | ✅ 手动 import() + setLocaleMessage() |
| 清除未使用的内容 | ✅ 无用字典在构建时被移除 | ❌ 未内置 |
| 测试缺失翻译(CLI / CI) | ✅ npx intlayer content test | ⚠️ 第三方(vue-i18n-extract) |
| AI 翻译 | ✅ 内置,使用你自己的提供商密钥 | ❌ 否 |
| 可视化编辑器 / CMS | ✅ 免费可视化编辑器 + 可选 CMS | ❌ 否(外部本地化平台) |
| MCP 服务器与 Agent Skills | ✅ 是 | ❌ 否 |
| 生态系统 / 社区 | ⚠️ 较小但增长迅速 | ✅ 在 Vue 生态中庞大且成熟 |
基准测试
测量了什么
Benchmark Bloom 套件用每个库构建同一个 Vite + Vue 3 应用程序:10 个页面(home、about、blog、careers、contact、FAQ、pricing、products、settings、team)、10 种语言(en、fr、es、de、it、pt、zh、ja、ko、ru)、相同的组件和相同的内容。页面在 en 和 fr 下测量。
两个库都在 static 配置下测试,这是大多数 Vue 项目实际交付的方式:对 vue-i18n,导入每种语言的 JSON 并传给 createI18n({ messages });对 Intlayer,使用默认的 importMode: 'static'。在该模式下 Intlayer 也会打包所有语言,但编译器仍然按组件限定内容范围,所以一个页面只携带它所渲染组件的字典。
对每个构建,套件记录:
- Lib size:只导入 i18n 库的空组件的 gzip 体积。运行时的固定成本。
- Page JS:每页下载的 gzip JavaScript,对所有页面和语言取平均。
- Locale leak %:下载的 JS 中,属于用户未查看语言的翻译字符串所占比例(以
en和fr做指纹,因此 50% 意味着“另一种被测语言完整存在”;打包 10 种语言时,实际浪费更高)。 - Page leak %:下载的 JS 中,属于用户不在的页面的翻译字符串所占比例。
- Component avg:每个组件单独编译时的平均 gzip 体积。显示单个组件拖入了多少 i18n 运行时和目录。
- E2E reactivity:从选择新语言到 DOM 中
html[lang]更新之间的实际耗时(Playwright,5 次迭代)。 - Page load:
PerformanceNavigationTiming.duration。
下方数字来自 2026-09-12 的运行,使用vue-i18n11.4.0 和intlayer9.5.0 / 9.5.1。测试应用故意做得很小(每种语言几十个字符串),因此泄漏百分比描述的是一种模式:它们随你的内容增长,而运行时成本保持固定。
Vite + Vue 3 上的结果
选择你关心的指标和库:
指标
动态 JSON 加载
在运行时懒加载翻译
有作用域的 JSON (命名空间)
每页翻译命名空间
这个指标是什么?
国际化库包的总 gzip 压缩大小。它仅包含 tree-shaking 和压缩(minification)后的提供者(provider)和内容检索逻辑。
为什么这很重要?
较小的库大小可减少初始 JavaScript 负载,从而缩短客户端的下载和执行时间。
视图形式
在弹窗中打开表格以清晰地查看所有数据
| 库 | 策略 | Lib size (gz) | Lib size (min) | Page JS 平均 (gz) | Locale leak | Page leak | Component 平均 (gz) | E2E 响应速度 | Page load |
|---|---|---|---|---|---|---|---|---|---|
| base(无 i18n) | - | 0.0 KB | 0.0 KB | 41.3 KB | 0.0% | - | 1.1 KB | 1.8 ms | 10.8 ms |
vue-i18n | static | 24.3 KB | 83.2 KB | 134.9 KB | 50.0% | 90.0% | 196.0 KB | 2.8 ms | 13.6 ms |
vue-intlayer | static | 3.9 KB | 11.1 KB | 57.1 KB | 56.8% | 0.0% | 7.7 KB | 4.5 ms | 13.8 ms |
@intlayer/vue-i18n (compat) | static | 7.9 KB | 23.2 KB | 47.0 KB | 15.0% | 0.0% | 8.4 KB | 1.5 ms | 9.3 ms |
基础应用的 page-leak 列留空:没有 i18n 库时,指纹识别会捕获共享 chunk 中硬编码的字符串,该数字没有意义。
如何解读
- 运行时成本。
vue-i18n是整个基准测试中最重的运行时之一:只导入它的空组件就要 24.3 KB gzip / 83.2 KB 压缩后。vue-intlayer只要 3.9 KB gzip。无论你有多少字符串,这个差距在每个页面上都要付出。 - 每页 JavaScript。 无 i18n 的应用重 41.3 KB。
vue-i18n让它增至三倍多,达到 134.9 KB;Intlayer 落在 57.1 KB,+15.8 KB,其中大部分是打包的十种语言(见下一点)。 - 泄漏。 使用
createI18n({ messages: { en, fr, ... } })时,每个页面都交付所有语言和所有页面的字符串:50% 的语言泄漏(在两种指纹语言上)和 90% 的页面泄漏。Intlayer 的static模式也打包所有语言(因此语言泄漏数字相当),但页面泄漏为 0%:一个页面只拉取它渲染的组件的字典。切换到importMode: 'dynamic'还能消除语言泄漏;该配置不在本次 Vue 运行范围内。 - 组件体积是架构差异的体现。 调用
useI18n()的组件平均编译为 196 KB,因为t()绑定到持有所有语言所有消息的全局实例。同一个组件使用useIntlayer()编译为 7.7 KB:它只触及自己的字典。 - 响应速度对两者都不是问题(2-5 ms)。一旦消息在内存中,Vue 的响应式系统让语言切换非常廉价。
@intlayer/vue-i18n,即插即用的适配器,保留了vue-i18n的 API,测得每页 47.0 KB、每组件 8.4 KB,应用代码未做改动。
作为参考,同一次运行测得 fluent-vue 每页 171.8 KB、运行时 29.7 KB、每组件 217 KB。
包含所有库和所有策略的完整表格,请参见 Vue 基准测试报告。
差距从何而来?全局实例 vs 编译后的字典
vue-i18n 是一个运行时。createI18n() 构建一个全局实例,为每种语言持有一棵消息树;useI18n() 把每个组件绑定到它;t("footer.github") 在渲染时查找键。正是这一点使 SFC <i18n> 块、v-t 和运行时消息加载成为可能,也正是因此每个组件的依赖图都包含整棵树:
复制代码到剪贴板
优化意味着你把 en.json 拆成按路由的文件,你在路由守卫中调用 setLocaleMessage(),并且你在组件移动时维护路由到文件的映射。运行时无法替你做这些,因为它不知道组件会请求哪些键。
Intlayer 把这些知识移到构建阶段。内容在组件旁声明,vite-intlayer 解析哪个组件导入哪个字典:
复制代码到剪贴板
编译器按字典、按语言精确输出该组件需要的 JSON,并丢弃没有任何导入的字典。按路由的作用域是按组件作用域的自然结果,而不是一项任务。
若还想丢弃未使用的语言,在intlayer.config.ts中设置dictionary.importMode: 'dynamic'。参见 bundle 优化文档。
开发体验
设置
vue-i18n
复制代码到剪贴板
复制代码到剪贴板
Intlayer
复制代码到剪贴板
复制代码到剪贴板
复制代码到剪贴板
组件
vue-i18n
复制代码到剪贴板
复制代码到剪贴板
在你自己为消息 schema 定义类型之前,t('counter.label') 只是一个字符串;拼写错误会直接渲染出键名。
Intlayer
复制代码到剪贴板
复制代码到剪贴板
label 和 increment 是有类型的;拼写错误是 TypeScript 错误,缺失的法语值是构建错误。
按语言懒加载
vue-i18n
复制代码到剪贴板
然后在路由守卫中调用 loadLocaleMessages(),如果想要按页面的作用域,还得自己按路由拆分 locales/{locale}.json。
Intlayer
复制代码到剪贴板
保留 vue-i18n 的 API,获得 Intlayer 的输出
@intlayer/vue-i18n 是一个即插即用的适配器:useI18n()、t()、d()、n()、{name} 和 {0} 插值、管道复数("car | cars")、v-t 和 i18n.global.locale 都继续工作,但由 vite-intlayer 编译的 Intlayer 字典提供服务。
复制代码到剪贴板
在基准测试中,同一应用的 compat 构建每页从 134.9 KB 降到 47.0 KB,每组件从 196 KB 降到 8.4 KB,组件未做改动。通过 JSON 同步插件,你现有的 locales/{locale}.json 可以继续作为事实来源。
参见 vue-i18n 迁移指南和兼容性文档。Nuxt 用户可通过 @nuxtjs/i18n 兼容性走同样的路径。
何时选择哪一个?
- 选择 vue-i18n,如果你想要标准的 Vue 方式、依赖 ICU 消息或 SFC
<i18n>块、已经在使用@nuxtjs/i18n,或者翻译平台期望集中式 JSON。如果 bundle 体积很重要,请预留时间来拆分目录并按路由懒加载。 - 选择 Intlayer,如果你想要按组件作用域的内容、严格的 TypeScript、构建时的缺失键错误、零成本的 tree-shaking 和懒加载,以及内置的编辑工具(可视化编辑器、CMS、AI 翻译、MCP 服务器)。对大型模块化 Vue / Nuxt 代码库和设计系统尤其适用。
- 选择
@intlayer/vue-i18n,如果你已经在用vue-i18n,想在不重写的情况下获得 bundle 收益。
常见问题解答
两者兼具,取决于您的采纳方式。vue-intlayer 是一个拥有独立 useIntlayer() 组合式函数的原生运行时。@intlayer/vue-i18n 则是一个兼容适配器,它保留了 vue-i18n 的 API 并替换了其底层绑定,让您无需改动组件即可平滑迁移,随后逐个文件进行过渡。
适配器不会读取它们。请将这些消息移至语言 JSON 文件中,或移至组件旁边的 .content.ts 文件中(这提供了相同的理念并支持自动生成的类型)。这是唯一无法直接继承的 vue-i18n 功能。
支持。Intlayer 与 Nuxt 涵盖多语言路由、语言检测中间件和站点地图生成。如果您目前使用的是 @nuxtjs/i18n,Nuxt i18n 兼容适配器 提供了理想的迁移路径。
可以。JSON 同步插件 会以 vue-i18n 方言语法({name}、{0}、"car | cars" 管道复数)读取它们,并在 CLI 或 CMS 进行更新时将翻译写回。
原生 ICU 支持正在开发中。@intlayer/vue-i18n 适配器解析 vue-i18n 自身的消息语法,包括管道复数以及命名和列表插值。有关 Intlayer 自身的复数模型,请参阅枚举内容。
相关对比
参考文档:
基准测试报告:
想了解这些库的由来,请阅读 JavaScript i18n 的发展史。
GitHub Star
GitHub star 是项目受欢迎程度、社区信任度和长期相关性的有力指标。虽然不是技术质量的直接衡量,但它反映了有多少开发者认为该项目有用、关注其进展并可能采用它。
提交活跃度
Star 反映受欢迎程度,提交次数反映项目投入的工作量。截至撰写时,Intlayer 约有 7,500 次提交,多于这里比较的大多数库,约为 next-intl 或 next-i18next 的 5 倍。
- intlify/vue-i18n
- aymericzip/intlayer
默认分支上的提交数,来源:GitHub API。
Intlayer 是一个 monorepo,因此该数字包含每个框架包、CLI 和文档。请把提交次数视为活跃度的信号,而不是质量的衡量。
npm 下载量
- vue-i18n
- vue-intlayer
来源:npm 注册表下载 API。
下载量奖励的是最老的方案,而不是最好的方案。一个多年前发布的库,仍会被当年选择它的每个项目、每次 CI 运行以及每个依赖它的包持续安装。这个数字衡量的更多是惯性,而不是新的选择。
AI 助手放大了这种效应。next-intl、i18next 和 vue-i18n 在它们的训练代码中随处可见,因此 AI 会默认推荐它们,而不去比较其他方案。每一次推荐都带来下载,又进一步推动下一次推荐。请以基准测试而不是下载量来比较。
结论
vue-i18n 成熟、灵活,并与 Vue 深度集成。基准测试展示了其运行时优先的设计在 Vite 构建上的代价:24 KB gzip 的运行时,一个无 i18n 时仅 41 KB 的应用每页 134.9 KB,每个页面上 90% 是其他页面的内容,以及每个都达到 196 KB 的组件,因为它们挂在全局消息树上。
Intlayer 把工作移进编译器。按组件的字典和无用内容清除是构建产物,而不是约定。在同一应用上:3.9 KB 运行时、每页 57.1 KB、0% 页面泄漏、组件小 25 倍。如果重写不在考虑之列,@intlayer/vue-i18n 可以在不改动组件的情况下走完大部分路程。
所有原始数据、测试应用和脚本都在 Benchmark Bloom 仓库中。自己跑一遍吧。
更多细节请参阅“为什么选择 Intlayer?”文档。
评论
暂无评论。成为第一个分享您想法的人吧。
