@modern-js/main-doc 3.1.4 → 3.2.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.
Files changed (47) hide show
  1. package/docs/en/components/international/init-options-desc.mdx +1 -1
  2. package/docs/en/components/international/install-command.mdx +4 -17
  3. package/docs/en/components/international/instance-code.mdx +4 -14
  4. package/docs/en/components/international/introduce.mdx +4 -1
  5. package/docs/en/configure/app/source/enable-async-pre-entry.mdx +30 -0
  6. package/docs/en/configure/app/tools/dev-server.mdx +0 -4
  7. package/docs/en/guides/advanced-features/international/_meta.json +0 -1
  8. package/docs/en/guides/advanced-features/international/advanced.mdx +48 -109
  9. package/docs/en/guides/advanced-features/international/api.mdx +125 -290
  10. package/docs/en/guides/advanced-features/international/best-practices.mdx +203 -48
  11. package/docs/en/guides/advanced-features/international/configuration.mdx +108 -315
  12. package/docs/en/guides/advanced-features/international/locale-detection.mdx +62 -208
  13. package/docs/en/guides/advanced-features/international/quick-start.mdx +41 -55
  14. package/docs/en/guides/advanced-features/international/resource-loading.mdx +63 -322
  15. package/docs/en/guides/advanced-features/international/routing.mdx +60 -138
  16. package/docs/en/guides/advanced-features/international.mdx +19 -27
  17. package/docs/en/guides/basic-features/alias.mdx +1 -1
  18. package/docs/en/guides/basic-features/html.mdx +2 -2
  19. package/docs/en/guides/basic-features/static-assets.mdx +1 -2
  20. package/docs/en/guides/concept/entries.mdx +2 -2
  21. package/docs/zh/components/international/init-options-desc.mdx +1 -1
  22. package/docs/zh/components/international/install-command.mdx +4 -16
  23. package/docs/zh/components/international/instance-code.mdx +4 -14
  24. package/docs/zh/components/international/introduce.mdx +5 -2
  25. package/docs/zh/configure/app/source/enable-async-pre-entry.mdx +77 -0
  26. package/docs/zh/configure/app/tools/dev-server.mdx +0 -4
  27. package/docs/zh/guides/advanced-features/bff/function.mdx +2 -2
  28. package/docs/zh/guides/advanced-features/international/_meta.json +0 -1
  29. package/docs/zh/guides/advanced-features/international/advanced.mdx +48 -109
  30. package/docs/zh/guides/advanced-features/international/api.mdx +126 -292
  31. package/docs/zh/guides/advanced-features/international/best-practices.mdx +204 -49
  32. package/docs/zh/guides/advanced-features/international/configuration.mdx +105 -318
  33. package/docs/zh/guides/advanced-features/international/locale-detection.mdx +62 -236
  34. package/docs/zh/guides/advanced-features/international/quick-start.mdx +40 -54
  35. package/docs/zh/guides/advanced-features/international/resource-loading.mdx +62 -324
  36. package/docs/zh/guides/advanced-features/international/routing.mdx +58 -136
  37. package/docs/zh/guides/advanced-features/international.mdx +19 -26
  38. package/docs/zh/guides/basic-features/alias.mdx +1 -1
  39. package/docs/zh/guides/basic-features/html.mdx +2 -2
  40. package/docs/zh/guides/basic-features/static-assets.mdx +1 -2
  41. package/docs/zh/guides/concept/entries.mdx +2 -2
  42. package/package.json +5 -4
  43. package/rspress.config.ts +45 -26
  44. package/docs/en/components/rspackPrecautions.mdx +0 -6
  45. package/docs/en/guides/advanced-features/international/basic.mdx +0 -417
  46. package/docs/zh/components/rspackPrecautions.mdx +0 -6
  47. package/docs/zh/guides/advanced-features/international/basic.mdx +0 -416
@@ -4,312 +4,142 @@ title: API 参考
4
4
 
5
5
  # API 参考
6
6
 
7
- ## useModernI18n Hook
7
+ ## useModernI18n
8
8
 
9
- `useModernI18n` 是插件提供的 React Hook,用于在组件中访问国际化功能。
9
+ `useModernI18n` 是插件提供的 React Hook,用于在组件中访问国际化状态和操作。
10
10
 
11
- ### 返回值说明
11
+ ### 返回值
12
12
 
13
- ```ts
14
- interface UseModernI18nReturn {
15
- /** 当前语言代码 */
16
- language: string;
17
-
18
- /** 切换语言的函数 */
19
- changeLanguage: (newLang: string) => Promise<void>;
20
-
21
- /** i18next 实例(用于高级用法) */
22
- i18nInstance: I18nInstance;
23
-
24
- /** 支持的语言列表 */
25
- supportedLanguages: string[];
26
-
27
- /** 检查语言是否支持 */
28
- isLanguageSupported: (lang: string) => boolean;
29
-
30
- /** 指示当前语言的翻译资源是否已准备好可以使用 */
31
- isResourcesReady: boolean;
32
- }
33
- ```
13
+ | 字段 | 类型 | 说明 |
14
+ | --- | --- | --- |
15
+ | `language` | `string` | 当前语言代码 |
16
+ | `changeLanguage` | `(lang: string) => Promise<void>` | 切换语言 |
17
+ | `supportedLanguages` | `string[]` | 支持的语言列表(来自 `localeDetection.languages`) |
18
+ | `isLanguageSupported` | `(lang: string) => boolean` | 检查语言是否在支持列表中 |
19
+ | `isResourcesReady` | `boolean` | 当前语言的翻译资源是否已加载完成 |
20
+ | `i18nInstance` | `I18nInstance` | i18next 实例(用于高级场景) |
34
21
 
35
- ### 使用示例
22
+ ### 基本用法
36
23
 
37
24
  ```tsx
38
25
  import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
26
+ import { useTranslation } from 'react-i18next';
39
27
 
40
28
  function LanguageSwitcher() {
41
- const { language, changeLanguage, supportedLanguages, isLanguageSupported } =
42
- useModernI18n();
29
+ const { language, changeLanguage, supportedLanguages } = useModernI18n();
30
+ const { t } = useTranslation();
43
31
 
44
32
  return (
45
33
  <div>
46
- <p>当前语言: {language}</p>
47
- <div>
48
- {supportedLanguages.map(lang => (
49
- <button
50
- key={lang}
51
- onClick={() => changeLanguage(lang)}
52
- disabled={lang === language}
53
- >
54
- {lang}
55
- </button>
56
- ))}
57
- </div>
58
- <button
59
- onClick={() => {
60
- if (isLanguageSupported('ja')) {
61
- changeLanguage('ja');
62
- }
63
- }}
64
- >
65
- 切换到日语
66
- </button>
34
+ <p>{t('welcome')}</p>
35
+ {supportedLanguages.map(lang => (
36
+ <button
37
+ key={lang}
38
+ onClick={() => changeLanguage(lang)}
39
+ disabled={lang === language}
40
+ >
41
+ {lang}
42
+ </button>
43
+ ))}
67
44
  </div>
68
45
  );
69
46
  }
70
47
  ```
71
48
 
72
- ### changeLanguage 方法
49
+ ### changeLanguage
73
50
 
74
- `changeLanguage` 方法用于切换语言,它会:
51
+ 切换语言时会依次执行:
75
52
 
76
53
  1. 更新 i18next 实例的语言
77
- 2. 更新浏览器缓存(Cookie/LocalStorage
78
- 3. 更新 URL 路径(如果启用 `localePathRedirect`)
54
+ 2. 更新浏览器缓存(Cookie / LocalStorage,取决于 `caches` 配置)
55
+ 3. 更新 URL 路径前缀(如果启用了 `localePathRedirect`)
79
56
 
80
- ```tsx
81
- const { changeLanguage } = useModernI18n();
57
+ `changeLanguage` 是异步函数,使用时需要 `await`:
82
58
 
83
- // 切换语言
59
+ ```ts
84
60
  await changeLanguage('zh');
85
61
  ```
86
62
 
87
- :::info
88
- `changeLanguage` 是异步函数,返回 Promise。
63
+ ### isResourcesReady
89
64
 
90
- :::
91
-
92
- ### 语言支持检查
93
-
94
- `isLanguageSupported` 用于检查某个语言是否在支持的语言列表中:
65
+ 在自定义后端场景中,翻译资源需要异步加载,可以用 `isResourcesReady` 防止在资源未就绪时渲染:
95
66
 
96
67
  ```tsx
97
- const { isLanguageSupported, changeLanguage } = useModernI18n();
98
-
99
- function handleLanguageChange(lang: string) {
100
- if (isLanguageSupported(lang)) {
101
- changeLanguage(lang);
102
- } else {
103
- console.warn(`语言 ${lang} 不受支持`);
104
- }
105
- }
106
- ```
107
-
108
- ### 资源加载状态
109
-
110
- `isResourcesReady` 指示当前语言的翻译资源是否已加载完成并可以使用。这在使用了 SDK 后端动态加载资源时特别有用。
111
-
112
- ```tsx
113
- import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
114
-
115
68
  function MyComponent() {
116
69
  const { isResourcesReady } = useModernI18n();
70
+ const { t } = useTranslation();
117
71
 
118
72
  if (!isResourcesReady) {
119
- return <div>正在加载翻译资源...</div>;
73
+ return <div>加载翻译中...</div>;
120
74
  }
121
75
 
122
- return <div>翻译资源已准备好</div>;
76
+ return <div>{t('content')}</div>;
123
77
  }
124
78
  ```
125
79
 
126
- **使用场景:**
127
-
128
- - 在资源加载时显示加载状态
129
- - 在资源准备好之前阻止渲染依赖翻译的内容
130
- - 优雅地处理资源加载错误
131
-
132
- :::info
133
- `isResourcesReady` 会自动检查:
134
-
135
- - i18n 实例是否已初始化
136
- - 当前语言是否有资源正在加载中(仅 SDK 后端)
137
- - 当前语言的所有必需命名空间是否已在 store 中加载完成
138
-
139
- :::
80
+ `isResourcesReady` 会检查:i18n 实例是否已初始化、当前语言是否有资源正在加载、所有必需命名空间是否已加载完成。
140
81
 
141
82
  ## I18nLink 组件
142
83
 
143
- `I18nLink` 组件用于创建带语言前缀的链接。
84
+ 带语言前缀的路由链接组件。
144
85
 
145
- ### Props 说明
86
+ ### Props
146
87
 
147
- ```tsx
148
- interface I18nLinkProps {
149
- /** 目标路径(不需要包含语言前缀) */
150
- to: string;
151
- /** 子元素 */
152
- children: React.ReactNode;
153
- /** 其他 Link 组件的 props(如 replace、state 等) */
154
- [key: string]: any;
155
- }
156
- ```
88
+ | Prop | 类型 | 必填 | 说明 |
89
+ | --- | --- | --- | --- |
90
+ | `to` | `string` | 是 | 目标路径,不需要包含语言前缀 |
91
+ | `children` | `React.ReactNode` | 是 | 链接内容 |
92
+ | `replace` | `boolean` | 否 | 使用 `history.replace` 而非 `push` |
93
+ | `state` | `any` | 否 | 传递给目标路由的状态 |
94
+ | 其他 Link props | | 否 | 继承自 `@modern-js/runtime/router` 的 `Link` 组件 |
157
95
 
158
- ### 使用示例
96
+ ### 用法
159
97
 
160
98
  ```tsx
161
99
  import { I18nLink } from '@modern-js/plugin-i18n/runtime';
162
100
 
163
- function Navigation() {
164
- return (
165
- <nav>
166
- <I18nLink to="/">首页</I18nLink>
167
- <I18nLink to="/about">关于</I18nLink>
168
- <I18nLink to="/contact" replace>
169
- 联系
170
- </I18nLink>
171
- </nav>
172
- );
173
- }
101
+ <I18nLink to="/about">关于</I18nLink>
102
+ <I18nLink to="/contact" replace>联系</I18nLink>
103
+ <I18nLink to="/profile" state={{ from: 'home' }}>个人中心</I18nLink>
174
104
  ```
175
105
 
176
106
  ## Runtime 插件 API
177
107
 
178
- Runtime 插件的 `onBeforeRender` 钩子中,可以通过 `context.changeLanguage` 方法修改语言。这对于需要根据请求信息(如用户偏好、地理位置等)动态设置语言的场景非常有用。
179
-
180
- ### context.changeLanguage
181
-
182
- 在 `onBeforeRender` 钩子中,i18n 插件会在 `context` 上添加 `changeLanguage` 方法,供其他 Runtime 插件使用。
183
-
184
- **类型定义:**
185
-
186
- ```ts
187
- interface TInternalRuntimeContext {
188
- i18nInstance?: I18nInstance;
189
- changeLanguage?: (lang: string) => Promise<void>;
190
- }
191
- ```
192
-
193
- ### 使用示例
108
+ i18n 插件会在 `onBeforeRender` 钩子的 context 上挂载 `changeLanguage` 和 `i18nInstance`,供其他 Runtime 插件使用:
194
109
 
195
110
  ```ts
196
111
  import type { RuntimePlugin } from '@modern-js/runtime';
197
112
 
198
- const myRuntimePlugin = (): RuntimePlugin => ({
199
- name: 'my-runtime-plugin',
113
+ const myPlugin = (): RuntimePlugin => ({
114
+ name: 'my-plugin',
200
115
  setup: api => {
201
116
  api.onBeforeRender(async context => {
202
- // 检查是否有 changeLanguage 方法(确保 i18n 插件已加载)
203
- if (context.changeLanguage) {
204
- // 根据某些条件决定语言
205
- const userLang = getUserLanguageFromRequest(context);
117
+ if (!context.changeLanguage) return; // 确保 i18n 插件已加载
118
+
119
+ const lang = detectLangFromRequest(context);
120
+ const supported = context.i18nInstance?.options?.supportedLngs ?? [];
206
121
 
207
- // 修改语言
208
- await context.changeLanguage(userLang);
122
+ if (supported.includes(lang)) {
123
+ try {
124
+ await context.changeLanguage(lang);
125
+ } catch (e) {
126
+ console.error('Language change failed:', e);
127
+ }
209
128
  }
210
129
  });
211
130
  },
212
131
  });
213
-
214
- function getUserLanguageFromRequest(context: any): string {
215
- // 从请求头、Cookie 或其他来源获取用户语言
216
- const acceptLanguage = context.ssrContext?.req?.headers['accept-language'];
217
- // 解析并返回合适的语言代码
218
- return parseAcceptLanguage(acceptLanguage) || 'zh';
219
- }
220
-
221
- export default myRuntimePlugin;
222
- ```
223
-
224
- ### 注意事项
225
-
226
- 1. **执行顺序**:确保 i18n 插件在其他使用 `changeLanguage` 的插件之前注册,这样 `context.changeLanguage` 才会可用。
227
-
228
- 2. **异步操作**:`changeLanguage` 是异步方法,需要使用 `await` 等待完成。
229
-
230
- 3. **错误处理**:如果传入无效的语言代码,会抛出错误,建议添加错误处理:
231
-
232
- ```ts
233
- api.onBeforeRender(async context => {
234
- if (context.changeLanguage) {
235
- try {
236
- await context.changeLanguage('zh');
237
- } catch (error) {
238
- console.error('Failed to change language:', error);
239
- }
240
- }
241
- });
242
132
  ```
243
133
 
244
- 4. **语言验证**:建议在调用 `changeLanguage` 前验证语言是否在支持的语言列表中:
245
-
246
- ```ts
247
- api.onBeforeRender(async context => {
248
- if (context.changeLanguage && context.i18nInstance) {
249
- const supportedLngs = context.i18nInstance.options?.supportedLngs || [];
250
- const targetLang = 'zh';
251
-
252
- if (supportedLngs.includes(targetLang)) {
253
- await context.changeLanguage(targetLang);
254
- }
255
- }
256
- });
257
- ```
258
-
259
- :::info
260
- `changeLanguage` 方法会:
261
-
262
- - 更新 i18n 实例的语言
263
- - 在浏览器环境中缓存语言选择(Cookie/LocalStorage)
264
- - 触发语言切换相关的回调
265
-
266
- 但不会自动更新 URL 路径,如果需要更新 URL,需要配合路由插件或手动处理。
267
- :::
268
-
269
- ## 与 react-i18next 集成
270
-
271
- 插件完全兼容 `react-i18next`,可以使用 `useTranslation` Hook 和其他 `react-i18next` 功能。
272
-
273
- ### useTranslation Hook
274
-
275
- ```tsx
276
- import { useTranslation } from 'react-i18next';
277
-
278
- function MyComponent() {
279
- const { t, i18n } = useTranslation();
280
-
281
- return (
282
- <div>
283
- <h1>{t('welcome')}</h1>
284
- <p>{t('description', { name: 'Modern.js' })}</p>
285
- </div>
286
- );
287
- }
288
- ```
289
-
290
- ### i18next 实例访问
291
-
292
- 可以通过 `useModernI18n` 获取 i18next 实例:
293
-
294
- ```tsx
295
- import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
296
- import { useTranslation } from 'react-i18next';
297
-
298
- function MyComponent() {
299
- const { i18nInstance } = useModernI18n();
300
- const { t } = useTranslation();
301
-
302
- // 直接访问 i18next 实例
303
- console.log(i18nInstance.language);
304
- console.log(i18nInstance.options);
305
-
306
- return <div>{t('hello')}</div>;
307
- }
308
- ```
134
+ **注意事项:**
135
+ - 确保 i18n 插件在使用 `context.changeLanguage` 的插件之前注册
136
+ - `changeLanguage` 在服务端不会更新 URL 路径,需要配合路由插件或手动处理
309
137
 
310
138
  ## 类型定义
311
139
 
312
- ### I18nInstance 接口
140
+ ### I18nInstance
141
+
142
+ 插件使用的 i18next 实例类型(i18next `i18n` 类型的子集,仅列出插件实际使用的字段):
313
143
 
314
144
  ```ts
315
145
  interface I18nInstance {
@@ -319,82 +149,86 @@ interface I18nInstance {
319
149
  changeLanguage: (lang: string) => void | Promise<void>;
320
150
  use: (plugin: any) => void;
321
151
  createInstance: (options?: I18nInitOptions) => I18nInstance;
322
- cloneInstance?: () => I18nInstance;
323
- services?: {
324
- languageDetector?: {
325
- detect: (request?: any, options?: any) => string | string[] | undefined;
326
- [key: string]: any;
327
- };
328
- [key: string]: any;
329
- };
330
152
  options?: {
331
153
  backend?: BackendOptions;
154
+ supportedLngs?: string[];
332
155
  [key: string]: any;
333
156
  };
334
157
  }
335
158
  ```
336
159
 
337
- ### I18nInitOptions 接口
160
+ ### I18nSdkLoader
161
+
162
+ 自定义后端加载函数的类型:
338
163
 
339
164
  ```ts
340
- interface I18nInitOptions {
341
- lng?: string;
342
- fallbackLng?: string;
343
- supportedLngs?: string[];
344
- initImmediate?: boolean;
345
- detection?: LanguageDetectorOptions;
346
- backend?: BackendOptions;
347
- resources?: Resources;
348
- ns?: string | string[];
349
- defaultNS?: string | string[];
350
- react?: {
351
- useSuspense?: boolean;
352
- [key: string]: any;
353
- };
354
- [key: string]: any;
165
+ type I18nSdkLoader = (options: I18nSdkLoadOptions) => Promise<Resources>;
166
+
167
+ interface I18nSdkLoadOptions {
168
+ lng?: string; // 单个语言代码
169
+ ns?: string; // 单个命名空间
170
+ lngs?: string[]; // 多个语言代码
171
+ nss?: string[]; // 多个命名空间
172
+ all?: boolean; // 加载所有资源
355
173
  }
174
+
175
+ type Resources = {
176
+ [lng: string]: {
177
+ [ns: string]: Record<string, any>;
178
+ };
179
+ };
356
180
  ```
357
181
 
358
- ### LanguageDetectorOptions 接口
182
+ ### LanguageDetectorOptions
359
183
 
360
184
  ```ts
361
185
  interface LanguageDetectorOptions {
362
- /** 检测顺序 */
363
186
  order?: string[];
364
- /** 查询参数的键名,默认 'lng' */
365
- lookupQuerystring?: string;
366
- /** Cookie 的键名,默认 'i18next' */
367
- lookupCookie?: string;
368
- /** LocalStorage 的键名,默认 'i18nextLng'(仅浏览器环境) */
369
- lookupLocalStorage?: string;
370
- /** SessionStorage 的键名(仅浏览器环境) */
187
+ lookupQuerystring?: string; // 默认 'lng'
188
+ lookupCookie?: string; // 默认 'i18next'
189
+ lookupLocalStorage?: string; // 默认 'i18nextLng'
371
190
  lookupSession?: string;
372
- /** 从路径的哪个位置开始检测语言,默认 0 */
373
- lookupFromPathIndex?: number;
374
- /** 缓存方式,可以是 false、字符串数组(如 ['cookie', 'localStorage']) */
375
- caches?: boolean | string[];
376
- /** Cookie 过期时间(分钟) */
377
- cookieMinutes?: number;
378
- /** Cookie 过期日期(Date 对象,优先级高于 cookieMinutes) */
191
+ lookupHeader?: string; // 默认 'accept-language'
192
+ lookupFromPathIndex?: number; // 默认 0
193
+ caches?: false | string[];
194
+ cookieMinutes?: number; // 默认 525600(1年)
379
195
  cookieExpirationDate?: Date;
380
- /** Cookie 域名 */
381
196
  cookieDomain?: string;
382
- /** 请求头的键名,默认 'accept-language' */
383
- lookupHeader?: string;
384
197
  }
385
198
  ```
386
199
 
387
- ### Resources 类型
200
+ ## react-i18next 集成
388
201
 
389
- ```ts
390
- type Resources = {
391
- [lng: string]: {
392
- [ns: string]: string | Record<string, string>;
393
- };
394
- };
202
+ 插件完全兼容 react-i18next,两套 API 可以混用:
203
+
204
+ - **`useTranslation`**(react-i18next):获取 `t()` 函数做翻译,这是最常用的 Hook
205
+ - **`useModernI18n`**(插件提供):获取语言切换、支持列表、资源加载状态等插件层面的状态
206
+
207
+ 大多数组件只需要 `useTranslation`,只有涉及语言切换或需要检查加载状态时才需要 `useModernI18n`:
208
+
209
+ ```tsx
210
+ import { useTranslation } from 'react-i18next';
211
+ import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
212
+
213
+ function App() {
214
+ const { t } = useTranslation(); // 翻译文本
215
+ const { language, changeLanguage } = useModernI18n(); // 语言切换
216
+
217
+ return (
218
+ <div>
219
+ <h1>{t('welcome')}</h1>
220
+ <button onClick={() => changeLanguage('zh')}>中文</button>
221
+ <button onClick={() => changeLanguage('en')}>English</button>
222
+ </div>
223
+ );
224
+ }
395
225
  ```
396
226
 
397
- :::info
398
- 命名空间的值可以是字符串(用于简单的键值对)或对象(用于嵌套的翻译结构)。
227
+ 也可以通过 `useModernI18n` 获取 i18next 实例后直接调用 react-i18next 之外的能力:
228
+
229
+ ```tsx
230
+ const { i18nInstance } = useModernI18n();
399
231
 
400
- :::
232
+ // 动态添加翻译资源
233
+ i18nInstance.addResourceBundle('zh', 'translation', { key: '值' }, true, true);
234
+ ```