@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,47 +4,43 @@ title: Resource Loading
4
4
 
5
5
  # Resource Loading
6
6
 
7
- The plugin supports three resource loading methods: HTTP backend, File System backend (FS Backend), and SDK backend. Additionally, the plugin supports chained backend, which allows combining multiple backends.
7
+ How translation files are loaded depends on where your translation resources are stored:
8
8
 
9
- ## HTTP Backend
9
+ | Scenario | Loading method |
10
+ | --- | --- |
11
+ | Translation files are local to the project | Static file backend (the default method in this guide) |
12
+ | Translations come from a remote API or translation platform | Custom backend |
13
+ | Both: local fallback + remote real-time updates | Chained backend |
10
14
 
11
- HTTP backend loads resource files through HTTP requests, suitable for client-side rendering (CSR) scenarios.
15
+ ## Static File Backend
12
16
 
13
- ### Configuration
17
+ Put translation files in your project and the plugin loads them directly. This is the most common approach.
14
18
 
15
- ```ts
16
- i18nPlugin({
17
- backend: {
18
- enabled: true,
19
- loadPath: '/locales/{{lng}}/{{ns}}.json',
20
- },
21
- });
22
- ```
19
+ **CSR and SSR use different loading mechanisms, but the configuration is exactly the same:**
20
+
21
+ - CSR: The browser fetches translation files through HTTP, such as `GET /locales/zh/translation.json`.
22
+ - SSR: The server reads files directly from disk without making HTTP requests.
23
23
 
24
- ### Resource File Structure
24
+ The plugin automatically chooses the right mechanism based on the runtime environment. You only need to configure `loadPath` once.
25
25
 
26
- Resource files need to be placed in the `config/public` directory or the directory configured through `server.publicDir`:
26
+ **Resource file location:**
27
27
 
28
28
  ```
29
- config/public/
30
- └── locales/
31
- ├── en/
32
- │ └── translation.json
33
- └── zh/
34
- └── translation.json
29
+ config/public/locales/ <- Default location. No extra configuration required.
30
+ ├── en/translation.json
31
+ └── zh/translation.json
35
32
  ```
36
33
 
37
- Or configure a custom directory through `server.publicDir`:
38
-
39
34
  ```ts
35
+ // modern.config.ts
40
36
  export default defineConfig({
41
- server: {
42
- publicDir: './locales', // Specify resource file directory
43
- },
44
37
  plugins: [
38
+ appTools(),
45
39
  i18nPlugin({
46
40
  backend: {
47
- enabled: true,
41
+ // `{{lng}}` is the language code, and `{{ns}}` is the namespace name.
42
+ // During SSR, the plugin automatically converts the leading `/` prefix
43
+ // to a relative path before reading the file. No extra handling is needed.
48
44
  loadPath: '/locales/{{lng}}/{{ns}}.json',
49
45
  },
50
46
  }),
@@ -52,115 +48,43 @@ export default defineConfig({
52
48
  });
53
49
  ```
54
50
 
55
- **Resource File Format**:
56
-
57
- ```json
58
- {
59
- "key1": "value1",
60
- "key2": "value2",
61
- "nested": {
62
- "key": "value"
63
- }
64
- }
65
- ```
66
-
67
- ### Path Variables
68
-
69
- `loadPath` supports the following variables:
70
-
71
- - `{{lng}}`: Language code (e.g., `en`, `zh`)
72
- - `{{ns}}`: Namespace (e.g., `translation`, `common`)
73
-
74
- **Examples**:
75
-
76
- ```ts
77
- // Default path format
78
- loadPath: '/locales/{{lng}}/{{ns}}.json';
79
- // Actual loading paths:
80
- // /locales/en/translation.json
81
- // /locales/zh/translation.json
82
-
83
- // Custom path format
84
- loadPath: '/i18n/{{lng}}/{{ns}}.json';
85
- // Actual loading paths:
86
- // /i18n/en/translation.json
87
- // /i18n/zh/translation.json
88
- ```
89
-
90
- ## File System Backend (FS Backend)
91
-
92
- File System backend reads resource files directly from the file system, suitable for server-side rendering (SSR) scenarios.
93
-
94
- ### Configuration
95
-
96
- In SSR scenarios, the plugin will automatically use the file system backend. Resource files need to be placed in the project directory:
97
-
98
- ```
99
- Project Root/
100
- └── locales/
101
- ├── en/
102
- │ └── translation.json
103
- └── zh/
104
- └── translation.json
105
- ```
106
-
107
- ### Resource File Path
108
-
109
- The default path format for file system backend is a relative path:
110
-
111
- ```
112
- ./locales/{{lng}}/{{ns}}.json
113
- ```
114
-
115
- You can customize the path through `loadPath`:
116
-
117
- ```ts
118
- i18nPlugin({
119
- backend: {
120
- enabled: true,
121
- loadPath: '/locales/{{lng}}/{{ns}}.json', // Use absolute path (recommended)
122
- },
123
- });
124
- ```
125
-
126
- :::warning
127
- The `loadPath` configuration is used for both HTTP backend (frontend) and file system backend (server-side). If configured as an absolute path starting with `/` (e.g., `/locales/{{lng}}/{{ns}}.json`), the file system backend will automatically convert it to a relative path (`./locales/{{lng}}/{{ns}}.json`). Therefore, it's recommended to use absolute paths in the configuration, which can meet both frontend and backend requirements.
128
-
129
- :::
51
+ To store files in another directory, configure `server.publicDir`. The relationship between **`server.publicDir` and `backend.loadPath`** is:
130
52
 
131
- ## SDK Backend
53
+ - `server.publicDir`: Decides which local directory is exposed as static assets, that is, where files are placed.
54
+ - `backend.loadPath`: Decides which URL i18next requests for translation files, or which path the server reads from.
132
55
 
133
- SDK backend allows loading resources through custom functions, suitable for scenarios where translation resources need to be loaded from external services, databases, or other custom sources.
56
+ ## Custom Backend
134
57
 
135
- ### Enable SDK Mode
58
+ When translation resources are not local files but come from a remote API, database, or translation platform, load them with an async function.
136
59
 
137
- **Step 1: Enable SDK mode in `modern.config.ts`**
60
+ **Step 1: declare it enabled in `modern.config.ts`**
138
61
 
139
62
  ```ts
140
63
  i18nPlugin({
141
64
  backend: {
142
- enabled: true,
143
- sdk: true, // Enable SDK mode
65
+ sdk: true,
144
66
  },
145
67
  });
146
68
  ```
147
69
 
148
- **Step 2: Implement SDK function in `modern.runtime.ts`**
70
+ **Step 2: implement the loader function in `modern.runtime.ts`**
149
71
 
150
72
  ```ts
151
73
  import { defineRuntimeConfig } from '@modern-js/runtime';
152
- import type { I18nSdkLoader, Resources } from '@modern-js/plugin-i18n/runtime';
74
+ import type { I18nSdkLoader } from '@modern-js/plugin-i18n/runtime';
153
75
 
154
- const mySdkLoader: I18nSdkLoader = async options => {
155
- // Implement resource loading logic
156
- if (options.all) {
157
- // Load all resources
158
- return await loadAllResources();
76
+ const myLoader: I18nSdkLoader = async options => {
77
+ // Most common case: load a single resource by language + namespace.
78
+ if (options.lng && options.ns) {
79
+ const res = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
80
+ const data = await res.json();
81
+ return { [options.lng]: { [options.ns]: data } };
159
82
  }
160
83
 
161
- if (options.lng && options.ns) {
162
- // Load single resource
163
- return await loadSingleResource(options.lng, options.ns);
84
+ // Load all resources at once.
85
+ if (options.all) {
86
+ const res = await fetch('/api/i18n/all');
87
+ return res.json(); // Format: { en: { translation: {...} }, zh: { translation: {...} } }
164
88
  }
165
89
 
166
90
  return {};
@@ -169,238 +93,53 @@ const mySdkLoader: I18nSdkLoader = async options => {
169
93
  export default defineRuntimeConfig({
170
94
  i18n: {
171
95
  initOptions: {
172
- backend: {
173
- sdk: mySdkLoader,
174
- },
96
+ backend: { sdk: myLoader },
175
97
  },
176
98
  },
177
99
  });
178
100
  ```
179
101
 
180
- ### Implement SDK Loader Function
181
-
182
- The SDK function receives an `I18nSdkLoadOptions` parameter and needs to return data in `Resources` format:
102
+ **Loader parameter type:**
183
103
 
184
104
  ```ts
185
105
  interface I18nSdkLoadOptions {
186
- /** Single language code */
187
- lng?: string;
188
- /** Single namespace */
189
- ns?: string;
190
- /** Multiple language codes */
191
- lngs?: string[];
192
- /** Multiple namespaces */
193
- nss?: string[];
194
- /** Load all resources */
195
- all?: boolean;
106
+ lng?: string; // Single language code
107
+ ns?: string; // Single namespace
108
+ lngs?: string[]; // Multiple language codes
109
+ nss?: string[]; // Multiple namespaces
110
+ all?: boolean; // Load all resources
196
111
  }
197
-
198
- type Resources = {
199
- [lng: string]: {
200
- [ns: string]: Record<string, string>;
201
- };
202
- };
203
- ```
204
-
205
- ### Batch Loading Examples
206
-
207
- SDK backend supports multiple loading modes:
208
-
209
- **1. Load single resource**:
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
112
  ```
225
113
 
226
- **2. Batch load multiple languages**:
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. Batch load multiple namespaces**:
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. Load all resources**:
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
- ### Check Resource Loading State
275
-
276
- When using SDK backend, you can check if resources are loaded using `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>Loading translation resources...</div>;
286
- }
287
-
288
- return <div>Resources are ready!</div>;
289
- }
290
- ```
291
-
292
- This is particularly useful when resources are loaded asynchronously, as it ensures all required namespaces for the current language are loaded before rendering content that depends on translations.
114
+ When using a custom backend, translation resources are loaded asynchronously. You can use `isResourcesReady` to show a loading state before loading is complete. See [Best Practices -> Loading State Handling](./best-practices.md#loading-state-handling).
293
115
 
294
116
  ## Chained Backend
295
117
 
296
- Chained backend allows using multiple backends simultaneously, enabling progressive resource loading and updates. When both `loadPath` (or FS backend) and `sdk` are configured, the plugin automatically uses `i18next-chained-backend` to chain resource loading.
297
-
298
- ### How It Works
299
-
300
- The chained backend workflow:
301
-
302
- 1. **Initial Load**: First load resources from HTTP/FS backend and display immediately (quick display of basic translations)
303
- 2. **Async Update**: Then asynchronously load resources from SDK backend and update the i18next store (update/supplement translations)
304
-
305
- This ensures users see page content quickly while the latest translation resources are loaded in the background.
306
-
307
- ### Configuration
308
-
309
- **Step 1: Configure chained backend in `modern.config.ts`**
310
-
311
- ```ts
312
- i18nPlugin({
313
- backend: {
314
- enabled: true,
315
- loadPath: '/locales/{{lng}}/{{ns}}.json', // HTTP/FS backend
316
- sdk: true, // SDK backend
317
- // cacheHitMode: 'refreshAndUpdateStore', // Default value, can be omitted
318
- },
319
- });
320
- ```
118
+ Use local files and a custom backend together to implement "show local translations quickly first, then update asynchronously with the latest translations":
321
119
 
322
- **Step 2: Implement SDK function in `modern.runtime.ts`**
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 implementation
333
- if (options.lng && options.ns) {
334
- return await mySdk.getResource(options.lng, options.ns);
335
- }
336
- },
337
- },
338
- },
339
- },
340
- });
341
- ```
342
-
343
- ### Cache Hit Mode (cacheHitMode)
344
-
345
- The `cacheHitMode` option controls the behavior of chained backend:
346
-
347
- - **`'none'`** (default, only when chained backend is not configured): If the first backend returns resources, stop and don't try the next backend
348
- - **`'refresh'`**: Try to refresh the cache by loading from the next backend and update the cache
349
- - **`'refreshAndUpdateStore'`** (default for chained backend): Try to refresh the cache by loading from the next backend, update the cache and also update the i18next resource store. This allows FS/HTTP resources to be displayed first, then SDK resources will update them asynchronously.
350
-
351
- **Configuration example**:
120
+ 1. When the page loads, translations are loaded from local files and displayed immediately.
121
+ 2. The custom backend loads the latest translations asynchronously in the background. After it completes, the page updates automatically.
352
122
 
353
123
  ```ts
124
+ // modern.config.ts
354
125
  i18nPlugin({
355
126
  backend: {
356
- enabled: true,
357
- loadPath: '/locales/{{lng}}/{{ns}}.json',
358
- sdk: true,
359
- cacheHitMode: 'refreshAndUpdateStore', // Explicitly specify (default value)
127
+ loadPath: '/locales/{{lng}}/{{ns}}.json', // Local files, fast display
128
+ sdk: true, // Remote loading, async update
360
129
  },
361
130
  });
362
131
  ```
363
132
 
364
- ### Use Cases
365
-
366
- Chained backend is particularly suitable for the following scenarios:
367
-
368
- 1. **Progressive Loading**: Display local/static resources first, then load latest translations from remote services
369
- 2. **Offline Support**: Local resources as offline fallback, SDK resources provide online updates
370
- 3. **Performance Optimization**: Quickly display basic translations, load complete translation content in the background
371
- 4. **A/B Testing**: Local resources as default values, SDK provides dynamic translation variants
372
-
373
- ### Complete Example
374
-
375
133
  ```ts
376
- // modern.config.ts
377
- i18nPlugin({
378
- backend: {
379
- enabled: true,
380
- loadPath: '/locales/{{lng}}/{{ns}}.json', // Local resources
381
- sdk: true, // Remote SDK resources
382
- cacheHitMode: 'refreshAndUpdateStore',
383
- },
384
- });
385
-
386
134
  // modern.runtime.ts
387
- import { defineRuntimeConfig } from '@modern-js/runtime';
388
-
389
135
  export default defineRuntimeConfig({
390
136
  i18n: {
391
137
  initOptions: {
392
138
  backend: {
393
139
  sdk: async options => {
394
140
  if (options.lng && options.ns) {
395
- // Load latest translations from remote service
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
- };
141
+ const res = await fetch(`https://api.example.com/i18n/${options.lng}/${options.ns}`);
142
+ return { [options.lng]: { [options.ns]: await res.json() } };
404
143
  }
405
144
  return {};
406
145
  },
@@ -410,8 +149,10 @@ export default defineRuntimeConfig({
410
149
  });
411
150
  ```
412
151
 
413
- In this example:
152
+ **`cacheHitMode` option** (controls how the two backends cooperate):
414
153
 
415
- - When the page loads, resources are first loaded from `/locales/{{lng}}/{{ns}}.json` and displayed immediately
416
- - Latest translations are loaded asynchronously from `https://api.example.com/i18n/...` in the background
417
- - After SDK resources are loaded, the i18next store is automatically updated, and the UI text is automatically updated
154
+ | Value | Behavior |
155
+ | --- | --- |
156
+ | `'none'` | Use local files after a successful local hit and do not request the custom backend |
157
+ | `'refresh'` | Continue requesting the custom backend and update cache, but do not update the current page |
158
+ | `'refreshAndUpdateStore'` | Continue requesting the custom backend, update cache, and refresh page text (default) |