@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
@@ -1,50 +1,43 @@
1
1
  ---
2
2
  title: 资源加载
3
3
  ---
4
-
5
4
  # 资源加载
6
5
 
7
- 插件支持三种资源加载方式:HTTP 后端、文件系统后端(FS Backend)和 SDK 后端。同时,插件还支持链式后端,可以组合使用多个后端。
6
+ 翻译文件的加载方式取决于你的翻译资源放在哪里:
8
7
 
9
- ## HTTP 后端
8
+ | 场景 | 加载方式 |
9
+ | --- | --- |
10
+ | 翻译文件放在项目本地 | 静态文件后端(本篇默认方式) |
11
+ | 翻译来自远程 API、翻译平台 | 自定义后端 |
12
+ | 两者都要:本地兜底 + 远程实时更新 | 链式后端 |
10
13
 
11
- HTTP 后端通过 HTTP 请求加载资源文件,适用于客户端渲染(CSR)场景。
14
+ ## 静态文件后端
12
15
 
13
- ### 配置方式
16
+ 把翻译文件放在项目里,插件直接加载。这是最常见的方式。
14
17
 
15
- ```ts
16
- i18nPlugin({
17
- backend: {
18
- enabled: true,
19
- loadPath: '/locales/{{lng}}/{{ns}}.json',
20
- },
21
- });
22
- ```
18
+ **CSR 和 SSR 的加载机制不同,但配置完全一样:**
19
+ - CSR:浏览器通过 HTTP 请求拉取翻译文件(如 `GET /locales/zh/translation.json`)
20
+ - SSR:服务端直接从磁盘读取文件,不走 HTTP
23
21
 
24
- ### 资源文件结构
22
+ 插件会根据运行环境自动选择,你只需要配置一次 `loadPath`。
25
23
 
26
- 资源文件需要放在 `config/public` 目录或通过 `server.publicDir` 配置的目录中:
24
+ **资源文件位置:**
27
25
 
28
26
  ```
29
- config/public/
30
- └── locales/
31
- ├── en/
32
- │ └── translation.json
33
- └── zh/
34
- └── translation.json
27
+ config/public/locales/ ← 默认位置,无需额外配置
28
+ ├── en/translation.json
29
+ └── zh/translation.json
35
30
  ```
36
31
 
37
- 或者通过 `server.publicDir` 配置自定义目录:
38
-
39
32
  ```ts
33
+ // modern.config.ts
40
34
  export default defineConfig({
41
- server: {
42
- publicDir: './locales', // 指定资源文件目录
43
- },
44
35
  plugins: [
36
+ appTools(),
45
37
  i18nPlugin({
46
38
  backend: {
47
- enabled: true,
39
+ // `{{lng}}` 对应语言代码,`{{ns}}` 对应命名空间名称。
40
+ // SSR 时插件会自动将路径中的 `/` 前缀转换为相对路径后进行文件读取,无需额外处理。
48
41
  loadPath: '/locales/{{lng}}/{{ns}}.json',
49
42
  },
50
43
  }),
@@ -52,115 +45,43 @@ export default defineConfig({
52
45
  });
53
46
  ```
54
47
 
55
- **资源文件格式**:
56
-
57
- ```json
58
- {
59
- "key1": "value1",
60
- "key2": "value2",
61
- "nested": {
62
- "key": "value"
63
- }
64
- }
65
- ```
66
-
67
- ### 路径变量
68
-
69
- `loadPath` 支持以下变量:
70
-
71
- - `{{lng}}`:语言代码(如 `en`、`zh`)
72
- - `{{ns}}`:命名空间(如 `translation`、`common`)
73
-
74
- **示例**:
75
-
76
- ```ts
77
- // 默认路径格式
78
- loadPath: '/locales/{{lng}}/{{ns}}.json';
79
- // 实际加载路径:
80
- // /locales/en/translation.json
81
- // /locales/zh/translation.json
82
-
83
- // 自定义路径格式
84
- loadPath: '/i18n/{{lng}}/{{ns}}.json';
85
- // 实际加载路径:
86
- // /i18n/en/translation.json
87
- // /i18n/zh/translation.json
88
- ```
89
-
90
- ## 文件系统后端(FS Backend)
91
-
92
- 文件系统后端直接从文件系统读取资源文件,适用于服务端渲染(SSR)场景。
93
-
94
- ### 配置方式
95
-
96
- 在 SSR 场景下,插件会自动使用文件系统后端。资源文件需要放在项目目录中:
97
-
98
- ```
99
- 项目根目录/
100
- └── locales/
101
- ├── en/
102
- │ └── translation.json
103
- └── zh/
104
- └── translation.json
105
- ```
106
-
107
- ### 资源文件路径
108
-
109
- 文件系统后端的默认路径格式为相对路径:
110
-
111
- ```
112
- ./locales/{{lng}}/{{ns}}.json
113
- ```
114
-
115
- 可以通过 `loadPath` 自定义路径:
116
-
117
- ```ts
118
- i18nPlugin({
119
- backend: {
120
- enabled: true,
121
- loadPath: '/locales/{{lng}}/{{ns}}.json', // 使用绝对路径(推荐)
122
- },
123
- });
124
- ```
125
-
126
- :::warning
127
- `loadPath` 配置会同时用于 HTTP 后端(前端)和文件系统后端(服务端)。如果配置的是以 `/` 开头的绝对路径(如 `/locales/{{lng}}/{{ns}}.json`),文件系统后端会自动将其转换为相对路径(`./locales/{{lng}}/{{ns}}.json`)。因此,建议在配置中使用绝对路径,这样可以同时满足前后端的需求。
48
+ 如果想放在其他目录,通过 `server.publicDir` 指定。其中,**`server.publicDir` 和 `backend.loadPath` 的关系:**
128
49
 
129
- :::
50
+ - `server.publicDir`:决定哪个本地目录被暴露为静态资源,即文件放在哪里
51
+ - `backend.loadPath`:决定 i18next 请求哪个 URL 去加载翻译文件,或者服务端从哪个路径去读取文件
130
52
 
131
- ## SDK 后端
53
+ ## 自定义后端
132
54
 
133
- SDK 后端允许通过自定义函数加载资源,适用于需要从外部服务、数据库或其他自定义来源加载翻译资源的场景。
55
+ 翻译资源不在本地文件,而是来自远程 API、数据库或翻译平台时,通过一个异步函数来加载。
134
56
 
135
- ### 启用 SDK 模式
136
-
137
- **步骤 1:在 `modern.config.ts` 中启用 SDK 模式**
57
+ **第一步:在 `modern.config.ts` 中声明启用**
138
58
 
139
59
  ```ts
140
60
  i18nPlugin({
141
61
  backend: {
142
- enabled: true,
143
- sdk: true, // 启用 SDK 模式
62
+ sdk: true,
144
63
  },
145
64
  });
146
65
  ```
147
66
 
148
- **步骤 2:在 `modern.runtime.ts` 中实现 SDK 函数**
67
+ **第二步:在 `modern.runtime.ts` 中实现加载函数**
149
68
 
150
69
  ```ts
151
70
  import { defineRuntimeConfig } from '@modern-js/runtime';
152
- import type { I18nSdkLoader, Resources } from '@modern-js/plugin-i18n/runtime';
71
+ import type { I18nSdkLoader } from '@modern-js/plugin-i18n/runtime';
153
72
 
154
- const mySdkLoader: I18nSdkLoader = async options => {
155
- // 实现资源加载逻辑
156
- if (options.all) {
157
- // 加载所有资源
158
- return await loadAllResources();
73
+ const myLoader: I18nSdkLoader = async options => {
74
+ // 最常用:按语言 + 命名空间加载单个资源
75
+ if (options.lng && options.ns) {
76
+ const res = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
77
+ const data = await res.json();
78
+ return { [options.lng]: { [options.ns]: data } };
159
79
  }
160
80
 
161
- if (options.lng && options.ns) {
162
- // 加载单个资源
163
- return await loadSingleResource(options.lng, options.ns);
81
+ // 一次性加载所有资源
82
+ if (options.all) {
83
+ const res = await fetch('/api/i18n/all');
84
+ return res.json(); // 格式:{ en: { translation: {...} }, zh: { translation: {...} } }
164
85
  }
165
86
 
166
87
  return {};
@@ -169,238 +90,53 @@ const mySdkLoader: I18nSdkLoader = async options => {
169
90
  export default defineRuntimeConfig({
170
91
  i18n: {
171
92
  initOptions: {
172
- backend: {
173
- sdk: mySdkLoader,
174
- },
93
+ backend: { sdk: myLoader },
175
94
  },
176
95
  },
177
96
  });
178
97
  ```
179
98
 
180
- ### 实现 SDK 加载函数
181
-
182
- SDK 函数接收一个 `I18nSdkLoadOptions` 参数,需要返回 `Resources` 格式的数据:
99
+ **加载函数的参数类型:**
183
100
 
184
101
  ```ts
185
102
  interface I18nSdkLoadOptions {
186
- /** 单个语言代码 */
187
- lng?: string;
188
- /** 单个命名空间 */
189
- ns?: string;
190
- /** 多个语言代码 */
191
- lngs?: string[];
192
- /** 多个命名空间 */
193
- nss?: string[];
194
- /** 加载所有资源 */
195
- all?: boolean;
196
- }
197
-
198
- type Resources = {
199
- [lng: string]: {
200
- [ns: string]: Record<string, string>;
201
- };
202
- };
203
- ```
204
-
205
- ### 批量加载示例
206
-
207
- SDK 后端支持多种加载模式:
208
-
209
- **1. 加载单个资源**:
210
-
211
- ```ts
212
- const sdkLoader: I18nSdkLoader = async options => {
213
- if (options.lng && options.ns) {
214
- const response = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
215
- const data = await response.json();
216
- return {
217
- [options.lng]: {
218
- [options.ns]: data,
219
- },
220
- };
221
- }
222
- return {};
223
- };
224
- ```
225
-
226
- **2. 批量加载多个语言**:
227
-
228
- ```ts
229
- const sdkLoader: I18nSdkLoader = async options => {
230
- if (options.lngs && options.ns) {
231
- const resources: Resources = {};
232
- for (const lng of options.lngs) {
233
- const response = await fetch(`/api/i18n/${lng}/${options.ns}`);
234
- resources[lng] = {
235
- [options.ns]: await response.json(),
236
- };
237
- }
238
- return resources;
239
- }
240
- return {};
241
- };
242
- ```
243
-
244
- **3. 批量加载多个命名空间**:
245
-
246
- ```ts
247
- const sdkLoader: I18nSdkLoader = async options => {
248
- if (options.lng && options.nss) {
249
- const resources: Resources = {
250
- [options.lng]: {},
251
- };
252
- for (const ns of options.nss) {
253
- const response = await fetch(`/api/i18n/${options.lng}/${ns}`);
254
- resources[options.lng][ns] = await response.json();
255
- }
256
- return resources;
257
- }
258
- return {};
259
- };
260
- ```
261
-
262
- **4. 加载所有资源**:
263
-
264
- ```ts
265
- const sdkLoader: I18nSdkLoader = async options => {
266
- if (options.all) {
267
- const response = await fetch('/api/i18n/all');
268
- return await response.json();
269
- }
270
- return {};
271
- };
272
- ```
273
-
274
- ### 检查资源加载状态
275
-
276
- 使用 SDK 后端时,可以使用 `isResourcesReady` 检查资源是否已加载:
277
-
278
- ```tsx
279
- import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
280
-
281
- function MyComponent() {
282
- const { isResourcesReady } = useModernI18n();
283
-
284
- if (!isResourcesReady) {
285
- return <div>正在加载翻译资源...</div>;
286
- }
287
-
288
- return <div>资源已准备好!</div>;
103
+ lng?: string; // 单个语言代码
104
+ ns?: string; // 单个命名空间
105
+ lngs?: string[]; // 多个语言代码
106
+ nss?: string[]; // 多个命名空间
107
+ all?: boolean; // 加载所有资源
289
108
  }
290
109
  ```
291
110
 
292
- 这在资源异步加载时特别有用,因为它确保当前语言的所有必需命名空间都已加载完成,然后再渲染依赖翻译的内容。
293
-
294
- ## 链式后端(Chained Backend)
295
-
296
- 链式后端允许同时使用多个后端,实现资源的渐进式加载和更新。当同时配置 `loadPath`(或 FS 后端)和 `sdk` 时,插件会自动使用 `i18next-chained-backend` 来链式加载资源。
297
-
298
- ### 工作原理
299
-
300
- 链式后端的工作流程:
301
-
302
- 1. **初始加载**:首先从 HTTP/FS 后端加载资源并立即显示(快速显示基础翻译)
303
- 2. **异步更新**:然后从 SDK 后端异步加载资源并更新 i18next store(更新/补充翻译)
304
-
305
- 这样可以确保用户快速看到页面内容,同时后台加载最新的翻译资源。
306
-
307
- ### 配置方式
308
-
309
- **步骤 1:在 `modern.config.ts` 中配置链式后端**
310
-
311
- ```ts
312
- i18nPlugin({
313
- backend: {
314
- enabled: true,
315
- loadPath: '/locales/{{lng}}/{{ns}}.json', // HTTP/FS 后端
316
- sdk: true, // SDK 后端
317
- // cacheHitMode: 'refreshAndUpdateStore', // 默认值,可省略
318
- },
319
- });
320
- ```
321
-
322
- **步骤 2:在 `modern.runtime.ts` 中实现 SDK 函数**
323
-
324
- ```ts
325
- import { defineRuntimeConfig } from '@modern-js/runtime';
326
-
327
- export default defineRuntimeConfig({
328
- i18n: {
329
- initOptions: {
330
- backend: {
331
- sdk: async options => {
332
- // SDK 实现
333
- if (options.lng && options.ns) {
334
- return await mySdk.getResource(options.lng, options.ns);
335
- }
336
- },
337
- },
338
- },
339
- },
340
- });
341
- ```
342
-
343
- ### 缓存命中模式(cacheHitMode)
111
+ 使用自定义后端时,翻译资源需要异步加载,可以用 `isResourcesReady` 在加载完成前显示 loading 状态,用法见[最佳实践 → 加载状态处理](./best-practices.md#加载状态处理)。
344
112
 
345
- `cacheHitMode` 选项控制链式后端的行为:
113
+ ## 链式后端
346
114
 
347
- - **`'none'`**(默认,仅当未配置链式后端时):如果第一个后端返回了资源,则停止,不再尝试下一个后端
348
- - **`'refresh'`**:尝试从下一个后端刷新缓存并更新缓存
349
- - **`'refreshAndUpdateStore'`**(链式后端的默认值):尝试从下一个后端刷新缓存,更新缓存并同时更新 i18next 资源存储。这允许先显示 FS/HTTP 资源,然后 SDK 资源会异步更新它们。
115
+ 同时使用本地文件和自定义后端,实现「先快速显示本地翻译,再异步更新为最新翻译」:
350
116
 
351
- **配置示例**:
117
+ 1. 页面加载时,立即从本地文件加载翻译并显示
118
+ 2. 后台异步从自定义后端加载最新翻译,完成后自动更新页面
352
119
 
353
120
  ```ts
121
+ // modern.config.ts
354
122
  i18nPlugin({
355
123
  backend: {
356
- enabled: true,
357
- loadPath: '/locales/{{lng}}/{{ns}}.json',
358
- sdk: true,
359
- cacheHitMode: 'refreshAndUpdateStore', // 显式指定(默认值)
124
+ loadPath: '/locales/{{lng}}/{{ns}}.json', // 本地文件,快速显示
125
+ sdk: true, // 远程加载,异步更新
360
126
  },
361
127
  });
362
128
  ```
363
129
 
364
- ### 使用场景
365
-
366
- 链式后端特别适用于以下场景:
367
-
368
- 1. **渐进式加载**:先显示本地/静态资源,然后从远程服务加载最新翻译
369
- 2. **离线支持**:本地资源作为离线 fallback,SDK 资源提供在线更新
370
- 3. **性能优化**:快速显示基础翻译,后台加载完整翻译内容
371
- 4. **A/B 测试**:本地资源作为默认值,SDK 提供动态翻译变体
372
-
373
- ### 完整示例
374
-
375
130
  ```ts
376
- // modern.config.ts
377
- i18nPlugin({
378
- backend: {
379
- enabled: true,
380
- loadPath: '/locales/{{lng}}/{{ns}}.json', // 本地资源
381
- sdk: true, // 远程 SDK 资源
382
- cacheHitMode: 'refreshAndUpdateStore',
383
- },
384
- });
385
-
386
131
  // modern.runtime.ts
387
- import { defineRuntimeConfig } from '@modern-js/runtime';
388
-
389
132
  export default defineRuntimeConfig({
390
133
  i18n: {
391
134
  initOptions: {
392
135
  backend: {
393
136
  sdk: async options => {
394
137
  if (options.lng && options.ns) {
395
- // 从远程服务加载最新翻译
396
- const response = await fetch(
397
- `https://api.example.com/i18n/${options.lng}/${options.ns}`,
398
- );
399
- return {
400
- [options.lng]: {
401
- [options.ns]: await response.json(),
402
- },
403
- };
138
+ const res = await fetch(`https://api.example.com/i18n/${options.lng}/${options.ns}`);
139
+ return { [options.lng]: { [options.ns]: await res.json() } };
404
140
  }
405
141
  return {};
406
142
  },
@@ -410,8 +146,10 @@ export default defineRuntimeConfig({
410
146
  });
411
147
  ```
412
148
 
413
- 在这个示例中:
149
+ **`cacheHitMode` 选项**(控制两个后端之间的协作方式):
414
150
 
415
- - 页面加载时,首先从 `/locales/{{lng}}/{{ns}}.json` 加载资源并立即显示
416
- - 后台异步从 `https://api.example.com/i18n/...` 加载最新翻译
417
- - SDK 资源加载完成后,自动更新 i18next store,界面文案自动更新
151
+ | | 行为 |
152
+ | --- | --- |
153
+ | `'none'` | 本地文件加载成功后直接使用,不再请求自定义后端 |
154
+ | `'refresh'` | 继续请求自定义后端并更新缓存,但不更新当前页面 |
155
+ | `'refreshAndUpdateStore'` | 继续请求自定义后端,更新缓存并同步刷新页面文案(默认) |