@intlayer/docs 8.12.2 → 8.12.4-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.
Files changed (73) hide show
  1. package/dist/cjs/blog.cjs.map +1 -1
  2. package/dist/cjs/common.cjs.map +1 -1
  3. package/dist/cjs/doc.cjs.map +1 -1
  4. package/dist/cjs/frequentQuestions.cjs.map +1 -1
  5. package/dist/cjs/generated/blog.entry.cjs +1 -0
  6. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  7. package/dist/cjs/generated/docs.entry.cjs +1 -0
  8. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  9. package/dist/cjs/generated/frequentQuestions.entry.cjs +1 -0
  10. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  11. package/dist/cjs/generated/legal.entry.cjs +1 -0
  12. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  13. package/dist/cjs/legal.cjs.map +1 -1
  14. package/dist/esm/blog.mjs.map +1 -1
  15. package/dist/esm/common.mjs.map +1 -1
  16. package/dist/esm/doc.mjs.map +1 -1
  17. package/dist/esm/frequentQuestions.mjs.map +1 -1
  18. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  19. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  20. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  21. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  22. package/dist/esm/legal.mjs.map +1 -1
  23. package/dist/types/blog.d.ts.map +1 -1
  24. package/dist/types/common.d.ts.map +1 -1
  25. package/dist/types/doc.d.ts.map +1 -1
  26. package/dist/types/frequentQuestions.d.ts.map +1 -1
  27. package/dist/types/legal.d.ts.map +1 -1
  28. package/docs/ar/bundle_optimization.md +250 -102
  29. package/docs/ar/configuration.md +10 -10
  30. package/docs/bn/bundle_optimization.md +252 -104
  31. package/docs/bn/configuration.md +10 -10
  32. package/docs/cs/bundle_optimization.md +253 -105
  33. package/docs/cs/configuration.md +10 -10
  34. package/docs/de/bundle_optimization.md +245 -97
  35. package/docs/de/configuration.md +10 -10
  36. package/docs/en/bundle_optimization.md +172 -49
  37. package/docs/en/configuration.md +10 -10
  38. package/docs/en-GB/bundle_optimization.md +230 -82
  39. package/docs/en-GB/configuration.md +10 -10
  40. package/docs/es/bundle_optimization.md +250 -102
  41. package/docs/es/configuration.md +10 -10
  42. package/docs/fr/bundle_optimization.md +223 -75
  43. package/docs/fr/configuration.md +10 -10
  44. package/docs/hi/bundle_optimization.md +253 -105
  45. package/docs/hi/configuration.md +10 -10
  46. package/docs/id/bundle_optimization.md +258 -110
  47. package/docs/id/configuration.md +10 -10
  48. package/docs/it/bundle_optimization.md +249 -103
  49. package/docs/it/configuration.md +10 -10
  50. package/docs/ja/bundle_optimization.md +245 -97
  51. package/docs/ja/configuration.md +10 -10
  52. package/docs/ko/bundle_optimization.md +253 -105
  53. package/docs/ko/configuration.md +10 -10
  54. package/docs/nl/bundle_optimization.md +249 -101
  55. package/docs/nl/configuration.md +10 -10
  56. package/docs/pl/bundle_optimization.md +258 -111
  57. package/docs/pl/configuration.md +10 -10
  58. package/docs/pt/bundle_optimization.md +256 -115
  59. package/docs/pt/configuration.md +10 -10
  60. package/docs/ru/bundle_optimization.md +253 -105
  61. package/docs/ru/configuration.md +10 -10
  62. package/docs/tr/bundle_optimization.md +255 -107
  63. package/docs/tr/configuration.md +10 -10
  64. package/docs/uk/bundle_optimization.md +250 -102
  65. package/docs/uk/configuration.md +10 -10
  66. package/docs/ur/bundle_optimization.md +257 -109
  67. package/docs/ur/configuration.md +10 -10
  68. package/docs/vi/bundle_optimization.md +259 -111
  69. package/docs/vi/configuration.md +10 -10
  70. package/docs/zh/bundle_optimization.md +260 -112
  71. package/docs/zh/configuration.md +10 -10
  72. package/docs/zh-TW/bundle_optimization.md +602 -0
  73. package/package.json +8 -8
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  createdAt: 2025-11-25
3
- updatedAt: 2026-04-08
4
- title: Optimising i18n Bundle Size & Performance
5
- description: Reduce application bundle size by optimising internationalisation (i18n) content. Learn how to leverage tree shaking and lazy loading for dictionaries with Intlayer.
3
+ updatedAt: 2026-06-07
4
+ title: i18n Bundle Size & Performance Optimisation
5
+ description: Reduce your application bundle size by optimising internationalisation (i18n) content. Learn how to leverage tree shaking and lazy loading for dictionaries with Intlayer.
6
6
  keywords:
7
7
  - Bundle Optimisation
8
8
  - Content Automation
@@ -16,33 +16,36 @@ slugs:
16
16
  - concept
17
17
  - bundle-optimization
18
18
  history:
19
+ - version: 8.12.0
20
+ date: 2026-06-07
21
+ changes: "Added `intlayerPurgeBabelPlugin` and `intlayerMinifyBabelPlugin` for Babel/Webpack; clarified the plugin pipeline"
19
22
  - version: 8.7.0
20
23
  date: 2026-04-08
21
- changes: "Add `minify` and `purge` options to the build configuration"
24
+ changes: "Added `minify` and `purge` options to build configuration"
22
25
  ---
23
26
 
24
- # Optimising i18n Bundle Size & Performance
27
+ # i18n Bundle Size & Performance Optimisation
25
28
 
26
- One of the most common challenges with traditional i18n solutions relying on JSON files is managing content size. If developers do not manually separate content into namespaces, users often end up downloading translations for every page and potentially every language just to view a single page.
29
+ One of the most common challenges with traditional i18n solutions relying on JSON files is managing content size. If developers do not manually separate content into namespaces, users often end up downloading the translations for every page and potentially every language just to view a single page.
27
30
 
28
- For example, an application with 10 pages translated into 10 languages might result in a user downloading the content of 100 pages, even though they only need **one** (the current page in the current language). This leads to wasted bandwidth and slower load times.
31
+ For example, an application with 10 pages translated into 10 languages could result in a user downloading 100 pages' worth of content, even though they only need **one** (the current page in the current language). This leads to wasted bandwidth and slower load times.
29
32
 
30
- **Intlayer solves this problem through build-time optimisation.** It analyses your code to detect which dictionaries are actually used per component and reinjects only the necessary content into your bundle.
33
+ **Intlayer solves this problem through build-time optimisation.** It analyses your code to detect exactly which dictionaries are actually used per component and re-injects only the necessary content into your bundle.
31
34
 
32
35
  ## Table of Contents
33
36
 
34
37
  <TOC />
35
38
 
36
- ## Scan your bundle
39
+ ## Analyse your bundle
37
40
 
38
- Analysing your bundle is the first step in identifying "heavy" JSON files and code-splitting opportunities. These tools generate a visual treemap of your application's compiled code, allowing you to see exactly which libraries are consuming the most space.
41
+ Analysing your bundle is the first step to identifying "heavy" JSON files and opportunities for code-splitting. These tools generate a visual treemap of your application's compiled code, allowing you to see exactly which libraries are taking up the most space.
39
42
 
40
43
  <Tabs>
41
44
  <Tab value="vite">
42
45
 
43
46
  ### Vite / Rollup
44
47
 
45
- Vite uses Rollup under the hood. The `rollup-plugin-visualizer` generates an interactive HTML file showing the size of every module in your graph.
48
+ Vite uses Rollup under the hood. The `rollup-plugin-visualizer` generates an interactive HTML file showing the size of each module in your graph.
46
49
 
47
50
  ```bash
48
51
  npm install -D rollup-plugin-visualizer
@@ -69,7 +72,7 @@ export default defineConfig({
69
72
 
70
73
  ### Next.js (Turbopack)
71
74
 
72
- For projects using the App Router and Turbopack, Next.js provides a built-in experimental analyser that requires no extra dependencies.
75
+ For projects using the App Router and Turbopack, Next.js provides a built-in, experimental analyser that requires no extra dependencies.
73
76
 
74
77
  ```bash packageManager='npm'
75
78
  npx next experimental-analyze
@@ -131,7 +134,7 @@ ANALYZE=true npm run build
131
134
 
132
135
  ### Standard Webpack
133
136
 
134
- For Create React App (ejected), Angular, or custom Webpack setups, use the industry-standard `webpack-bundle-analyzer`.
137
+ For Create React App (ejected), Angular, or custom Webpack setups, use the industry standard `webpack-bundle-analyzer`.
135
138
 
136
139
  ```bash packageManager='npm'
137
140
  npm install -D webpack-bundle-analyzer
@@ -149,7 +152,7 @@ pnpm add -D webpack-bundle-analyzer
149
152
  bun add -d webpack-bundle-analyzer
150
153
  ```
151
154
 
152
- ```typescript fileName="webpack.config.ts
155
+ ```typescript fileName="webpack.config.ts"
153
156
  import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
154
157
 
155
158
  export default {
@@ -166,19 +169,56 @@ export default {
166
169
  </Tab>
167
170
  </Tabs>
168
171
 
169
- ## How It Works
172
+ ## How it works
170
173
 
171
- Intlayer uses a **per-component approach**. Unlike global JSON files, your content is defined alongside or within your components. During the build process, Intlayer:
174
+ Intlayer uses a **per-component approach**. Unlike global JSON files, your content is defined alongside or within your components. During the build process, Intlayer will:
172
175
 
173
- 1. **Analyses** your code to find `useIntlayer` calls.
174
- 2. **Builds** the corresponding dictionary content.
175
- 3. **Replaces** the `useIntlayer` call with optimised code based on your configuration.
176
+ 1. **Analyse** your code to find `useIntlayer` calls.
177
+ 2. **Build** the corresponding dictionary content.
178
+ 3. **Replace** the `useIntlayer` call with optimised code based on your configuration.
176
179
 
177
180
  This ensures that:
178
181
 
179
182
  - If a component is not imported, its content is not included in the bundle (Dead Code Elimination).
180
183
  - If a component is lazy-loaded, its content is also lazy-loaded.
181
184
 
185
+ ## Plugin Reference
186
+
187
+ Intlayer's build optimisation is split into several discrete plugins, each with a single responsibility. Understanding what each one does prevents confusion when configuring them.
188
+
189
+ ### Babel plugins (`@intlayer/babel`)
190
+
191
+ These are used directly in `babel.config.js` for Webpack-based setups (Next.js with Babel, CRA, custom Webpack, etc).
192
+
193
+ | Plugin | What it does |
194
+ | :---------------------------- | :------------------------------------------------------------------------------------------------------------------ |
195
+ | `intlayerExtractBabelPlugin` | Scans `.content.ts` files and writes compiled dictionaries to `.intlayer/` |
196
+ | `intlayerOptimizeBabelPlugin` | Rewrites `useIntlayer('key')` → `useDictionary(hash)` and injects the matching dictionary `import` |
197
+ | `intlayerPurgeBabelPlugin` | Scans all source files, removes **unused content fields** from the compiled `.intlayer/**/*.json` dictionary files |
198
+ | `intlayerMinifyBabelPlugin` | **Renames content field keys** to short alphabetical aliases (`title` → `a`) in both JSON files and the source code |
199
+
200
+ > **Plugin order matters.** In your `babel.config.js` the purge and minify plugins must appear **before** the optimize plugin. The optimize pass replaces `useIntlayer('key')` with an opaque `useDictionary(hash)` call, wiping out the dictionary key information the purge and minify passes need to identify which fields are used.
201
+
202
+ Each Babel plugin has a corresponding options helper that reads your `intlayer.config.ts` once at config load time and returns pre-resolved values:
203
+
204
+ | Options helper | Used with |
205
+ | :--------------------------- | :---------------------------- |
206
+ | `getExtractPluginOptions()` | `intlayerExtractBabelPlugin` |
207
+ | `getOptimizePluginOptions()` | `intlayerOptimizeBabelPlugin` |
208
+ | `getPurgePluginOptions()` | `intlayerPurgeBabelPlugin` |
209
+ | `getMinifyPluginOptions()` | `intlayerMinifyBabelPlugin` |
210
+
211
+ ### Vite plugins (`vite-intlayer`)
212
+
213
+ Vite users **never configure these directly**. They are wired up automatically when you call `withIntlayer()` in `vite.config.ts`. The `build.purge` and `build.minify` flags in `intlayer.config.ts` toggle the corresponding behaviour without any extra plugin registration.
214
+
215
+ | Internal Vite plugin | Equivalent behaviour |
216
+ | :------------------- | :------------------------------------------------------------------------------------- |
217
+ | Usage analyzer | Same as `intlayerPurgeBabelPlugin` analyse pass |
218
+ | Dictionary prune | Same as `intlayerPurgeBabelPlugin` JSON write pass |
219
+ | Dictionary minify | Same as `intlayerMinifyBabelPlugin` JSON write pass |
220
+ | Babel transform | Same as `intlayerMinifyBabelPlugin` source code rename + `intlayerOptimizeBabelPlugin` |
221
+
182
222
  ## Setup by Platform
183
223
 
184
224
  <Tabs>
@@ -186,9 +226,9 @@ This ensures that:
186
226
 
187
227
  ### Next.js
188
228
 
189
- Next.js requires the `@intlayer/swc` plugin to handle the transformation, as Next.js uses SWC for builds.
229
+ Next.js requires the `@intlayer/swc` plugin for the optimise (import rewrite) pass, because Next.js uses SWC for builds.
190
230
 
191
- > This plugin is not installed by default because SWC plugins are still experimental for Next.js. It may change in the future.
231
+ > This plugin is not installed by default as SWC plugins are still experimental for Next.js. This may change in the future.
192
232
 
193
233
  ```bash packageManager="npm"
194
234
  npm install -D @intlayer/swc
@@ -206,21 +246,63 @@ pnpm add -D @intlayer/swc
206
246
  bun add -d @intlayer/swc
207
247
  ```
208
248
 
209
- Once Installed. Intlayer will automatically detect and use the plugin.
249
+ Once installed, Intlayer will automatically detect and use the plugin.
250
+
251
+ For the **purge and minify** passes (field removal and field rename), install `@intlayer/babel` alongside it and add the Babel plugins. Because Next.js uses SWC for transformation but still evaluates `babel.config.js` for plugin config, the Babel plugins run as a pre-pass before SWC.
252
+
253
+ ```bash packageManager="npm"
254
+ npm install -D @intlayer/babel
255
+ ```
256
+
257
+ ```javascript fileName="babel.config.js"
258
+ const {
259
+ intlayerPurgeBabelPlugin,
260
+ intlayerMinifyBabelPlugin,
261
+ getPurgePluginOptions,
262
+ getMinifyPluginOptions,
263
+ } = require("@intlayer/babel");
264
+
265
+ module.exports = {
266
+ presets: ["next/babel"],
267
+ plugins: [
268
+ // Purge: remove unused content fields from .intlayer/**/*.json
269
+ [intlayerPurgeBabelPlugin, getPurgePluginOptions()],
270
+ // Minify: rename content field keys in JSON + source code
271
+ [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],
272
+ // Note: intlayerOptimizeBabelPlugin is NOT needed here because
273
+ // @intlayer/swc handles the useIntlayer → useDictionary rewrite.
274
+ ],
275
+ };
276
+ ```
210
277
 
211
278
  </Tab>
212
279
  <Tab value="vite">
213
280
 
214
281
  ### Vite
215
282
 
216
- Vite uses `@intlayer/babel` plugin which is included as dependency of `vite-intlayer`. The optimisation is enabled by default. Nothing else to do.
283
+ Vite uses the `@intlayer/babel` plugin, which is included as a dependency of `vite-intlayer`. The full optimisation pipeline — import rewrite, purge, and minify — is enabled by default and requires no extra plugin registration.
284
+
285
+ Enable purge and minify by setting the corresponding flags in `intlayer.config.ts`:
286
+
287
+ ```typescript fileName="intlayer.config.ts"
288
+ import type { IntlayerConfig } from "intlayer";
289
+
290
+ const config: IntlayerConfig = {
291
+ build: {
292
+ purge: true, // remove unused content fields from bundled JSON
293
+ minify: true, // rename content field keys to short aliases
294
+ },
295
+ };
296
+
297
+ export default config;
298
+ ```
217
299
 
218
300
  </Tab>
219
301
  <Tab value="webpack">
220
302
 
221
- ### Webpack
303
+ ### Webpack (and Next.js with Babel)
222
304
 
223
- To enable bundle optimisation with Intlayer on Webpack, you need to install and configure the appropriate Babel (`@intlayer/babel`) or SWC (`@intlayer/swc`) plugin.
305
+ Install `@intlayer/babel`:
224
306
 
225
307
  ```bash packageManager="npm"
226
308
  npm install -D @intlayer/babel
@@ -238,14 +320,37 @@ pnpm add -D @intlayer/babel
238
320
  bun add -d @intlayer/babel
239
321
  ```
240
322
 
241
- ```typescript fileName="babel.config.js"
323
+ Add all four plugins to `babel.config.js` in the correct order:
324
+
325
+ ```javascript fileName="babel.config.js"
242
326
  const {
243
- getOptimizePluginOptions,
327
+ intlayerExtractBabelPlugin,
328
+ intlayerPurgeBabelPlugin,
329
+ intlayerMinifyBabelPlugin,
244
330
  intlayerOptimizeBabelPlugin,
331
+ getExtractPluginOptions,
332
+ getPurgePluginOptions,
333
+ getMinifyPluginOptions,
334
+ getOptimizePluginOptions,
245
335
  } = require("@intlayer/babel");
246
336
 
247
337
  module.exports = {
248
- plugins: [[intlayerOptimizeBabelPlugin, getOptimizePluginOptions()]],
338
+ plugins: [
339
+ // Extract: compile .content.ts files → .intlayer/**/*.json
340
+ [intlayerExtractBabelPlugin, getExtractPluginOptions()],
341
+
342
+ // Purge: remove unused fields from .intlayer/**/*.json
343
+ // (reads the intlayer.config.ts build.purge flag)
344
+ [intlayerPurgeBabelPlugin, getPurgePluginOptions()],
345
+
346
+ // Minify: rename field keys in JSON + source code
347
+ // (reads the intlayer.config.ts build.minify flag)
348
+ [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],
349
+
350
+ // Optimize: rewrite useIntlayer('key') → useDictionary(hash)
351
+ // Must come last because it erases the dictionary key.
352
+ [intlayerOptimizeBabelPlugin, getOptimizePluginOptions()],
353
+ ],
249
354
  };
250
355
  ```
251
356
 
@@ -268,43 +373,48 @@ const config: IntlayerConfig = {
268
373
  importMode: "dynamic",
269
374
  },
270
375
  build: {
271
- /**
272
- * Minify the dictionaries to reduce the bundle size.
273
- */
274
- minify: true;
275
-
276
- /**
277
- * Purge the unused keys in a dictionaries
278
- */
279
- purge: true;
280
-
281
- /**
282
- * Indicates if the build should check TypeScript types
283
- */
284
- checkTypes: false;
376
+ // Replace useIntlayer() calls with direct dictionary imports at build-time.
377
+ // undefined = auto (enabled in production), true = always, false = never.
378
+ optimize: undefined,
379
+
380
+ // Rename content field keys in compiled dictionaries to short alphabetical
381
+ // aliases (e.g. title → a). Reduces JSON size; requires optimize.
382
+ minify: true,
383
+
384
+ // Remove content fields that are never accessed in the source code.
385
+ // Requires optimize.
386
+ purge: true,
285
387
  },
286
388
  };
287
389
 
288
390
  export default config;
289
391
  ```
290
392
 
291
- > Keeping the default option for `optimize` is recommended in the most majority of cases.
393
+ > It is recommended to keep the default value (`undefined`) for `optimize` in most cases.
292
394
 
293
- > See doc configuration for more details: [Configuration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/configuration.md)
395
+ > See the configuration reference for all options: [Configuration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/configuration.md)
294
396
 
295
397
  ### Build Options
296
398
 
297
- The following options are available under the `build` configuration object:
399
+ | Property | Type | Default | Description |
400
+ | :------------- | :--------------------- | :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
401
+ | **`optimize`** | `boolean \| undefined` | `undefined` | Enables the import rewrite pass. `undefined` = active in production builds only. `false` disables purge and minify as well. |
402
+ | **`minify`** | `boolean` | `false` | Renames content field keys in compiled JSON files to short alphabetical aliases. Rewrites matching property accesses in the source code as well. Has no effect when `optimize` is `false`. |
403
+ | **`purge`** | `boolean` | `false` | Removes content fields that are never statically accessed in the source code from the compiled JSON files. Has no effect when `optimize` is `false`. |
298
404
 
299
- | Property | Type | Default | Description |
300
- | :------------- | :-------- | :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
301
- | **`optimize`** | `boolean` | `undefined` | Controls whether build optimisation is enabled. If `true`, Intlayer replaces dictionary calls with optimised injects. If `false`, optimisation is disabled. Ideally set to `true` in production. |
302
- | **`minify`** | `boolean` | `false` | Whether to minify the dictionaries to reduce the bundle size. |
303
- | **`purge`** | `boolean" | `false` | Whether to purge the unused keys in dictionaries. |
405
+ ### Minification (field key rename)
304
406
 
305
- ### Minification
407
+ `build.minify` does **not** minify your JavaScript bundle — your bundler handles that. Instead, it shrinks the compiled dictionary JSON files by replacing every user-defined content field key with a short alphabetical alias:
306
408
 
307
- Minifying dictionaries removes unnecessary whitespace, comments, and reduces the size of the JSON content. This is especially useful for large dictionaries.
409
+ ```
410
+ // Before minification
411
+ { "title": "Hello", "subtitle": "World" }
412
+
413
+ // After minification
414
+ { "a": "Hello", "b": "World" }
415
+ ```
416
+
417
+ The same rename is applied to all property accesses in your source code, so `content.title` becomes `content.a` in the compiled output. The runtime behaviour is identical.
308
418
 
309
419
  ```typescript fileName="intlayer.config.ts"
310
420
  import type { IntlayerConfig } from "intlayer";
@@ -318,11 +428,13 @@ const config: IntlayerConfig = {
318
428
  export default config;
319
429
  ```
320
430
 
321
- > Note: Minification is ignored if `optimize` is disabled or if the Visual Editor is enabled (as the editor needs the full content to allow editing).
431
+ > Minification is skipped when `optimize` is `false` or when `editor.enabled` is `true` (the visual editor requires the original field names to allow editing).
432
+
433
+ > Minification is also skipped for dictionaries loaded via `importMode: 'fetch'` because their JSON is served from a remote API using the original field names — renaming the client-side keys would break the server/client contract.
322
434
 
323
- ### Purging
435
+ ### Purging (unused field removal)
324
436
 
325
- Purging ensures that only the keys actually used in your code are included in the final dictionary bundle. This can significantly reduce the size of your bundle if you have large dictionaries with many keys that are not used in every part of your application.
437
+ `build.purge` analyses which content fields are actually accessed in your source code and removes all others from the compiled JSON files.
326
438
 
327
439
  ```typescript fileName="intlayer.config.ts"
328
440
  import type { IntlayerConfig } from "intlayer";
@@ -336,27 +448,43 @@ const config: IntlayerConfig = {
336
448
  export default config;
337
449
  ```
338
450
 
339
- > Note: Purging is ignored if `optimize` is disabled.
451
+ **Example:** a dictionary with five fields where only two are used:
452
+
453
+ ```
454
+ // Before purge
455
+ { "title": "…", "subtitle": "…", "cta": "…", "footer": "…", "badge": "…" }
456
+
457
+ // After purge (only title + subtitle accessed in source)
458
+ { "title": "…", "subtitle": "…" }
459
+ ```
460
+
461
+ > Purge is skipped when `optimize` is `false` or when `editor.enabled` is `true`.
462
+
463
+ > Purge is also conservatively skipped when a source file cannot be parsed, or when the result of `useIntlayer` is assigned to a variable and passed around in ways the static analyser cannot track (e.g. spread into an object, passed as a prop without destructuring). In those cases, the full dictionary is preserved.
340
464
 
341
465
  ### Import Mode
342
466
 
343
- For large applications, including several pages and locales, your JSON can represent a significant part of your bundle size. Intlayer allows you to control how dictionaries are loaded.
467
+ For large applications, including several pages and locales, your JSON can represent an important part of your bundle size. Intlayer allows you to control how dictionaries are loaded using the `importMode` option.
468
+
469
+ ### Global definition
344
470
 
345
- The import mode can be defined by default globally in your `intlayer.config.ts` file.
471
+ The import mode can be defined globally in your `intlayer.config.ts` file.
346
472
 
347
473
  ```typescript fileName="intlayer.config.ts"
348
474
  import type { IntlayerConfig } from "intlayer";
349
475
 
350
476
  const config: IntlayerConfig = {
351
- build: {
352
- minify: true,
477
+ dictionary: {
478
+ importMode: "dynamic", // Default is 'static'
353
479
  },
354
480
  };
355
481
 
356
482
  export default config;
357
483
  ```
358
484
 
359
- As well as for each dictionaries in your `.content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5}}` files.
485
+ ### Per-dictionary definition
486
+
487
+ You can override the import mode for individual dictionaries in their `.content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5|md|mdx|yaml|yml}}` files.
360
488
 
361
489
  ```ts
362
490
  import { type Dictionary, t } from "intlayer";
@@ -372,28 +500,28 @@ const appContent: Dictionary = {
372
500
  export default appContent;
373
501
  ```
374
502
 
375
- | Property | Type | Default | Description |
376
- | :--------------- | :--------------------------------- | :--------- | :--------------------------------------------------------------------------------------------------------------- |
377
- | **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Deprecated**: Use `dictionary.importMode` instead. Determines how dictionaries are loaded (see details below). |
503
+ | Property | Type | Default | Description |
504
+ | :--------------- | :--------------------------------- | :--------- | :------------------------------------------------------------------------------------------------------- |
505
+ | **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Deprecated**: Use `dictionary.importMode` instead. Determines how dictionaries are loaded (see below). |
378
506
 
379
- The `importMode` setting dictates how the dictionary content is injected into your component.
380
- You can define it globally in the `intlayer.config.ts` file under the `dictionary` object, or you can overwrite it for a specific dictionary in its `.content.ts` file.
507
+ The `importMode` setting determines how the dictionary's content is injected into your component. You can define it globally in `intlayer.config.ts` under the `dictionary` object, or override it on a per-dictionary basis in its `.content.ts` file.
381
508
 
382
509
  ### 1. Static Mode (`default`)
383
510
 
384
511
  In static mode, Intlayer replaces `useIntlayer` with `useDictionary` and injects the dictionary directly into the JavaScript bundle.
385
512
 
386
- - **Pros:** Instant rendering (synchronous), zero extra network requests during hydration.
513
+ - **Pros:** Instant rendering (synchronous), zero additional network requests during hydration.
387
514
  - **Cons:** The bundle includes translations for **all** available languages for that specific component.
388
515
  - **Best for:** Single Page Applications (SPA).
389
516
 
390
- **Transformed Code Example:**
517
+ **Transformed code example:**
391
518
 
392
519
  ```tsx
393
520
  // Your code
394
521
  const content = useIntlayer("my-key");
395
522
 
396
- // Optimised code (Static)
523
+ // Optimised code illustration after transformation (Static)
524
+ // This is for illustration only, the actual code will differ for optimisation reasons
397
525
  const content = useDictionary({
398
526
  key: "my-key",
399
527
  content: {
@@ -408,19 +536,20 @@ const content = useDictionary({
408
536
 
409
537
  ### 2. Dynamic Mode
410
538
 
411
- In dynamic mode, Intlayer replaces `useIntlayer` with `useDictionaryAsync`. This uses `import()` (Suspense-like mechanism) to lazy-load specifically the JSON for the current locale.
539
+ In dynamic mode, Intlayer replaces the `useIntlayer` with `useDictionaryAsync`. This uses `import()` (a Suspense-like mechanism) to lazy-load specifically the JSON for the current locale.
412
540
 
413
- - **Pros:** **Locale-level tree shaking.** A user viewing the English version will _only_ download the English dictionary. The French dictionary is never loaded.
541
+ - **Pros:** **Locale-level tree shaking.** A user viewing the English version will download _only_ the English dictionary. The French dictionary is never loaded.
414
542
  - **Cons:** Triggers a network request (asset fetch) per component during hydration.
415
543
  - **Best for:** Large text blocks, articles, or applications supporting many languages where bundle size is critical.
416
544
 
417
- **Transformed Code Example:**
545
+ **Transformed code example:**
418
546
 
419
547
  ```tsx
420
548
  // Your code
421
549
  const content = useIntlayer("my-key");
422
550
 
423
- // Optimised code (Dynamic)
551
+ // Optimised code illustration after transformation (Dynamic)
552
+ // This is for illustration only, the actual code will differ for optimisation reasons
424
553
  const content = useDictionaryAsync({
425
554
  en: () =>
426
555
  import(".intlayer/dynamic_dictionary/my-key/en.json").then(
@@ -433,22 +562,41 @@ const content = useDictionaryAsync({
433
562
  });
434
563
  ```
435
564
 
436
- > When using `importMode: 'dynamic'`, if you have 100 components using `useIntlayer` on a single page, the browser will attempt 100 separate fetches. To avoid this "waterfall" of requests, group content into fewer `.content` files (e.g., one dictionary per page section) rather than one per atom component.
565
+ > When using `importMode: 'dynamic'`, if you have 100 components using `useIntlayer` on a single page, the browser will attempt 100 separate fetches. To avoid this "waterfall" of requests, group content into fewer `.content` files (e.g. one dictionary per page section) instead of one per atom component. You can also use multiple `.content` files that use the same key. Intlayer will merge them into a single dictionary.
437
566
 
438
567
  ### 3. Fetch Mode
439
568
 
440
569
  Behaves similarly to Dynamic mode but attempts to fetch dictionaries from the Intlayer Live Sync API first. If the API call fails or the content is not marked for live updates, it falls back to the dynamic import.
441
570
 
571
+ **Transformed code example:**
572
+
573
+ ```tsx
574
+ // Your code
575
+ const content = useIntlayer("my-key");
576
+
577
+ // Optimised code illustration (Fetch)
578
+ const content = useDictionaryAsync({
579
+ en: () =>
580
+ fetch("https://intlayer.my-domain.com/dictionary/my-key/en").then((res) =>
581
+ res.json()
582
+ ),
583
+ fr: () =>
584
+ fetch("https://intlayer.my-domain.com/dictionary/my-key/fr").then((res) =>
585
+ res.json()
586
+ ),
587
+ });
588
+ ```
589
+
442
590
  > See CMS documentation for more details: [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_CMS.md)
443
591
 
444
- > In fetch mode, purge and minification can't be used.
592
+ > In fetch mode, purge and minification are not applied because the JSON is served from a remote API using the original field names.
445
593
 
446
594
  ## Summary: Static vs Dynamic
447
595
 
448
- | Feature | Static Mode | Dynamic Mode |
449
- | :------------------- | :-------------------------------------------- | :----------------------------------- |
450
- | **JS Bundle Size** | Larger (includes all langs for the component) | Smallest (only code, no content) |
451
- | **Initial Load** | Instant (Content is in bundle) | Slight delay (Fetches JSON) |
452
- | **Network Requests** | 0 extra requests | 1 request per dictionary |
453
- | **Tree Shaking** | Component-level | Component-level + Locale-level |
454
- | **Best Use Case** | UI Components, Small Apps | Pages with much text, Many Languages |
596
+ | Feature | Static Mode | Dynamic Mode |
597
+ | :------------------- | :------------------------------------------------ | :------------------------------- |
598
+ | **JS Bundle Size** | Larger (includes all languages for the component) | Smallest (code only, no content) |
599
+ | **Initial Load** | Instant (Content is in bundle) | Slight delay (Fetches JSON) |
600
+ | **Network Requests** | 0 extra requests | 1 request per dictionary key |
601
+ | **Tree Shaking** | Component-level | Component-level + Locale-level |
602
+ | **Best Use Case** | UI Components, Small Apps | Text-heavy pages, Many Languages |
@@ -681,16 +681,16 @@ routing: {
681
681
 
682
682
  When using cookie storage, you can configure additional cookie attributes:
683
683
 
684
- | Field | Description | Type |
685
- | ---------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------- |
686
- | `name` | Cookie name. Default: `'INTLAYER_LOCALE'` | `string` |
687
- | `domain` | Cookie domain. Default: `undefined` | `string` |
688
- | `path` | Cookie path. Default: `undefined` | `string` |
689
- | `secure` | Require HTTPS. Default: `undefined` | `boolean` |
690
- | `httpOnly` | HTTP-only flag. Default: `undefined` | `boolean` |
691
- | `sameSite` | SameSite policy. | `'strict'` &#124; <br/> `'lax'` &#124; <br/> `'none'` |
692
- | `expires` | Expiration date or days. Default: `undefined` | `Date` &#124; <br/> `number` |
693
- | `maxAge` | Lifetime in seconds from creation. Takes precedence over `expires`. Default: `undefined` | `number` |
684
+ | Field | Description | Type |
685
+ | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
686
+ | `name` | Cookie name. Default: `'INTLAYER_LOCALE'` | `string` |
687
+ | `domain` | Cookie domain. Default: `undefined` | `string` |
688
+ | `path` | Cookie path. Default: `undefined` | `string` |
689
+ | `secure` | Require HTTPS. Default: `undefined` | `boolean` |
690
+ | `httpOnly` | HTTP-only flag. Default: `undefined` | `boolean` |
691
+ | `sameSite` | SameSite policy. | `'strict'` &#124; <br/> `'lax'` &#124; <br/> `'none'` |
692
+ | `expires` | A `number` is days from creation; a `Date` (or ISO date string) is an absolute expiry. Default: `undefined` | `Date` &#124; <br/> `number` &#124; <br/> `string` |
693
+ | `maxAge` | Lifetime in seconds from creation. Takes precedence over `expires`. Default: `undefined` | `number` |
694
694
 
695
695
  #### Locale Storage Attributes
696
696