使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本如果您有改善此文档的想法,请随时通过在GitHub上提交拉取请求来贡献。
文档的 GitHub 链接复制文档 Markdown 到剪贴板
Intlayer 比 Paraglide 更轻量吗?
是的。
Paraglide 作为业界公认非常轻量的 i18n 解决方案享有良好声誉,初看之下,基准测试 也印证了这一点:其库体积几乎为零。然而,库体积为零并不代表下发到浏览器的体积为零。这只意味着字节被转移到了该指标不统计的地方。
核心要点
库体积只是被隐藏了,并没有消失:
Paraglide 将其 runtime 和消息函数直接生成到你的代码库中。这部分代码虽然依然传输给浏览器,但被归类为你的代码,而不是库的代码。
无 Provider 并非免费的午餐:
每次调用 m.my_key() 都会自行解析语言,在渲染每个节点时都要读取 cookie 或本地存储,而不是从 context 中一次性读取。
缺乏动态加载机制:
Paraglide 会将一条消息的所有语言全部引入客户端 bundle 中。而 Intlayer 在配置 importMode: 'dynamic' 或 'fetch' 时,仅加载当前正在渲染的单一语言。
Tree Shaking 并非总是生效:
在我们的部分基准测试中,Paraglide 宣传的 Tree Shaking 未能起效。建议务必检查你自己的 bundle 体积。
Paraglide 的体积究竟去了哪里?
在基准测试报告中,“库体积”指标衡量的是在添加任何业务内容之前,空组件中各 i18n 库的 Provider 和 Hook 体积。
在弹窗中打开表格以清晰地查看所有数据
| 库 (TanStack Start) | 库体积 (gz) | 库体积 (min) |
|---|---|---|
@inlang/paraglide-js@2.15.1 | 1.8 KB | 4.5 KB |
react-intlayer@9.5.1 | 5.0 KB | 15.2 KB |
单看这项数据,Paraglide 确实获胜。但 Paraglide 本质上是一个编译器:它读取你的 messages/*.json 文件,并在你的仓库中生成一个 paraglide/ 目录,其中包含 runtime.js(语言检测、cookie 和存储策略、URL 本地化)以及每个消息对应的 JavaScript 函数。
复制代码到剪贴板
由于这些代码位于你的 src/ 目录下且通过相对路径导入,打包工具会将其归算到你的应用程序中,而不是 node_modules 包。因此,库体积一栏几乎显示为零,但相同的业务逻辑依旧被完整打包进了你的页面 bundle 中。
生成代码本身并不是坏事:生成的 runtime 仅包含你配置中真正需要的逻辑(前缀策略、cookie 与 local storage 选择等)。Intlayer 则通过另一种方式达到相同效果,即在构建时注入环境变量,使打包工具自动剔除你配置未启用的代码分支。这两种方案最终都比 i18next 或 next-intl 轻量 3 到 10 倍。
因此,真正公平的衡量标准并不是库体积,而是每个页面实际传输的 JavaScript 体积。
页面实测体积
TanStack Start 应用,10 个页面,在 en 和 fr 路由上进行实测(经 gzip 压缩):
在弹窗中打开表格以清晰地查看所有数据
| 配置 | 页面 JS 平均 (gz) | 超出基准 | 语言泄露率 | 跨页面泄露率 |
|---|---|---|---|---|
| 基准(无 i18n) | 111.0 KB | - | 0.0% | 0.0% |
paraglide(任何策略) | 125.1 KB | +14.1 KB | 49.7% | 0.0% |
intlayer (importMode: static) | 125.8 KB | +14.8 KB | 50.0% | 0.0% |
intlayer (importMode: dynamic) | 118.6 KB | +7.6 KB | 0.0% | 0.0% |
Next.js 16 App Router,同一应用:
在弹窗中打开表格以清晰地查看所有数据
| 配置 | 页面 JS 平均 (gz) | 超出基准 |
|---|---|---|
| 基准(无 i18n) | 141.0 KB | - |
paraglide-next | 155.3 KB | +14.3 KB |
next-intlayer | 141.3 KB | +0.3 KB |
动态 JSON 加载
在运行时懒加载翻译
有作用域的 JSON (命名空间)
每页翻译命名空间
I18n 性能基准测试
这个指标是什么?
国际化库包的总 gzip 压缩大小。它仅包含 tree-shaking 和压缩(minification)后的提供者(provider)和内容检索逻辑。
为什么这很重要?
较小的库大小可减少初始 JavaScript 负载,从而缩短客户端的下载和执行时间。
视图形式
完整数据请参阅 TanStack Start 基准测试报告 与 Next.js 基准测试报告。所有 bundle 均可在 基准测试仓库 中核查。
实测结果呈现出两个明显特征:
- 在
static模式下,Intlayer 传输的内容体积与 Paraglide 基本持平(125.8 KB 对比 125.1 KB)。这符合预期:两者都包含了页面所需消息的所有语言版本。 - 无论使用何种策略,Paraglide 的体积始终保持在 125.1 KB,因为它没有动态加载模式。上表中其每一行都等同于静态引入。
无 Provider:看似美妙却代价不菲的方案
Paraglide 不需要 Provider。你只需导入消息并直接调用:
复制代码到剪贴板
没有 context,没有外层包裹组件,没有 hook。表面上看简单直观。但是语言依然必须由某个地方解析。每个生成的消息函数大致如下所示(简化代码):
复制代码到剪贴板
而 getLocale() 会遍历已配置的各种策略(cookie、本地存储、URL、基础语言)以获取当前语言。这意味着你渲染的每个文本节点(<>{m.my_key()}</>)都会各自执行一次语言解析流程,包括在浏览器中读取 document.cookie。一个包含 200 个翻译字符串的页面,在单次渲染中就会解析 200 次语言,并且在每次重新渲染时周而复始。
基于 Provider 的库仅需读取一次语言,将其保存在 context(或 signal、store)中,所有节点直接读取已存在于内存中的值。Provider 的开销仅有几百字节。省去 Provider 会导致每次渲染都消耗 CPU 周期,这在基准测试中表现得尤为明显:在 TanStack Start 上,Paraglide 的页面加载时间与语言切换延迟均落后于 Intlayer(页面加载时间 22.1 ms 对比 14.6 ms,端到端响应度 4.3 ms 对比 3.2 ms)。
开发者体验(DX)
Paraglide 的事实来源是 JSON,但你从不直接导入这些 JSON 文件,而是导入生成的 .js 文件:
复制代码到剪贴板
复制代码到剪贴板
复制代码到剪贴板
复制代码到剪贴板
复制代码到剪贴板
这种开发循环需要付出相应代价:
- 每次修改 JSON 文件,都必须等待重新生成完成,导入才能被识别或类型才能得到更新。
- 生成的
paraglide/目录要么提交至 Git(这意味着每次涉及文案修改的 PR 都会在生成文件上产生合并冲突),要么将其忽略(这意味着在每次类型检查、测试和 CI 任务之前都必须额外执行一次生成步骤)。 - 每个字符串都被包裹成函数调用。常量在各处变成了
m.key(),即便在原本只需静态值的地方也是如此。
Tree Shaking:请核查你的实际 Bundle
Paraglide 最主要的主打特性是:由于每个消息都是独立的 export,未使用的消息能被 Tree Shaking 剔除。在 Svelte + Vite 的基准测试中,它确实如宣传的那样生效了。
但在其它技术栈中并非如此。在我们针对 Next.js 的测试中,Paraglide 的页面体积比基础应用多出 14 KB,而 next-intlayer 仅增加了 0.3 KB。在 TanStack Start 上的早期测试也表明,来自其他页面的消息同样混入了当前路由的 bundle 中。
Tree Shaking 效果取决于你的打包工具(Turbopack、Rolldown、Rollup)、消息导入语法(import { m } 与 import * as m)以及副作用分析能力。如果你因体积小巧而选择 Paraglide,请务必打开 bundle 可视化工具并在自己的项目中实际验证。
无动态加载机制
这是架构上的硬伤。Paraglide 无法做到一次只加载一种语言:每个消息函数都会静态导入每种语言的实现代码,因此所有语言都会全部打包到你的客户端 bundle 中。
在支持 2 种语言时,有一半的翻译数据传输被浪费了,这与前文测得的 ~50% 语言泄露率完全吻合。当支持 10 种语言时,浪费率高达 90%;当支持 30 种语言时,浪费率高达 97%。
即使改成动态加载也无法根治:由于每个消息是一个独立函数,如果按函数进行懒加载,将会导致成千上万次碎小的网络请求。
Intlayer 允许你全局或按字典自由配置加载模式:
复制代码到剪贴板
在弹窗中打开表格以清晰地查看所有数据
importMode | 传输至客户端的内容 | 对比 Paraglide |
|---|---|---|
static | 页面所用字典的所有语言版本 | 理论体积完全一致 |
dynamic | 仅加载当前语言,按字典进行按需懒加载 | N 个语言时体积轻量 N 倍 |
fetch | 仅加载当前语言,直接通过 Live Sync API 获取 | N 个语言时体积轻量 N 倍 |
借助 构建期转换优化 与 importMode: 'static',Intlayer 在理论上加载的内容与 Paraglide 毫无二致。而启用 'dynamic' 或 'fetch' 后,它仅加载当前语言所需的内容:对于支持 N 种语言的应用,翻译数据的网络传输量将比 Paraglide 小 N 倍。
Paraglide 依然适用的场景
如果你的技术栈是 Svelte 搭配 Vite,且仅需支持两到三种语言,Tree Shaking 可以按预期工作,多语言带来的体积开销也相对可控。
如果你的团队已经深度依赖 inlang 生态(Fink、Sherlock、消息格式插件),Paraglide 能够与其实现原生无缝集成。
在你的应用中实际测验
使用免费的 i18n SEO Scanner 检测线上生产应用的传输体积与语言泄露情况:
安装并初始化 Intlayer:
复制代码到剪贴板
拓展阅读
评论
暂无评论。成为第一个分享您想法的人吧。
