@intlayer/docs 5.8.0-canary.0 → 5.8.1-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blog/ar/intlayer_with_next-i18next.md +2 -2
- package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +96 -219
- package/blog/ar/react-i18next_vs_react-intl_vs_intlayer.md +88 -129
- package/blog/ar/vue-i18n_vs_intlayer.md +268 -0
- package/blog/de/intlayer_with_next-i18next.md +2 -2
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/de/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/de/vue-i18n_vs_intlayer.md +268 -0
- package/blog/en/intlayer_with_next-i18next.md +2 -2
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/en/react-i18next_vs_react-intl_vs_intlayer.md +88 -120
- package/blog/en/vue-i18n_vs_intlayer.md +276 -0
- package/blog/en-GB/intlayer_with_next-i18next.md +2 -2
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +85 -218
- package/blog/en-GB/react-i18next_vs_react-intl_vs_intlayer.md +80 -130
- package/blog/en-GB/vue-i18n_vs_intlayer.md +258 -0
- package/blog/es/intlayer_with_next-i18next.md +2 -2
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/es/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/es/vue-i18n_vs_intlayer.md +268 -0
- package/blog/fr/intlayer_with_next-i18next.md +2 -2
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +91 -214
- package/blog/fr/react-i18next_vs_react-intl_vs_intlayer.md +86 -127
- package/blog/fr/vue-i18n_vs_intlayer.md +269 -0
- package/blog/hi/intlayer_with_next-i18next.md +2 -2
- package/blog/hi/next-i18next_vs_next-intl_vs_intlayer.md +97 -220
- package/blog/hi/react-i18next_vs_react-intl_vs_intlayer.md +89 -130
- package/blog/hi/vue-i18n_vs_intlayer.md +268 -0
- package/blog/it/intlayer_with_next-i18next.md +2 -2
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +91 -214
- package/blog/it/react-i18next_vs_react-intl_vs_intlayer.md +86 -127
- package/blog/it/vue-i18n_vs_intlayer.md +268 -0
- package/blog/ja/intlayer_with_next-i18next.md +2 -2
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/ja/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/ja/vue-i18n_vs_intlayer.md +268 -0
- package/blog/ko/intlayer_with_next-i18next.md +2 -2
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +95 -217
- package/blog/ko/react-i18next_vs_react-intl_vs_intlayer.md +89 -130
- package/blog/ko/vue-i18n_vs_intlayer.md +268 -0
- package/blog/pt/intlayer_with_next-i18next.md +2 -2
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/pt/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/pt/vue-i18n_vs_intlayer.md +268 -0
- package/blog/ru/intlayer_with_next-i18next.md +2 -2
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +94 -217
- package/blog/ru/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/ru/vue-i18n_vs_intlayer.md +268 -0
- package/blog/zh/intlayer_with_next-i18next.md +2 -2
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +93 -216
- package/blog/zh/react-i18next_vs_react-intl_vs_intlayer.md +87 -128
- package/blog/zh/vue-i18n_vs_intlayer.md +269 -0
- package/dist/cjs/generated/blog.entry.cjs +41 -0
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/esm/generated/blog.entry.mjs +41 -0
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/types/generated/blog.entry.d.ts +1 -0
- package/dist/types/generated/blog.entry.d.ts.map +1 -1
- package/docs/ar/formatters.md +417 -31
- package/docs/ar/how_works_intlayer.md +2 -4
- package/docs/ar/interest_of_intlayer.md +7 -10
- package/docs/ar/intlayer_CMS.md +2 -3
- package/docs/ar/intlayer_visual_editor.md +2 -3
- package/docs/ar/intlayer_with_tanstack.md +1 -1
- package/docs/ar/introduction.md +4 -4
- package/docs/de/formatters.md +444 -34
- package/docs/de/introduction.md +2 -2
- package/docs/en/dictionary/enumeration.md +2 -2
- package/docs/en/dictionary/function_fetching.md +2 -2
- package/docs/en/dictionary/get_started.md +2 -2
- package/docs/en/dictionary/translation.md +2 -2
- package/docs/en/formatters.md +383 -15
- package/docs/en/how_works_intlayer.md +2 -4
- package/docs/en/interest_of_intlayer.md +48 -29
- package/docs/en/intlayer_CMS.md +2 -3
- package/docs/en/intlayer_visual_editor.md +2 -3
- package/docs/en/intlayer_with_create_react_app.md +2 -2
- package/docs/en/intlayer_with_express.md +2 -2
- package/docs/en/intlayer_with_tanstack.md +1 -1
- package/docs/en/introduction.md +4 -4
- package/docs/en/packages/express-intlayer/index.md +2 -2
- package/docs/en/packages/intlayer/getConfiguration.md +2 -3
- package/docs/en/packages/intlayer/getEnumeration.md +2 -7
- package/docs/en/packages/intlayer/getHTMLTextDir.md +2 -4
- package/docs/en/packages/intlayer/getLocaleLang.md +2 -4
- package/docs/en/packages/intlayer/getLocaleName.md +2 -3
- package/docs/en/packages/intlayer/getLocalizedUrl.md +2 -8
- package/docs/en/packages/intlayer/getMultilingualUrls.md +2 -7
- package/docs/en/packages/intlayer/getPathWithoutLocale.md +2 -3
- package/docs/en/packages/intlayer/getTranslation.md +2 -4
- package/docs/en/packages/intlayer/index.md +2 -2
- package/docs/en/packages/next-intlayer/index.md +2 -2
- package/docs/en/packages/next-intlayer/t.md +2 -2
- package/docs/en/packages/next-intlayer/useDictionary.md +2 -2
- package/docs/en/packages/next-intlayer/useIntlayer.md +2 -2
- package/docs/en/packages/next-intlayer/useLocale.md +2 -2
- package/docs/en/packages/react-intlayer/index.md +2 -2
- package/docs/en/packages/react-intlayer/t.md +2 -2
- package/docs/en/packages/react-intlayer/useI18n.md +2 -2
- package/docs/en/packages/react-intlayer/useIntlayer.md +2 -2
- package/docs/en/packages/react-intlayer/useLocale.md +2 -2
- package/docs/en/packages/react-scripts-intlayer/index.md +2 -2
- package/docs/en/packages/solid-intlayer/index.md +2 -2
- package/docs/en/packages/vite-intlayer/index.md +2 -2
- package/docs/en-GB/formatters.md +402 -16
- package/docs/en-GB/how_works_intlayer.md +2 -4
- package/docs/en-GB/interest_of_intlayer.md +7 -10
- package/docs/en-GB/intlayer_with_tanstack.md +1 -1
- package/docs/en-GB/introduction.md +2 -2
- package/docs/es/formatters.md +438 -28
- package/docs/es/how_works_intlayer.md +2 -4
- package/docs/es/interest_of_intlayer.md +7 -10
- package/docs/es/intlayer_with_tanstack.md +1 -1
- package/docs/es/introduction.md +2 -2
- package/docs/fr/formatters.md +438 -28
- package/docs/fr/how_works_intlayer.md +2 -4
- package/docs/fr/interest_of_intlayer.md +7 -10
- package/docs/fr/intlayer_with_tanstack.md +1 -1
- package/docs/fr/introduction.md +2 -2
- package/docs/hi/formatters.md +430 -39
- package/docs/hi/how_works_intlayer.md +2 -4
- package/docs/hi/interest_of_intlayer.md +7 -10
- package/docs/hi/intlayer_with_tanstack.md +1 -1
- package/docs/hi/introduction.md +2 -2
- package/docs/it/formatters.md +438 -30
- package/docs/it/how_works_intlayer.md +2 -4
- package/docs/it/interest_of_intlayer.md +7 -10
- package/docs/it/intlayer_with_tanstack.md +1 -1
- package/docs/it/introduction.md +2 -2
- package/docs/ja/formatters.md +435 -47
- package/docs/ja/how_works_intlayer.md +2 -4
- package/docs/ja/interest_of_intlayer.md +7 -10
- package/docs/ja/intlayer_with_tanstack.md +1 -1
- package/docs/ja/introduction.md +2 -2
- package/docs/ko/formatters.md +432 -41
- package/docs/ko/how_works_intlayer.md +2 -4
- package/docs/ko/interest_of_intlayer.md +7 -10
- package/docs/ko/intlayer_with_tanstack.md +1 -1
- package/docs/ko/introduction.md +2 -2
- package/docs/pt/formatters.md +416 -30
- package/docs/pt/how_works_intlayer.md +2 -4
- package/docs/pt/intlayer_with_tanstack.md +1 -1
- package/docs/pt/introduction.md +2 -2
- package/docs/ru/autoFill.md +2 -2
- package/docs/ru/configuration.md +1 -40
- package/docs/ru/formatters.md +438 -28
- package/docs/ru/how_works_intlayer.md +5 -7
- package/docs/ru/index.md +1 -1
- package/docs/ru/interest_of_intlayer.md +8 -11
- package/docs/ru/intlayer_CMS.md +7 -8
- package/docs/ru/intlayer_cli.md +4 -7
- package/docs/ru/intlayer_visual_editor.md +5 -6
- package/docs/ru/intlayer_with_angular.md +1 -1
- package/docs/ru/intlayer_with_create_react_app.md +5 -5
- package/docs/ru/intlayer_with_lynx+react.md +1 -1
- package/docs/ru/intlayer_with_nextjs_15.md +3 -3
- package/docs/ru/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/ru/intlayer_with_nuxt.md +1 -1
- package/docs/ru/intlayer_with_react_native+expo.md +2 -2
- package/docs/ru/intlayer_with_tanstack.md +3 -3
- package/docs/ru/intlayer_with_vite+preact.md +3 -3
- package/docs/ru/intlayer_with_vite+react.md +3 -3
- package/docs/ru/intlayer_with_vite+solid.md +1 -1
- package/docs/ru/intlayer_with_vite+svelte.md +1 -1
- package/docs/ru/intlayer_with_vite+vue.md +2 -2
- package/docs/ru/introduction.md +5 -5
- package/docs/ru/locale_mapper.md +1 -1
- package/docs/ru/packages/@intlayer/api/index.md +2 -2
- package/docs/ru/packages/@intlayer/chokidar/index.md +1 -1
- package/docs/ru/packages/@intlayer/cli/index.md +2 -2
- package/docs/ru/packages/@intlayer/config/index.md +2 -2
- package/docs/ru/packages/@intlayer/core/index.md +2 -2
- package/docs/ru/packages/@intlayer/design-system/index.md +2 -2
- package/docs/ru/packages/@intlayer/dictionary-entry/index.md +2 -2
- package/docs/ru/packages/@intlayer/editor/index.md +1 -1
- package/docs/ru/packages/@intlayer/editor-react/index.md +1 -1
- package/docs/ru/packages/@intlayer/webpack/index.md +1 -1
- package/docs/ru/packages/angular-intlayer/index.md +1 -1
- package/docs/ru/packages/express-intlayer/index.md +3 -3
- package/docs/ru/packages/express-intlayer/t.md +1 -1
- package/docs/ru/packages/intlayer/getEnumeration.md +3 -8
- package/docs/ru/packages/intlayer/getTranslation.md +3 -5
- package/docs/ru/packages/intlayer/getTranslationContent.md +1 -3
- package/docs/ru/packages/intlayer/index.md +3 -3
- package/docs/ru/packages/intlayer-cli/index.md +1 -1
- package/docs/ru/packages/intlayer-editor/index.md +2 -2
- package/docs/ru/packages/lynx-intlayer/index.md +1 -1
- package/docs/ru/packages/next-intlayer/index.md +4 -4
- package/docs/ru/packages/next-intlayer/t.md +4 -4
- package/docs/ru/packages/next-intlayer/useLocale.md +3 -3
- package/docs/ru/packages/nuxt-intlayer/index.md +1 -1
- package/docs/ru/packages/preact-intlayer/index.md +1 -1
- package/docs/ru/packages/react-intlayer/index.md +4 -4
- package/docs/ru/packages/react-intlayer/t.md +4 -4
- package/docs/ru/packages/react-native-intlayer/index.md +1 -1
- package/docs/ru/packages/react-scripts-intlayer/index.md +3 -3
- package/docs/ru/packages/solid-intlayer/index.md +3 -3
- package/docs/ru/packages/svelte-intlayer/index.md +1 -1
- package/docs/ru/packages/vite-intlayer/index.md +3 -3
- package/docs/ru/packages/vue-intlayer/index.md +1 -1
- package/docs/ru/per_locale_file.md +1 -1
- package/docs/ru/roadmap.md +3 -5
- package/docs/ru/vs_code_extension.md +1 -1
- package/docs/zh/formatters.md +446 -38
- package/docs/zh/how_works_intlayer.md +2 -4
- package/docs/zh/interest_of_intlayer.md +7 -10
- package/docs/zh/intlayer_with_tanstack.md +1 -1
- package/docs/zh/introduction.md +2 -2
- package/frequent_questions/ar/domain_routing.md +1 -1
- package/frequent_questions/en/domain_routing.md +1 -1
- package/frequent_questions/en-GB/domain_routing.md +1 -1
- package/frequent_questions/es/domain_routing.md +1 -1
- package/frequent_questions/fr/domain_routing.md +1 -1
- package/frequent_questions/hi/domain_routing.md +1 -1
- package/frequent_questions/it/domain_routing.md +1 -1
- package/frequent_questions/ko/domain_routing.md +1 -1
- package/frequent_questions/pt/domain_routing.md +1 -1
- package/frequent_questions/ru/domain_routing.md +1 -1
- package/frequent_questions/ru/get_locale_cookie.md +4 -4
- package/frequent_questions/ru/static_rendering.md +1 -2
- package/frequent_questions/zh/domain_routing.md +1 -1
- package/package.json +9 -11
- package/src/generated/blog.entry.ts +42 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
createdAt:
|
|
3
|
-
updatedAt: 2025-
|
|
2
|
+
createdAt: 2025-08-23
|
|
3
|
+
updatedAt: 2025-08-23
|
|
4
4
|
title: next-i18next vs next-intl vs Intlayer
|
|
5
|
-
description: 比较
|
|
5
|
+
description: 比较 next-i18next、next-intl 和 Intlayer 在 Next.js 应用国际化(i18n)中的表现
|
|
6
6
|
keywords:
|
|
7
7
|
- next-intl
|
|
8
8
|
- next-i18next
|
|
9
9
|
- Intlayer
|
|
10
10
|
- 国际化
|
|
11
|
-
-
|
|
11
|
+
- 博客
|
|
12
12
|
- Next.js
|
|
13
13
|
- JavaScript
|
|
14
14
|
- React
|
|
@@ -17,269 +17,146 @@ slugs:
|
|
|
17
17
|
- next-i18next-vs-next-intl-vs-intlayer
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
# next-i18next VS next-intl VS
|
|
20
|
+
# next-i18next VS next-intl VS intlayer | Next.js 国际化(i18n)
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
本指南比较了三种广泛使用的 **Next.js** 国际化方案:**next-intl**、**next-i18next** 和 **Intlayer**。
|
|
23
|
+
我们重点关注 **Next.js 13+ App Router**(配合 **React 服务器组件**),并评估:
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
1. **架构与内容组织**
|
|
26
|
+
2. **TypeScript 与安全性**
|
|
27
|
+
3. **缺失翻译处理**
|
|
28
|
+
4. **路由与中间件**
|
|
29
|
+
5. **性能与加载行为**
|
|
30
|
+
6. **开发者体验(DX)、工具链与维护**
|
|
31
|
+
7. **SEO 与大规模项目的可扩展性**
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
2. **TypeScript 支持**
|
|
28
|
-
3. **缺失翻译的管理**
|
|
29
|
-
4. **服务器组件支持**
|
|
30
|
-
5. **增强的路由和中间件** 适用于 Next.js
|
|
31
|
-
6. **设置的简单性**
|
|
32
|
-
|
|
33
|
-
该指南还提供了对 **Intlayer** 的 **深入了解**,展示了它为什么可以成为一个强大的选择, , 特别是对于 Next.js 13+,包括 **App Router** 和 **服务器组件**。
|
|
33
|
+
> **简而言之**:这三者都能实现 Next.js 应用的本地化。如果你需要**组件范围的内容管理**、**严格的 TypeScript 类型**、**构建时缺失键检查**、**支持 Tree-shaking 的词典**,以及**一流的 App Router 和 SEO 辅助工具**,那么 **Intlayer** 是最完整、最现代的选择。
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
### 1. next-intl
|
|
37
|
+
## 高层定位
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
- **next-intl** - 轻量且直观的消息格式化,具备扎实的 Next.js 支持。通常采用集中式目录;开发体验简单,但安全性和大规模维护主要依赖于你自己。
|
|
40
|
+
- **next-i18next** - 以 Next.js 形式呈现的 i18next。生态系统成熟,通过插件(例如 ICU)提供丰富功能,但配置可能冗长,且随着项目增长,目录往往趋于集中化。
|
|
41
|
+
- **Intlayer** - 面向组件的 Next.js 内容模型,**严格的 TypeScript 类型**,**构建时检查**,**摇树优化**,**内置中间件和 SEO 辅助工具**,可选的 **可视化编辑器/CMS**,以及 **AI 辅助翻译**。
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
- **TypeScript 支持**:基础的 TypeScript 集成。存在一些类型定义,但并不以从翻译文件自动生成 TypeScript 定义为主要方向。
|
|
45
|
-
- **缺失翻译**:基本的回退机制。默认情况下,回退到一个键或默认语言字符串。没有强大的开箱即用的工具来进行高级缺失翻译检查。
|
|
46
|
-
- **服务器组件支持**:通常与 Next.js 13+ 一起工作,但对于深层服务器端使用(例如,复杂动态路由的服务器组件),模式不够专用。
|
|
47
|
-
- **路由和中间件**:中间件支持是可能的,但有限。通常依赖于 Next.js 的 `Middleware` 进行语言检测,或手动配置以重写语言路径。
|
|
48
|
-
- **设置简单性**:非常简单。需要最少的样板代码。
|
|
43
|
+
---
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
## 并列功能对比(聚焦 Next.js)
|
|
46
|
+
|
|
47
|
+
| 功能 | `next-intlayer`(Intlayer) | `next-intl` | `next-i18next` |
|
|
48
|
+
| -------------------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
|
|
49
|
+
| **组件附近的翻译** | ✅ 是,内容与每个组件共置 | ❌ 否 | ❌ 否 |
|
|
50
|
+
| **TypeScript 集成** | ✅ 高级,自动生成严格类型 | ✅ 良好 | ⚠️ 基础 |
|
|
51
|
+
| **缺失翻译检测** | ✅ TypeScript 错误高亮和构建时错误/警告 | ⚠️ 运行时回退 | ⚠️ 运行时回退 |
|
|
52
|
+
| **丰富内容(JSX/Markdown/组件)** | ✅ 直接支持 | ❌ 不支持丰富节点 | ⚠️ 有限支持 |
|
|
53
|
+
| **AI 驱动的翻译** | ✅ 是,支持多个 AI 提供商。可使用您自己的 API 密钥。考虑您的应用程序和内容范围的上下文 | ❌ 否 | ❌ 否 |
|
|
54
|
+
| **可视化编辑器** | ✅ 是,本地可视化编辑器 + 可选 CMS;可外部化代码库内容;可嵌入 | ❌ 否 / 可通过外部本地化平台获得 | ❌ 否 / 可通过外部本地化平台获得 |
|
|
55
|
+
| **本地化路由** | ✅ 是,开箱即用支持本地化路径(兼容 Next.js 和 Vite) | ✅ 内置,App Router 支持 `[locale]` 路由段 | ✅ 内置 |
|
|
56
|
+
| **动态路由生成** | ✅ 是 | ✅ 是 | ✅ 是 |
|
|
57
|
+
| **复数形式** | ✅ 基于枚举的模式 | ✅ 良好 | ✅ 良好 |
|
|
58
|
+
| **格式化(日期、数字、货币)** | ✅ 优化的格式化器(底层使用 Intl) | ✅ 良好(Intl 辅助工具) | ✅ 良好(Intl 辅助工具) |
|
|
59
|
+
| **内容格式** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml 进行中) | ✅ .json, .js, .ts | ⚠️ .json |
|
|
60
|
+
| **ICU 支持** | ⚠️ 进行中 | ✅ 是 | ⚠️ 通过插件(`i18next-icu`) |
|
|
61
|
+
| **SEO 辅助工具(hreflang,网站地图)** | ✅ 内置工具:网站地图、robots.txt、元数据辅助工具 | ✅ 良好 | ✅ 良好 |
|
|
62
|
+
| **生态系统 / 社区** | ⚠️ 规模较小但增长迅速且活跃 | ✅ 中等规模,专注于 Next.js | ✅ 中等规模,专注于 Next.js |
|
|
63
|
+
| **服务器端渲染与服务器组件** | ✅ 是,针对 SSR / React 服务器组件进行了优化 | ⚠️ 支持页面级别,但需要在组件树上传递 t 函数给子服务器组件 | ⚠️ 支持页面级别,但需要在组件树上传递 t 函数给子服务器组件 |
|
|
64
|
+
| **Tree-shaking(仅加载使用的内容)** | ✅ 是,通过 Babel/SWC 插件在构建时按组件进行 | ⚠️ 部分支持 | ⚠️ 部分支持 |
|
|
65
|
+
| **懒加载** | ✅ 是,按语言环境 / 按字典 | ✅ 是(按路由/按语言环境),需要命名空间管理 | ✅ 是(按路由/按语言环境),需要命名空间管理 |
|
|
66
|
+
| **清除未使用内容** | ✅ 是,按字典在构建时 | ❌ 否,可以通过命名空间管理手动处理 | ❌ 否,可以通过命名空间管理手动处理 |
|
|
67
|
+
| **大型项目管理** | ✅ 鼓励模块化,适合设计系统 | ✅ 通过设置实现模块化 | ✅ 通过设置实现模块化 |
|
|
51
68
|
|
|
52
69
|
---
|
|
53
70
|
|
|
54
|
-
|
|
71
|
+
## 深度比较
|
|
55
72
|
|
|
56
|
-
|
|
73
|
+
### 1) 架构与可扩展性
|
|
57
74
|
|
|
58
|
-
-
|
|
59
|
-
- **
|
|
60
|
-
- **缺失翻译**:i18next 提供插值/回退机制。然而,缺失翻译检测通常需要额外设置或第三方插件。
|
|
61
|
-
- **服务器组件支持**:已记录基本用法与 Next.js 13 兼容,但高级用法(例如,深度集成服务器组件、动态路由生成)可能比较麻烦。
|
|
62
|
-
- **路由和中间件**:在语言子路径的重写中严重依赖于 Next.js 的 `Middleware`。对于更复杂的设置,你可能需要深入了解高级 i18next 配置。
|
|
63
|
-
- **设置简单性**:对于习惯 i18next 的人来说是熟悉的方式。然而,在需要高级 i18n 特性时(命名空间、多种回退语言等)可能会增加更多样板代码。
|
|
75
|
+
- **next-intl / next-i18next**:默认每个语言环境使用**集中式目录**(i18next 中还有**命名空间**)。初期运行良好,但随着耦合增加和键值频繁变动,往往会成为一个庞大的共享区域。
|
|
76
|
+
- **Intlayer**:鼓励将**每个组件**(或每个功能)的字典与其对应的代码**共置**。这降低了认知负担,简化了 UI 组件的复制/迁移,并减少了跨团队的冲突。未使用的内容也更容易被发现和清理。
|
|
64
77
|
|
|
65
|
-
|
|
78
|
+
**重要原因:** 在大型代码库或设计系统设置中,**模块化内容**比单一目录更具扩展性。
|
|
66
79
|
|
|
67
80
|
---
|
|
68
81
|
|
|
69
|
-
###
|
|
70
|
-
|
|
71
|
-
**主要焦点**:一个现代的开源 i18n 库,专门为 Next.js **App Router**(12, 13, 14 和 15)量身定制,内置支持 **服务器组件** 和 **Turbopack**。
|
|
82
|
+
### 2) TypeScript 与安全性
|
|
72
83
|
|
|
73
|
-
|
|
84
|
+
- **next-intl**:提供了扎实的 TypeScript 支持,但**默认情况下键并非严格类型化**;你需要手动维护安全模式。
|
|
85
|
+
- **next-i18next**:为钩子提供基础类型定义;**严格的键类型化需要额外的工具/配置**。
|
|
86
|
+
- **Intlayer**:**从您的内容生成严格类型**。**IDE 自动补全**和**编译时错误**可以在部署前捕获拼写错误和缺失的键。
|
|
74
87
|
|
|
75
|
-
|
|
88
|
+
**重要原因:** 强类型将失败提前到**左侧**(CI/构建阶段),而不是在**右侧**(运行时)出现。
|
|
76
89
|
|
|
77
|
-
|
|
78
|
-
- 这使得你的代码更加 **模块化和可维护**,特别是在大型代码库中。
|
|
79
|
-
|
|
80
|
-
2. **TypeScript 支持**
|
|
81
|
-
|
|
82
|
-
- **自动生成的类型定义**:一旦你定义了内容,Intlayer 将生成可以支持自动完成并捕捉翻译错误的类型。
|
|
83
|
-
- 最小化运行时错误,比如缺失键,并直接在你的 IDE 中提供高级 **自动完成**。
|
|
84
|
-
|
|
85
|
-
3. **缺失翻译的管理**
|
|
90
|
+
---
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
- 这确保你永远不会在多语言之间意外发布缺失文本。
|
|
92
|
+
### 3)缺失翻译处理
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
- **next-intl / next-i18next**:依赖**运行时回退**(例如,显示键名或默认语言)。构建不会失败。
|
|
95
|
+
- **Intlayer**:通过**构建时检测**,对缺失的语言或键发出**警告/错误**。
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
- 提供专门的提供者(`IntlayerServerProvider`、`IntlayerClientProvider`)以 **隔离服务器上下文**(处理 Next.js 13+ 时至关重要)。
|
|
97
|
+
**重要原因:** 在构建时捕获缺口可以防止生产环境出现“神秘字符串”,并符合严格的发布门控。
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
---
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
- 动态处理本地化路径(例如,`/en-US/about` 与 `/fr/about`),配置最小化。
|
|
99
|
-
- 提供助手方法如 `getMultilingualUrls` 用于生成替代语言链接(非常适合 **SEO**)。
|
|
101
|
+
### 4)路由、中间件和 URL 策略
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- 一个包装插件 `withIntlayer(nextConfig)` 可以 **注入** 所有环境变量和内容监视器。
|
|
104
|
-
- **没有大型回退配置**, , 该系统旨在“正常工作”,减少摩擦。
|
|
103
|
+
- 三者均支持在 App Router 上使用 **Next.js 本地化路由**。
|
|
104
|
+
- **Intlayer** 进一步提供了 **i18n 中间件**(通过请求头/Cookie 进行语言环境检测)和 **辅助工具**,用于生成本地化 URL 以及 `<link rel="alternate" hreflang="…">` 标签。
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
**重要原因:** 减少自定义粘合层;实现跨语言环境的 **一致用户体验** 和 **干净的 SEO**。
|
|
107
107
|
|
|
108
108
|
---
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
| **特性** | **next-intl** | **next-i18next** | **Intlayer** |
|
|
113
|
-
| ----------------------- | ------------------------- | ------------------------------ | ------------------------------- |
|
|
114
|
-
| **将翻译靠近组件** | 部分 - 通常一个语言文件夹 | 非默认 - 通常 `public/locales` | **是 - 推荐且简单** |
|
|
115
|
-
| **TypeScript 自动生成** | 基本 TS 定义 | 基本 TS 支持 | **是 - 高级开箱即用** |
|
|
116
|
-
| **缺失翻译检测** | 主要是回退字符串 | 主要是回退字符串 | **是 - 构建时检查** |
|
|
117
|
-
| **服务器组件支持** | 有效但不专用 | 支持但可能冗长 | **完全支持专用提供者** |
|
|
118
|
-
| **路由和中间件** | 手动集成与 Next 中间件 | 通过重写配置提供 | **专用 i18n 中间件 + 高级钩子** |
|
|
119
|
-
| **设置复杂性** | 简单,最小配置 | 传统,对于高级用法可能冗长 | **一个配置文件 & 插件** |
|
|
120
|
-
|
|
121
|
-
---
|
|
110
|
+
### 5) 服务器组件(RSC)对齐
|
|
122
111
|
|
|
123
|
-
|
|
112
|
+
- **所有方案**均支持 Next.js 13+。
|
|
113
|
+
- **Intlayer** 通过一致的 API 和专为 RSC 设计的提供者,平滑处理 **服务器/客户端边界**,避免在组件树中传递格式化器或 t 函数。
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
**重要原因:** 更清晰的思维模型,减少混合树中的边缘情况。
|
|
126
116
|
|
|
127
|
-
|
|
117
|
+
---
|
|
128
118
|
|
|
129
|
-
|
|
119
|
+
### 6) 性能与加载行为
|
|
130
120
|
|
|
131
|
-
|
|
121
|
+
- **next-intl / next-i18next**:通过**命名空间**和**路由级拆分**实现部分控制;如果管理不严,存在打包未使用字符串的风险。
|
|
122
|
+
- **Intlayer**:在构建时进行**摇树优化**,并按字典/语言环境**懒加载**。未使用的内容不会被打包。
|
|
132
123
|
|
|
133
|
-
|
|
124
|
+
**重要原因:** 包体积更小,启动更快,尤其适用于多语言站点。
|
|
134
125
|
|
|
135
|
-
|
|
126
|
+
---
|
|
136
127
|
|
|
137
|
-
|
|
128
|
+
### 7) 开发体验(DX)、工具链与维护
|
|
138
129
|
|
|
139
|
-
|
|
130
|
+
- **next-intl / next-i18next**:通常需要接入外部平台来处理翻译和编辑工作流。
|
|
131
|
+
- **Intlayer**:内置**免费可视化编辑器**和**可选CMS**(支持Git友好或外部化)。此外,还提供**VSCode扩展**用于内容创作,并支持使用您自己的提供商密钥进行**AI辅助翻译**。
|
|
140
132
|
|
|
141
|
-
|
|
142
|
-
- 标准的 `intlayerMiddleware` 不需要深入自定义重写。
|
|
133
|
+
**重要原因:** 降低运营成本,缩短开发者与内容作者之间的反馈循环。
|
|
143
134
|
|
|
144
|
-
|
|
135
|
+
---
|
|
145
136
|
|
|
146
|
-
|
|
147
|
-
- 清晰、直接的用法,适用于 **服务器** 和 **客户端** 组件,通过 `IntlayerServerProvider` 和 `IntlayerClientProvider` 实现。
|
|
137
|
+
## 何时选择哪种方案?
|
|
148
138
|
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
- 如果你想要一个**极简**的解决方案,且对集中式目录感到舒适,并且你的应用是**小型到中型**,请选择 **next-intl**。
|
|
140
|
+
- 如果你需要 **i18next 的插件生态系统**(例如,通过插件实现高级 ICU 规则),且你的团队已经熟悉 i18next,愿意接受**更多配置**以获得灵活性,请选择 **next-i18next**。
|
|
141
|
+
- 如果你重视**组件范围的内容管理**、**严格的 TypeScript**、**构建时保证**、**摇树优化**,以及**内置的路由/SEO/编辑工具**,尤其是针对 **Next.js App Router** 和**大型模块化代码库**,请选择 **Intlayer**。
|
|
151
142
|
|
|
152
143
|
---
|
|
153
144
|
|
|
154
|
-
##
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
1. **安装和配置**
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
npm install intlayer next-intlayer
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
```ts
|
|
168
|
-
// intlayer.config.ts
|
|
169
|
-
import { Locales, type IntlayerConfig } from "intlayer";
|
|
170
|
-
|
|
171
|
-
const config: IntlayerConfig = {
|
|
172
|
-
internationalization: {
|
|
173
|
-
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
174
|
-
defaultLocale: Locales.ENGLISH,
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
export default config;
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
2. **使用插件**
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
// next.config.mjs
|
|
184
|
-
import { withIntlayer } from "next-intlayer/server";
|
|
185
|
-
|
|
186
|
-
/** @type {import('next').NextConfig} */
|
|
187
|
-
const nextConfig = {};
|
|
188
|
-
|
|
189
|
-
export default withIntlayer(nextConfig);
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
3. **添加中间件**
|
|
193
|
-
|
|
194
|
-
```ts
|
|
195
|
-
// src/middleware.ts
|
|
196
|
-
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";
|
|
197
|
-
|
|
198
|
-
export const config = {
|
|
199
|
-
matcher:
|
|
200
|
-
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
|
|
201
|
-
};
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
4. **创建本地化布局**
|
|
205
|
-
|
|
206
|
-
```tsx
|
|
207
|
-
// src/app/[locale]/layout.tsx
|
|
208
|
-
import { getHTMLTextDir } from "intlayer";
|
|
209
|
-
import { NextLayoutIntlayer } from "next-intlayer";
|
|
210
|
-
|
|
211
|
-
const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
|
|
212
|
-
const { locale } = params;
|
|
213
|
-
return (
|
|
214
|
-
<html lang={locale} dir={getHTMLTextDir(locale)}>
|
|
215
|
-
<body>{children}</body>
|
|
216
|
-
</html>
|
|
217
|
-
);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
export { generateStaticParams } from "next-intlayer";
|
|
221
|
-
export default LocaleLayout;
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
5. **声明并使用内容**
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
// src/app/[locale]/page.content.ts
|
|
228
|
-
import { t } from "intlayer";
|
|
229
|
-
|
|
230
|
-
export default {
|
|
231
|
-
key: "page",
|
|
232
|
-
content: {
|
|
233
|
-
getStarted: {
|
|
234
|
-
main: t({
|
|
235
|
-
en: "Get started by editing",
|
|
236
|
-
fr: "Commencez par éditer",
|
|
237
|
-
es: "Comience por editar",
|
|
238
|
-
}),
|
|
239
|
-
pageLink: "src/app/page.tsx",
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
};
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
```tsx
|
|
246
|
-
// src/app/[locale]/page.tsx
|
|
247
|
-
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
248
|
-
import { IntlayerClientProvider, useIntlayer } from "next-intlayer";
|
|
249
|
-
|
|
250
|
-
const PageContent = () => {
|
|
251
|
-
const { content } = useIntlayer("page");
|
|
252
|
-
return (
|
|
253
|
-
<>
|
|
254
|
-
<p>{content.getStarted.main}</p>
|
|
255
|
-
<code>{content.getStarted.pageLink}</code>
|
|
256
|
-
</>
|
|
257
|
-
);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export default function Page({ params }) {
|
|
261
|
-
return (
|
|
262
|
-
<IntlayerServerProvider locale={params.locale}>
|
|
263
|
-
<IntlayerClientProvider locale={params.locale}>
|
|
264
|
-
<PageContent />
|
|
265
|
-
</IntlayerClientProvider>
|
|
266
|
-
</IntlayerServerProvider>
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
</details>
|
|
145
|
+
## 实用迁移注意事项(next-intl / next-i18next → Intlayer)
|
|
146
|
+
|
|
147
|
+
- **按功能开始**:一次将一个路由或组件迁移到**本地字典**。
|
|
148
|
+
- **并行保留旧目录**:迁移期间搭桥,避免一次性大迁移。
|
|
149
|
+
- **开启严格检查**:让构建时检测及早暴露缺口。
|
|
150
|
+
- **采用中间件和辅助工具**:全站标准化语言检测和SEO标签。
|
|
151
|
+
- **测量包大小**:随着未使用内容被剔除,预期**包体积减少**。
|
|
272
152
|
|
|
273
153
|
---
|
|
274
154
|
|
|
275
155
|
## 结论
|
|
276
156
|
|
|
277
|
-
|
|
157
|
+
这三个库都能成功实现核心本地化。区别在于在**现代 Next.js**中,要实现一个健壮、可扩展的方案,你需要付出多少工作量:
|
|
278
158
|
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
- 提供 **强大的 TypeScript** 自动生成以确保更安全的代码
|
|
282
|
-
- 在构建时处理 **缺失翻译**
|
|
283
|
-
- 提供一个 **简化的单一配置** 方法和增强的路由与中间件
|
|
159
|
+
- 使用 **Intlayer**,**模块化内容**、**严格的 TS**、**构建时安全性**、**摇树优化的包**,以及**一流的 App Router 和 SEO 工具**都是**默认配置**,而非额外负担。
|
|
160
|
+
- 如果您的团队重视多语言、组件驱动应用中的**可维护性和速度**,Intlayer 提供了当今**最完整**的体验。
|
|
284
161
|
|
|
285
|
-
|
|
162
|
+
更多详情请参阅[《为什么选择 Intlayer?》文档](https://intlayer.org/doc/why)。
|