@intlayer/docs 5.8.0-canary.0 → 5.8.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 +89 -220
- package/blog/en/react-i18next_vs_react-intl_vs_intlayer.md +85 -123
- package/blog/en/vue-i18n_vs_intlayer.md +268 -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 +40 -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 +7 -7
- package/src/generated/blog.entry.ts +41 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-01-02
|
|
3
3
|
updatedAt: 2025-06-29
|
|
4
|
-
title: react-
|
|
5
|
-
description: react-i18next
|
|
4
|
+
title: react-i18next vs react-intl vs Intlayer
|
|
5
|
+
description: 将 react-i18next 与 next-intl 和 Intlayer 集成,用于 React 应用的国际化 (i18n)
|
|
6
6
|
keywords:
|
|
7
7
|
- next-intl
|
|
8
8
|
- react-i18next
|
|
9
9
|
- Intlayer
|
|
10
10
|
- 国际化
|
|
11
|
-
-
|
|
11
|
+
- 博客
|
|
12
12
|
- Next.js
|
|
13
13
|
- JavaScript
|
|
14
14
|
- React
|
|
@@ -17,178 +17,137 @@ slugs:
|
|
|
17
17
|
- react-i18next-vs-react-intl-vs-intlayer
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# react-Intl VS react-i18next VS intlayer | React 国际化 (i18n)
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
本指南比较了三种成熟的 **React** 国际化方案:**react-intl**(FormatJS)、**react-i18next**(i18next)和 **Intlayer**。
|
|
23
|
+
我们重点关注 **纯 React** 应用(例如 Vite、CRA、SPA)。如果您使用的是 Next.js,请参阅我们专门的 Next.js 比较。
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## 1. 介绍
|
|
27
|
-
|
|
28
|
-
在 React 应用中实现国际化 (i18n) 有多种方式。这里介绍的三种库有不同的设计理念、功能集和社区支持:
|
|
25
|
+
我们将评估:
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
- 架构与内容组织
|
|
28
|
+
- TypeScript 与安全性
|
|
29
|
+
- 缺失翻译的处理
|
|
30
|
+
- 丰富的内容与格式化能力
|
|
31
|
+
- 性能与加载行为
|
|
32
|
+
- 开发者体验(DX)、工具链与维护
|
|
33
|
+
- SEO/路由(依赖框架)
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
> **简而言之**:这三者都能实现 React 应用的本地化。如果您需要**组件范围的内容**、**严格的 TypeScript 类型**、**构建时缺失键检查**、**支持 Tree-shaking 的字典**,以及内置的编辑工具(可视化编辑器/CMS + 可选的 AI 翻译),那么 **Intlayer** 是模块化 React 代码库中最完整的选择。
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
38
|
-
##
|
|
39
|
-
|
|
40
|
-
### 概述
|
|
41
|
-
|
|
42
|
-
[**React-Intl**](https://formatjs.io/docs/react-intl/) 是 [FormatJS](https://formatjs.io/) 套件的一部分。它提供了一套强大的 **API 和组件** 来处理消息格式化、复数形式、日期/时间和数字格式化。React-Intl 在企业应用中被广泛使用,主要是因为它是标准化消息语法和格式化的生态系统的一部分。
|
|
43
|
-
|
|
44
|
-
### 主要特性
|
|
45
|
-
|
|
46
|
-
- **ICU 消息语法**:提供全面的语法来处理消息插值、复数形式等。
|
|
47
|
-
- **本地化格式化**:内置工具根据地区格式化日期、时间、数字和相对时间。
|
|
48
|
-
- **声明式组件**:提供 `<FormattedMessage>`、`<FormattedNumber>`、`<FormattedDate>` 等,以便在 JSX 中无缝使用。
|
|
49
|
-
- **丰富的生态系统**:与 FormatJS 工具(例如 [babel-plugin-react-intl](https://formatjs.io/docs/tooling/babel-plugin/))良好集成,用于提取、管理和编译消息。
|
|
50
|
-
|
|
51
|
-
### 典型工作流程
|
|
52
|
-
|
|
53
|
-
1. **定义消息目录**(通常是每个地区的 JSON 文件)。
|
|
54
|
-
2. **在 `<IntlProvider locale="zh" messages={messages}>` 中包装您的应用**。
|
|
55
|
-
3. **使用** `<FormattedMessage id="myMessage" defaultMessage="你好,世界" />` 或 `useIntl()` 钩子来访问翻译字符串。
|
|
56
|
-
|
|
57
|
-
### 优点
|
|
58
|
-
|
|
59
|
-
- 成熟且在许多生产环境中使用。
|
|
60
|
-
- 高级消息格式化,包括复数形式、性别、时区等。
|
|
61
|
-
- 对消息提取和编译的强大工具支持。
|
|
62
|
-
|
|
63
|
-
### 缺点
|
|
39
|
+
## 高层定位
|
|
64
40
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
41
|
+
- **react-intl** - 以 ICU 为先,符合标准的格式化(日期/数字/复数),拥有成熟的 API。目录通常是集中管理的;键的安全性和构建时验证主要由你负责。
|
|
42
|
+
- **react-i18next** - 极其流行且灵活;支持命名空间、检测器和许多插件(ICU、后端等)。功能强大,但随着项目规模扩大,配置可能变得复杂。
|
|
43
|
+
- **Intlayer** - 面向组件的 React 内容模型,**严格的 TS 类型**,**构建时检查**,**支持 Tree-shaking**,以及 **可视化编辑器/CMS** 和 **AI 辅助翻译**。兼容 React Router、Vite、CRA 等。
|
|
67
44
|
|
|
68
45
|
---
|
|
69
46
|
|
|
70
|
-
##
|
|
47
|
+
## 功能矩阵(React 重点)
|
|
48
|
+
|
|
49
|
+
| 功能 | `react-intlayer` (Intlayer) | `react-i18next` (i18next) | `react-intl` (FormatJS) |
|
|
50
|
+
| -------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------- |
|
|
51
|
+
| **组件附近的翻译** | ✅ 是,内容与每个组件共置 | ❌ 否 | ❌ 否 |
|
|
52
|
+
| **TypeScript 集成** | ✅ 高级,自动生成严格类型 | ⚠️ 基础;需要额外配置以保证安全 | ✅ 良好,但不够严格 |
|
|
53
|
+
| **缺失翻译检测** | ✅ TypeScript 错误高亮和构建时错误/警告 | ⚠️ 主要是运行时回退字符串 | ⚠️ 回退字符串 |
|
|
54
|
+
| **丰富内容(JSX/Markdown/组件)** | ✅ 直接支持 | ⚠️ 有限 / 仅插值 | ⚠️ ICU 语法,不是真正的 JSX |
|
|
55
|
+
| **AI 驱动的翻译** | ✅ 是,支持多个 AI 提供商。可使用您自己的 API 密钥。考虑到您的应用程序和内容范围的上下文 | ❌ 否 | ❌ 否 |
|
|
56
|
+
| **可视化编辑器** | ✅ 是,本地可视化编辑器 + 可选 CMS;可以外部化代码库内容;可嵌入 | ❌ 否 / 通过外部本地化平台提供 | ❌ 否 / 通过外部本地化平台提供 |
|
|
57
|
+
| **本地化路由** | ✅ 是,开箱即用支持本地化路径(兼容 Next.js 和 Vite) | ⚠️ 无内置支持,需要插件(例如 `next-i18next`)或自定义路由配置 | ❌ 否,仅支持消息格式化,路由需手动管理 |
|
|
58
|
+
| **动态路由生成** | ✅ 是 | ⚠️ 依赖插件/生态系统或手动设置 | ❌ 不提供 |
|
|
59
|
+
| **复数形式处理** | ✅ 基于枚举的模式 | ✅ 可配置(如 i18next-icu 插件) | ✅ (ICU) |
|
|
60
|
+
| **格式化(日期、数字、货币)** | ✅ 优化的格式化器(底层使用 Intl) | ⚠️ 通过插件或自定义 Intl 使用 | ✅ ICU 格式化器 |
|
|
61
|
+
| **内容格式** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml 进行中) | ⚠️ .json | ✅ .json, .js |
|
|
62
|
+
| **ICU 支持** | ⚠️ 进行中 | ⚠️ 通过插件(如 i18next-icu) | ✅ 是 |
|
|
63
|
+
| **SEO 辅助工具(hreflang,网站地图)** | ✅ 内置工具:网站地图、robots.txt、元数据辅助工具 | ⚠️ 社区插件/手动 | ❌ 非核心功能 |
|
|
64
|
+
| **生态系统 / 社区** | ⚠️ 较小但增长迅速且反应灵敏 | ✅ 最大且成熟 | ✅ 大型 |
|
|
65
|
+
| **服务器端渲染与服务器组件** | ✅ 支持,针对 SSR / React 服务器组件进行了优化 | ⚠️ 支持页面级别,但需要在组件树上传递 t 函数给子服务器组件 | ❌ 不支持,需要在组件树上传递 t 函数给子服务器组件 |
|
|
66
|
+
| **Tree-shaking(仅加载使用的内容)** | ✅ 支持,通过 Babel/SWC 插件在构建时按组件进行优化 | ⚠️ 通常加载全部(可通过命名空间/代码拆分进行改进) | ⚠️ 通常加载全部 |
|
|
67
|
+
| **懒加载** | ✅ 是的,按语言环境 / 按词典 | ✅ 是的(例如,按需加载后端/命名空间) | ✅ 是的(拆分语言包) |
|
|
68
|
+
| **清除未使用内容** | ✅ 是的,按词典在构建时 | ❌ 否,仅通过手动命名空间分割 | ❌ 否,所有声明的消息都会被打包 |
|
|
69
|
+
| **大型项目管理** | ✅ 鼓励模块化,适合设计系统 | ⚠️ 需要良好的文件管理 | ⚠️ 中央目录可能变得庞大 |
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
[**React-i18next**](https://react.i18next.com/) 是 [i18next](https://www.i18next.com/) 的 React 扩展,是最流行的 JavaScript i18n 框架之一。它提供了 **广泛的特性** 用于运行时翻译、懒加载和语言检测,使其对于各种用例极其灵活。
|
|
75
|
-
|
|
76
|
-
### 主要特性
|
|
77
|
-
|
|
78
|
-
- **灵活的翻译结构**:不绑定于像 ICU 这样的单一格式。您可以将翻译存储在 JSON 中,使用插值、复数形式等。
|
|
79
|
-
- **动态语言切换**:内置语言检测插件和运行时更新。
|
|
80
|
-
- **嵌套和结构化翻译**:可以轻松地将翻译嵌套在 JSON 中。
|
|
81
|
-
- **广泛的插件生态系统**:用于检测(浏览器、路径、子域等)、资源加载、缓存等。
|
|
82
|
-
|
|
83
|
-
### 典型工作流程
|
|
84
|
-
|
|
85
|
-
1. **安装 `i18next` 和 `react-i18next`。**
|
|
86
|
-
2. **配置 i18n** 加载翻译(JSON)并设置语言检测或回退。
|
|
87
|
-
3. **在 `I18nextProvider` 中包装您的应用**。
|
|
88
|
-
4. **使用 `useTranslation()` 钩子** 或 `<Trans>` 组件来显示翻译。
|
|
71
|
+
---
|
|
89
72
|
|
|
90
|
-
|
|
73
|
+
## 深度比较
|
|
91
74
|
|
|
92
|
-
|
|
93
|
-
- 非常活跃的社区和大量插件生态系统。
|
|
94
|
-
- 轻松 **动态加载** 翻译(例如,从服务器按需加载)。
|
|
75
|
+
### 1) 架构与可扩展性
|
|
95
76
|
|
|
96
|
-
|
|
77
|
+
- **react-intl / react-i18next**:大多数配置保持每种语言的**集中式本地化文件夹**,有时按**命名空间**(i18next)拆分。早期效果良好,但随着应用增长,成为共享的表面区域。
|
|
78
|
+
- **Intlayer**:提倡与其所服务的 UI **共置** 的 **每组件(或每功能)字典**。这保持了所有权的清晰,便于组件的复制/迁移,并减少跨团队的键变动。未使用的内容更容易识别和删除。
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
- 如果您希望严格类型的翻译,可能需要额外的 TypeScript 设置。
|
|
80
|
+
**重要原因:** 模块化内容反映模块化 UI。当翻译与其所属组件共存时,大型 React 代码库会保持更整洁。
|
|
100
81
|
|
|
101
82
|
---
|
|
102
83
|
|
|
103
|
-
|
|
84
|
+
### 2) TypeScript 与安全性
|
|
104
85
|
|
|
105
|
-
|
|
86
|
+
- **react-intl**:类型定义扎实,但**没有自动键类型**;你需要自己强制安全模式。
|
|
87
|
+
- **react-i18next**:为钩子提供强类型;**严格的键类型**通常需要额外配置或生成器。
|
|
88
|
+
- **Intlayer**:**从您的内容自动生成严格类型**。IDE 自动完成和**编译时错误**可以在运行时之前捕获拼写错误和缺失的键。
|
|
106
89
|
|
|
107
|
-
|
|
90
|
+
**重要原因:** 将失败“左移”(到构建/CI阶段)可以减少生产环境问题并加快开发者反馈循环。
|
|
108
91
|
|
|
109
|
-
|
|
92
|
+
---
|
|
110
93
|
|
|
111
|
-
|
|
112
|
-
- **内置路由和中间件**:可选模块用于本地化路由(例如,`/zh/about`、`/fr/about`)和用于检测用户区域的服务器中间件。
|
|
113
|
-
- **自动生成的 TypeScript 类型**:通过自动完成功能和编译时错误检测,确保类型安全。
|
|
114
|
-
- **动态和丰富的翻译**:可以在翻译中包含 JSX/TSX 以应对更复杂的用例(例如,链接、加粗文本、翻译中的图标)。
|
|
94
|
+
### 3) 缺失翻译处理
|
|
115
95
|
|
|
116
|
-
|
|
96
|
+
- **react-intl / react-i18next**:默认使用**运行时回退**(键回显或默认语言)。您可以添加代码检查/插件,但构建时不保证检测。
|
|
97
|
+
- **Intlayer**:通过**构建时检测**,在缺少必需的语言或键时发出警告或错误。
|
|
117
98
|
|
|
118
|
-
|
|
119
|
-
2. **创建 `intlayer.config.ts`** 定义可用的区域和默认区域。
|
|
120
|
-
3. **使用 Intlayer CLI** 或插件来 **转译** 内容声明。
|
|
121
|
-
4. **在 `<IntlayerProvider>` 中包装您的应用** 并使用 `useIntlayer("keyName")` 获取内容。
|
|
99
|
+
**重要原因:** CI 在缺失字符串时失败,防止“神秘的英文”泄漏到非英文界面中。
|
|
122
100
|
|
|
123
|
-
|
|
101
|
+
---
|
|
124
102
|
|
|
125
|
-
|
|
126
|
-
- 可能 **丰富的内容**(例如,将 React 节点传递作为翻译)。
|
|
127
|
-
- **开箱即用的本地化路由**。
|
|
128
|
-
- 与流行的构建工具(CRA、Vite)集成,易于设置。
|
|
103
|
+
### 4) 丰富内容与格式化
|
|
129
104
|
|
|
130
|
-
|
|
105
|
+
- **react-intl**:对复数、选择、日期/数字和消息组合提供出色的 **ICU** 支持。可以使用 JSX,但思维模型仍以消息为中心。
|
|
106
|
+
- **react-i18next**:灵活的插值和用于嵌入元素/组件的 **`<Trans>`** 组件;通过插件支持 ICU。
|
|
107
|
+
- **Intlayer**:内容文件可以包含 **丰富节点**(JSX/Markdown/组件)和 **元数据**。格式化底层使用 Intl;复数模式设计符合人体工学。
|
|
131
108
|
|
|
132
|
-
|
|
133
|
-
- 更加注重“组件级内容声明”的方法, , 可能与典型的 .json 目录有一定差异。
|
|
134
|
-
- 与更成熟的库相比,生态系统和社区较小。
|
|
109
|
+
**重要原因:** 当库能够干净地支持 React 节点时,处理复杂的 UI 文本(链接、加粗部分、内联组件)会更加轻松。
|
|
135
110
|
|
|
136
111
|
---
|
|
137
112
|
|
|
138
|
-
|
|
113
|
+
### 5) 性能与加载行为
|
|
114
|
+
|
|
115
|
+
- **react-intl / react-i18next**:您通常需要手动管理**目录拆分**和**懒加载**(命名空间/动态导入)。这种方式有效但需要严格的规范。
|
|
116
|
+
- **Intlayer**:自动**摇树优化**未使用的字典,并开箱即用地支持**按字典/按语言的懒加载**。
|
|
139
117
|
|
|
140
|
-
|
|
141
|
-
| ------------------- | ----------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
|
|
142
|
-
| **主要用例** | 基于字符串的翻译,日期/数字格式化,ICU 消息语法 | 全功能 i18n,易于动态切换、嵌套、插件生态系统 | 强类型翻译,聚焦于声明式内容、本地化路由和可选的服务器中间件 |
|
|
143
|
-
| **方法** | 使用 `<IntlProvider>` 和 FormatJS 消息组件 | 使用 `I18nextProvider` 和 `useTranslation()` 钩子 | 使用 `<IntlayerProvider>` 和 `useIntlayer()` 钩子以及内容声明 |
|
|
144
|
-
| **本地化格式** | 基于 ICU 的字符串(JSON 或 JavaScript 目录) | JSON 资源文件(或自定义加载程序)。ICU 格式可通过 i18next 插件选择 | `.content.[ts/js/tsx]` 或 JSON 声明;可以包含字符串或 React 组件 |
|
|
145
|
-
| **路由** | 由外部处理(没有内置的本地化路由机制) | 通过 i18next 插件(路径、子域检测等)外部处理 | 内置支持本地化路由(如 `/zh/about`、`/fr/about`),以及可选的服务器中间件(用于 SSR/Vite) |
|
|
146
|
-
| **TypeScript 支持** | 良好(官方包的类型定义) | 良好,但如果您希望严格检查类型翻译,则需要额外的配置 | 优秀(自动生成内容键和翻译的类型定义) |
|
|
147
|
-
| **复数和格式化** | 高级:內置日期/时间/数字格式化、复数/性别支持 | 可配置的复数形式。日期/时间格式化通常通过外部库或 i18next 插件完成 | 可以依赖标准 JavaScript Intl 或将逻辑嵌入内容中。虽然不如 FormatJS 专业,但能处理典型案例。 |
|
|
148
|
-
| **社区和生态系统** | 大,属于 FormatJS 生态系统 | 非常大,活跃,插件众多(检测、缓存、框架等) | 较小但正在成长;开源,现代方法 |
|
|
149
|
-
| **学习曲线** | 中等(学习 ICU 消息语法,FormatJS 规范) | 低到中等(使用比较简单,但高级配置可能会变得冗长) | 中等(内容声明的概念和专业构建步骤) |
|
|
118
|
+
**重要性说明:** 更小的包体积和更少的未使用字符串能提升启动和导航性能。
|
|
150
119
|
|
|
151
120
|
---
|
|
152
121
|
|
|
153
|
-
|
|
122
|
+
### 6) 开发体验(DX)、工具链与维护
|
|
154
123
|
|
|
155
|
-
|
|
124
|
+
- **react-intl / react-i18next**:拥有广泛的社区生态系统;对于编辑工作流,通常采用外部本地化平台。
|
|
125
|
+
- **Intlayer**:提供免费的**可视化编辑器**和**可选的内容管理系统(CMS)**(内容可保存在 Git 中或外部化)。还提供用于内容创作的**VSCode 扩展**,以及使用您自己的提供商密钥进行的**AI 辅助翻译**。
|
|
156
126
|
|
|
157
|
-
|
|
158
|
-
- 您更倾向于使用“**基于标准**”的方法进行翻译。
|
|
159
|
-
- 您不需要本地化路由或强类型的翻译键。
|
|
127
|
+
**重要原因:** 内置工具缩短了开发者与内容作者之间的反馈周期--减少了胶水代码,降低了对第三方依赖的需求。
|
|
160
128
|
|
|
161
|
-
|
|
129
|
+
---
|
|
162
130
|
|
|
163
|
-
|
|
164
|
-
- 您希望使用 **基于插件** 的语言检测(例如,从 URL、Cookies、本地存储等)或高级缓存。
|
|
165
|
-
- 您需要最大的生态系统,具有针对各种框架(如 Next.js、React Native 等)的许多现有集成。
|
|
131
|
+
## 何时选择哪种方案?
|
|
166
132
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- 您需要 **内置本地化路由** 或想要轻松将其纳入您的 SSR 或 Vite 设置。
|
|
171
|
-
- 您希望采用现代方法或简单地希望拥有一个覆盖 **内容管理**(i18n)和 **路由** 的类型安全的库。
|
|
133
|
+
- 如果您需要**以 ICU 为优先**的消息格式化,且希望使用简洁、符合标准的 API,并且您的团队能够手动维护目录和安全检查,**请选择 react-intl**。
|
|
134
|
+
- 如果您需要**i18next 生态系统的广泛支持**(检测器、后端、ICU 插件、集成等),并且愿意接受更多配置以获得更高灵活性,**请选择 react-i18next**。
|
|
135
|
+
- **选择 Intlayer** 如果你重视 **组件范围的内容管理**、**严格的 TypeScript 类型检查**、**构建时保证**、**摇树优化**,以及 **开箱即用** 的编辑工具 -- 尤其适用于 **大型、模块化** 的 React 应用。
|
|
172
136
|
|
|
173
137
|
---
|
|
174
138
|
|
|
175
|
-
##
|
|
176
|
-
|
|
177
|
-
每个库都为国际化 React 应用程序提供了强大的解决方案:
|
|
178
|
-
|
|
179
|
-
- **React-Intl** 在消息格式化方面表现优异,是专注于 ICU 消息语法的企业解决方案的热门选择。
|
|
180
|
-
- **React-i18next** 为高级或动态 i18n 需求提供了高度灵活和插件驱动的环境。
|
|
181
|
-
- **Intlayer** 提供了 **现代、强类型** 的方法,结合了内容声明、高级的本地化路由和基于插件的(CRA,Vite)集成。
|
|
139
|
+
## 实用迁移建议(react-intl / react-i18next → Intlayer)
|
|
182
140
|
|
|
183
|
-
|
|
141
|
+
- **渐进迁移**:从一个功能或路由开始;在过渡期间并行保留旧版目录。
|
|
142
|
+
- **采用每组件字典**:将内容与组件共置,减少耦合。
|
|
143
|
+
- **启用严格检查**:让构建时错误提前暴露缺失的键/语言,便于 CI 早期发现。
|
|
144
|
+
- **测量包体积**:预期未使用的字符串被剔除后包体积会减小。
|
|
184
145
|
|
|
185
146
|
---
|
|
186
147
|
|
|
187
|
-
|
|
148
|
+
## 结论
|
|
188
149
|
|
|
189
|
-
|
|
190
|
-
- [React-i18next 文档](https://react.i18next.com/)
|
|
191
|
-
- [Intlayer + CRA 开始指南](#)(来自您的文档)
|
|
192
|
-
- [Intlayer + Vite 和 React 开始指南](#)(来自您的文档)
|
|
150
|
+
所有三个库都能有效地实现 React 的本地化。区别在于你需要构建多少**基础设施**,才能达到一个**安全、可扩展**的环境:
|
|
193
151
|
|
|
194
|
-
|
|
152
|
+
- 使用 **Intlayer**,**模块化内容**、**严格的 TS 类型检查**、**构建时安全性**、**摇树优化的包**以及**编辑工具**都是默认配置,而非额外负担。
|
|
153
|
+
- 如果你的团队重视多语言、组件驱动的 React 应用中的**可维护性和速度**,Intlayer 提供了目前**最完整**的开发者和内容工作流。
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2024-08-11
|
|
3
|
+
updatedAt: 2025-08-23
|
|
4
|
+
title: vue-i18n 与 Intlayer 对比
|
|
5
|
+
description: 比较 vue-i18n 与 Intlayer 在 Vue/Nuxt 应用中的国际化 (i18n) 方案
|
|
6
|
+
keywords:
|
|
7
|
+
- vue-i18n
|
|
8
|
+
- Intlayer
|
|
9
|
+
- 国际化
|
|
10
|
+
- i18n
|
|
11
|
+
- 博客
|
|
12
|
+
- Vue
|
|
13
|
+
- Nuxt
|
|
14
|
+
- JavaScript
|
|
15
|
+
slugs:
|
|
16
|
+
- blog
|
|
17
|
+
- vue-i18n-vs-intlayer
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# vue-i18n VS Intlayer | Vue 国际化 (i18n)
|
|
21
|
+
|
|
22
|
+
本指南比较了两个流行的 **Vue 3**(及 **Nuxt**)国际化选项:**vue-i18n** 和 **Intlayer**。
|
|
23
|
+
我们聚焦于现代 Vue 工具链(Vite,Composition API),并评估:
|
|
24
|
+
|
|
25
|
+
1. **架构与内容组织**
|
|
26
|
+
2. **TypeScript 与安全性**
|
|
27
|
+
3. **缺失翻译处理**
|
|
28
|
+
4. **路由与 URL 策略**
|
|
29
|
+
5. **性能与加载行为**
|
|
30
|
+
6. **开发者体验 (DX)、工具链与维护**
|
|
31
|
+
7. **SEO 与大型项目的可扩展性**
|
|
32
|
+
|
|
33
|
+
> **简而言之**:两者都能实现 Vue 应用的本地化。如果你需要**组件范围的内容**、**严格的 TypeScript 类型**、**构建时缺失键检查**、**支持 Tree-shaking 的字典**,以及**内置的路由/SEO 辅助工具**,再加上**可视化编辑器和 AI 翻译**,那么 **Intlayer** 是更完整、更现代的选择。
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 高层定位
|
|
38
|
+
|
|
39
|
+
- **vue-i18n** - Vue 的事实标准国际化库。支持灵活的消息格式(ICU 风格)、单文件组件(SFC)中的 `<i18n>` 块用于本地消息,并拥有庞大的生态系统。安全性和大规模维护主要依赖开发者自身。
|
|
40
|
+
- **Intlayer** - 面向组件的内容模型,适用于 Vue/Vite/Nuxt,具备**严格的 TypeScript 类型检查**、**构建时校验**、**摇树优化**、**路由和 SEO 辅助工具**,可选的**可视化编辑器/CMS**,以及**AI 辅助翻译**。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 并列功能对比(Vue 重点)
|
|
45
|
+
|
|
46
|
+
| 功能 | **Intlayer** | **vue-i18n** |
|
|
47
|
+
| -------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
48
|
+
| **组件附近的翻译** | ✅ 是,内容与组件共置(例如,`MyComp.content.ts`) | ✅ 是,通过 SFC `<i18n>` 块(可选) |
|
|
49
|
+
| **TypeScript 集成** | ✅ 高级,自动生成 **严格** 类型和键自动补全 | ✅ 良好的类型定义;**严格的键安全性需要额外的设置/规范** |
|
|
50
|
+
| **缺失翻译检测** | ✅ **构建时** 警告/错误和 TS 显示 | ⚠️ 运行时回退/警告 |
|
|
51
|
+
| **丰富内容(组件/Markdown)** | ✅ 直接支持丰富节点和Markdown内容文件 | ⚠️ 有限支持(组件通过`<i18n-t>`,Markdown通过外部插件) |
|
|
52
|
+
| **AI驱动的翻译** | ✅ 内置使用您自己的AI提供商密钥的工作流程 | ❌ 未内置 |
|
|
53
|
+
| **可视化编辑器 / CMS** | ✅ 免费的可视化编辑器和可选的CMS | ❌ 未内置(使用外部平台) |
|
|
54
|
+
| **本地化路由** | ✅ 为 Vue Router/Nuxt 提供生成本地化路径、URL 和 `hreflang` 的辅助工具 | ⚠️ 非核心功能(使用 Nuxt i18n 或自定义 Vue Router 配置) |
|
|
55
|
+
| **动态路由生成** | ✅ 支持 | ❌ 不提供(由 Nuxt i18n 提供) |
|
|
56
|
+
| **复数化与格式化** | ✅ 枚举模式;基于 Intl 的格式化工具 | ✅ ICU 风格消息;Intl 格式化工具 |
|
|
57
|
+
| **内容格式** | ✅ `.ts`、`.js`、`.json`、`.md`、`.txt`(YAML 进行中) | ✅ `.json`、`.js`(加上 SFC `<i18n>` 块) |
|
|
58
|
+
| **ICU 支持** | ⚠️ 进行中 | ✅ 支持 |
|
|
59
|
+
| **SEO 辅助工具(站点地图、robots、元数据)** | ✅ 内置辅助工具(框架无关) | ❌ 非核心功能(Nuxt i18n/社区提供) |
|
|
60
|
+
| **SSR/SSG** | ✅ 支持 Vue SSR 和 Nuxt;不阻塞静态渲染 | ✅ 支持 Vue SSR/Nuxt |
|
|
61
|
+
| **Tree-shaking(仅打包使用的内容)** | ✅ 构建时按组件进行 | ⚠️ 部分支持;需要手动代码拆分/异步消息 |
|
|
62
|
+
| **懒加载** | ✅ 按语言/词典级别 | ✅ 支持异步语言消息 |
|
|
63
|
+
| **清理未使用内容** | ✅ 是(构建时) | ❌ 非内置功能 |
|
|
64
|
+
| **大型项目可维护性** | ✅ 鼓励模块化、设计系统友好的结构 | ✅ 可行,但需要严格的文件/命名空间管理 |
|
|
65
|
+
| **生态系统 / 社区** | ⚠️ 较小但增长迅速 | ✅ Vue 生态系统中庞大且成熟 |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 深度比较
|
|
70
|
+
|
|
71
|
+
### 1) 架构与可扩展性
|
|
72
|
+
|
|
73
|
+
- **vue-i18n**:常见的设置是为每个语言环境使用**集中式目录**(可选地拆分为文件/命名空间)。SFC `<i18n>` 块允许局部消息,但随着项目增长,团队通常会回归使用共享目录。
|
|
74
|
+
- **Intlayer**:提倡将**每个组件的字典**存储在其对应组件旁边。这减少了跨团队冲突,保持内容可发现性,并自然限制了漂移/未使用的键。
|
|
75
|
+
|
|
76
|
+
**重要原因:** 在大型 Vue 应用或设计系统中,**模块化内容**比单体目录更易于扩展。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 2) TypeScript 与安全性
|
|
81
|
+
|
|
82
|
+
- **vue-i18n**:良好的 TS 支持;**严格键类型**通常需要自定义模式/泛型和谨慎的约定。
|
|
83
|
+
- **Intlayer**:从您的内容中**生成严格类型**,提供**IDE 自动补全**和针对拼写错误/缺失键的**编译时错误**。
|
|
84
|
+
|
|
85
|
+
**重要性说明:** 强类型可以在**运行前**捕获问题。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### 3) 缺失翻译处理
|
|
90
|
+
|
|
91
|
+
- **vue-i18n**:**运行时**警告/回退(例如,回退到默认语言或键)。
|
|
92
|
+
- **Intlayer**:通过**构建时**检测,针对不同语言和键发出警告/错误。
|
|
93
|
+
|
|
94
|
+
**重要性说明:** 构建时强制执行确保生产环境界面干净且一致。
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### 4) 路由与 URL 策略(Vue Router/Nuxt)
|
|
99
|
+
|
|
100
|
+
- **两者**都支持本地化路由。
|
|
101
|
+
- **Intlayer** 提供辅助工具来 **生成本地化路径**,**管理语言前缀**,并为 SEO 生成 **`<link rel="alternate" hreflang>`** 标签。在 Nuxt 中,它补充了框架的路由功能。
|
|
102
|
+
|
|
103
|
+
**重要性:** 减少自定义粘合层,实现跨语言环境的 **更清晰的 SEO**。
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### 5) 性能与加载行为
|
|
108
|
+
|
|
109
|
+
- **vue-i18n**:支持异步加载语言消息;避免过度打包需要你自行管理(需谨慎拆分目录)。
|
|
110
|
+
- **Intlayer**:在构建时进行 **Tree-shaking**,并按字典/语言进行 **懒加载**。未使用的内容不会被打包。
|
|
111
|
+
|
|
112
|
+
**重要性:** 更小的包体积和更快的多语言 Vue 应用启动速度。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 6) 开发者体验与工具链
|
|
117
|
+
|
|
118
|
+
- **vue-i18n**:成熟的文档和社区;您通常会依赖**外部本地化平台**来进行编辑工作流程。
|
|
119
|
+
- **Intlayer**:提供免费的**可视化编辑器**,可选的**CMS**(支持 Git 或外部化),一个**VSCode 扩展**,**CLI/CI** 工具,以及使用您自己的提供商密钥的**AI 辅助翻译**。
|
|
120
|
+
|
|
121
|
+
**重要原因:** 降低运维成本,缩短开发与内容的循环时间。
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### 7) SEO、SSR 与 SSG
|
|
126
|
+
|
|
127
|
+
- **两者**均支持 Vue SSR 和 Nuxt。
|
|
128
|
+
- **Intlayer**:增加了**SEO 辅助工具**(站点地图/元数据/`hreflang`),与框架无关,并且能很好地配合 Vue/Nuxt 构建。
|
|
129
|
+
|
|
130
|
+
**重要原因:** 实现国际化 SEO,无需定制复杂配置。
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 为什么选择 Intlayer?(问题与方法)
|
|
135
|
+
|
|
136
|
+
大多数 i18n 方案(包括 **vue-i18n**)都从**集中式目录**开始:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
.
|
|
140
|
+
├── locales
|
|
141
|
+
│ ├── en.json
|
|
142
|
+
│ ├── es.json
|
|
143
|
+
│ └── fr.json
|
|
144
|
+
└── src
|
|
145
|
+
└── components
|
|
146
|
+
└── MyComponent.vue
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
或者使用按语言区分的文件夹:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
.
|
|
153
|
+
├── locales
|
|
154
|
+
│ ├── en
|
|
155
|
+
│ │ ├── footer.json
|
|
156
|
+
│ │ └── navbar.json
|
|
157
|
+
│ ├── fr
|
|
158
|
+
│ │ ├── footer.json
|
|
159
|
+
│ │ └── navbar.json
|
|
160
|
+
│ └── es
|
|
161
|
+
│ ├── footer.json
|
|
162
|
+
│ └── navbar.json
|
|
163
|
+
└── src
|
|
164
|
+
└── components
|
|
165
|
+
└── MyComponent.vue
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
随着应用程序的增长,这通常会减慢开发速度:
|
|
169
|
+
|
|
170
|
+
1. **对于新组件**,你需要创建/编辑远程目录,连接命名空间,并进行翻译(通常通过从 AI 工具手动复制粘贴)。
|
|
171
|
+
2. **在更改组件时**,你需要寻找共享的键,进行翻译,保持各语言版本同步,删除无用键,并对齐 JSON 结构。
|
|
172
|
+
|
|
173
|
+
**Intlayer** 将内容限定在**每个组件范围内**,并将其**保存在代码旁边**,就像我们已经对 CSS、故事、测试和文档所做的那样:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
.
|
|
177
|
+
└── components
|
|
178
|
+
└── MyComponent
|
|
179
|
+
├── MyComponent.content.ts
|
|
180
|
+
└── MyComponent.vue
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**内容声明**(每个组件):
|
|
184
|
+
|
|
185
|
+
```ts fileName="./components/MyComponent/MyComponent.content.ts"
|
|
186
|
+
import { t, type Dictionary } from "intlayer";
|
|
187
|
+
|
|
188
|
+
// 组件示例内容声明
|
|
189
|
+
const componentExampleContent = {
|
|
190
|
+
key: "component-example",
|
|
191
|
+
content: {
|
|
192
|
+
greeting: t({
|
|
193
|
+
en: "Hello World",
|
|
194
|
+
es: "Hola Mundo",
|
|
195
|
+
fr: "Bonjour le monde",
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
} satisfies Dictionary;
|
|
199
|
+
|
|
200
|
+
export default componentExampleContent;
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**在 Vue 中的使用**(组合式 API):
|
|
204
|
+
|
|
205
|
+
```vue fileName="./components/MyComponent/MyComponent.vue"
|
|
206
|
+
<script setup lang="ts">
|
|
207
|
+
import { useIntlayer } from "vue-intlayer"; // Vue 集成
|
|
208
|
+
const { greeting } = useIntlayer("component-example");
|
|
209
|
+
</script>
|
|
210
|
+
|
|
211
|
+
<template>
|
|
212
|
+
<span>{{ greeting }}</span>
|
|
213
|
+
</template>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
这种方法:
|
|
217
|
+
|
|
218
|
+
- **加快开发速度**(声明一次;IDE/AI 自动补全)。
|
|
219
|
+
- **清理代码库**(1 个组件 = 1 个字典)。
|
|
220
|
+
- **简化复制/迁移**(复制组件及其内容一起复制)。
|
|
221
|
+
- **避免死键**(未使用的组件不导入内容)。
|
|
222
|
+
- **优化加载**(懒加载组件携带其内容)。
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Intlayer 的额外功能(与 Vue 相关)
|
|
227
|
+
|
|
228
|
+
- **跨框架支持**:支持 Vue、Nuxt、Vite、React、Express 等。
|
|
229
|
+
- **基于 JavaScript 的内容管理**:在代码中声明,灵活度高。
|
|
230
|
+
- **每个语言环境的声明文件**:为所有语言环境预设内容,工具自动生成其余部分。
|
|
231
|
+
- **类型安全环境**:强大的 TypeScript 配置,支持自动补全。
|
|
232
|
+
- **简化内容获取**:单一钩子/组合函数获取字典的所有内容。
|
|
233
|
+
- **有序的代码库**:一个组件对应一个字典,存放在同一文件夹。
|
|
234
|
+
- **增强的路由功能**:为 **Vue Router/Nuxt** 提供本地化路径和元数据的辅助工具。
|
|
235
|
+
- **Markdown 支持**:按语言环境导入远程/本地 Markdown;将 frontmatter 暴露给代码。
|
|
236
|
+
- **免费可视化编辑器和可选 CMS**:无需付费本地化平台即可创作;支持 Git 友好的同步。
|
|
237
|
+
- **可摇树内容**:仅打包使用的内容;支持懒加载。
|
|
238
|
+
- **静态渲染友好**:不阻塞静态站点生成(SSG)。
|
|
239
|
+
- **AI驱动的翻译**:使用您自己的AI提供商/API密钥,支持翻译成231种语言。
|
|
240
|
+
- **MCP服务器和VSCode扩展**:在您的IDE中自动化i18n工作流和内容创作。
|
|
241
|
+
- **互操作性**:在需要时与**vue-i18n**、**react-i18next**和**react-intl**桥接。
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 何时选择哪一个?
|
|
246
|
+
|
|
247
|
+
- 如果您想要**标准的Vue方案**,并且能够自行管理目录/命名空间,且您的应用是**小型到中型**(或者您已经依赖Nuxt i18n),请选择**vue-i18n**。
|
|
248
|
+
- 如果您重视**组件范围的内容**、**严格的TypeScript**、**构建时保证**、**摇树优化**以及**内置的路由/SEO/编辑工具**,尤其是针对**大型、模块化的Vue/Nuxt代码库**,请选择**Intlayer**。
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 实用迁移注意事项(vue-i18n → Intlayer)
|
|
253
|
+
|
|
254
|
+
- **按功能开始**:一次将一个路由/视图/组件迁移到本地 Intlayer 字典。
|
|
255
|
+
- **迁移期间桥接**:保持 vue-i18n 目录并行存在;逐步替换查找。
|
|
256
|
+
- **启用严格检查**:让构建时检测及早发现缺失的键/语言环境。
|
|
257
|
+
- **采用路由/SEO 辅助工具**:标准化语言环境检测和 `hreflang` 标签。
|
|
258
|
+
- **测量包大小**:随着未使用内容被排除,预计**包大小会减少**。
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 结论
|
|
263
|
+
|
|
264
|
+
**vue-i18n** 和 **Intlayer** 都能很好地本地化 Vue 应用。区别在于你需要自己构建多少内容,才能实现一个健壮且可扩展的方案:
|
|
265
|
+
|
|
266
|
+
- 使用 **Intlayer**,**模块化内容**、**严格的 TS**、**构建时安全性**、**摇树优化的包**以及**路由/SEO/编辑器工具**均为**开箱即用**。
|
|
267
|
+
- 如果您的团队优先考虑在多语言、组件驱动的 Vue/Nuxt 应用中的**可维护性和速度**,Intlayer 提供了目前**最完整**的体验。
|
|
268
|
+
|
|
269
|
+
有关更多详情,请参阅 ['为什么选择 Intlayer?' 文档](https://intlayer.org/doc/why)。
|
|
@@ -1600,6 +1600,47 @@ const blogEntry = {
|
|
|
1600
1600
|
)
|
|
1601
1601
|
)
|
|
1602
1602
|
},
|
|
1603
|
+
"./blog/en/vue-i18n_vs_intlayer.md": {
|
|
1604
|
+
en: Promise.resolve(
|
|
1605
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/en/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1606
|
+
),
|
|
1607
|
+
fr: Promise.resolve(
|
|
1608
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/fr/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1609
|
+
),
|
|
1610
|
+
ru: Promise.resolve(
|
|
1611
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/ru/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1612
|
+
),
|
|
1613
|
+
ja: Promise.resolve(
|
|
1614
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/ja/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1615
|
+
),
|
|
1616
|
+
ko: Promise.resolve(
|
|
1617
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/ko/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1618
|
+
),
|
|
1619
|
+
zh: Promise.resolve(
|
|
1620
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/zh/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1621
|
+
),
|
|
1622
|
+
es: Promise.resolve(
|
|
1623
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/es/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1624
|
+
),
|
|
1625
|
+
de: Promise.resolve(
|
|
1626
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/de/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1627
|
+
),
|
|
1628
|
+
ar: Promise.resolve(
|
|
1629
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/ar/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1630
|
+
),
|
|
1631
|
+
pt: Promise.resolve(
|
|
1632
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/pt/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1633
|
+
),
|
|
1634
|
+
"en-GB": Promise.resolve(
|
|
1635
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/en-GB/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1636
|
+
),
|
|
1637
|
+
it: Promise.resolve(
|
|
1638
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/it/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1639
|
+
),
|
|
1640
|
+
hi: Promise.resolve(
|
|
1641
|
+
(0, import_promises.readFile)((0, import_path.join)(dir, "../../../blog/hi/vue-i18n_vs_intlayer.md"), "utf8")
|
|
1642
|
+
)
|
|
1643
|
+
},
|
|
1603
1644
|
"./blog/en/what_is_internationalization.md": {
|
|
1604
1645
|
en: Promise.resolve(
|
|
1605
1646
|
(0, import_promises.readFile)(
|