@intlayer/docs 9.0.0-canary.7 → 9.0.0-canary.9

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 (98) hide show
  1. package/dist/cjs/generated/docs.entry.cjs +0 -20
  2. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  3. package/dist/esm/generated/docs.entry.mjs +0 -20
  4. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  5. package/dist/types/generated/docs.entry.d.ts +0 -1
  6. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  7. package/docs/ar/dynamic_dictionaries/index.md +24 -18
  8. package/docs/ar/dynamic_dictionaries/variants.md +280 -22
  9. package/docs/ar/plugins/sync-json.md +0 -1
  10. package/docs/ar/releases/v9.md +35 -12
  11. package/docs/de/dynamic_dictionaries/index.md +22 -22
  12. package/docs/de/dynamic_dictionaries/variants.md +272 -14
  13. package/docs/de/plugins/sync-json.md +0 -1
  14. package/docs/de/releases/v9.md +35 -12
  15. package/docs/en/dynamic_dictionaries/index.md +20 -14
  16. package/docs/en/dynamic_dictionaries/variants.md +266 -8
  17. package/docs/en/plugins/sync-json.md +0 -1
  18. package/docs/en/releases/v9.md +35 -12
  19. package/docs/en-GB/dynamic_dictionaries/index.md +21 -15
  20. package/docs/en-GB/dynamic_dictionaries/variants.md +268 -10
  21. package/docs/en-GB/plugins/sync-json.md +0 -1
  22. package/docs/en-GB/releases/v9.md +35 -12
  23. package/docs/es/dynamic_dictionaries/index.md +25 -19
  24. package/docs/es/dynamic_dictionaries/variants.md +275 -17
  25. package/docs/es/plugins/sync-json.md +0 -1
  26. package/docs/es/releases/v9.md +35 -12
  27. package/docs/fr/dynamic_dictionaries/index.md +26 -20
  28. package/docs/fr/dynamic_dictionaries/variants.md +273 -15
  29. package/docs/fr/plugins/sync-json.md +0 -1
  30. package/docs/fr/releases/v9.md +35 -12
  31. package/docs/hi/dynamic_dictionaries/index.md +28 -22
  32. package/docs/hi/dynamic_dictionaries/variants.md +282 -24
  33. package/docs/hi/plugins/sync-json.md +0 -1
  34. package/docs/hi/releases/v9.md +35 -12
  35. package/docs/id/dynamic_dictionaries/index.md +25 -19
  36. package/docs/id/dynamic_dictionaries/variants.md +274 -16
  37. package/docs/id/plugins/sync-json.md +0 -1
  38. package/docs/id/releases/v9.md +35 -12
  39. package/docs/it/dynamic_dictionaries/index.md +26 -20
  40. package/docs/it/dynamic_dictionaries/variants.md +273 -15
  41. package/docs/it/plugins/sync-json.md +0 -1
  42. package/docs/it/releases/v9.md +35 -12
  43. package/docs/ja/dynamic_dictionaries/index.md +27 -21
  44. package/docs/ja/dynamic_dictionaries/variants.md +276 -18
  45. package/docs/ja/plugins/sync-json.md +0 -1
  46. package/docs/ja/releases/v9.md +35 -12
  47. package/docs/ko/dynamic_dictionaries/index.md +23 -17
  48. package/docs/ko/dynamic_dictionaries/variants.md +273 -15
  49. package/docs/ko/plugins/sync-json.md +0 -1
  50. package/docs/ko/releases/v9.md +35 -12
  51. package/docs/pl/dynamic_dictionaries/index.md +26 -20
  52. package/docs/pl/dynamic_dictionaries/variants.md +275 -17
  53. package/docs/pl/plugins/sync-json.md +0 -1
  54. package/docs/pl/releases/v9.md +35 -12
  55. package/docs/pt/dynamic_dictionaries/index.md +25 -19
  56. package/docs/pt/dynamic_dictionaries/variants.md +276 -18
  57. package/docs/pt/plugins/sync-json.md +0 -1
  58. package/docs/pt/releases/v9.md +35 -12
  59. package/docs/ru/dynamic_dictionaries/index.md +25 -19
  60. package/docs/ru/dynamic_dictionaries/variants.md +277 -19
  61. package/docs/ru/plugins/sync-json.md +0 -1
  62. package/docs/ru/releases/v9.md +35 -12
  63. package/docs/tr/dynamic_dictionaries/index.md +27 -21
  64. package/docs/tr/dynamic_dictionaries/variants.md +274 -16
  65. package/docs/tr/plugins/sync-json.md +0 -1
  66. package/docs/tr/releases/v9.md +35 -12
  67. package/docs/uk/dynamic_dictionaries/index.md +25 -19
  68. package/docs/uk/dynamic_dictionaries/variants.md +277 -19
  69. package/docs/uk/plugins/sync-json.md +0 -1
  70. package/docs/uk/releases/v9.md +35 -12
  71. package/docs/vi/dynamic_dictionaries/index.md +28 -22
  72. package/docs/vi/dynamic_dictionaries/variants.md +278 -20
  73. package/docs/vi/plugins/sync-json.md +0 -1
  74. package/docs/vi/releases/v9.md +35 -12
  75. package/docs/zh/dynamic_dictionaries/index.md +24 -18
  76. package/docs/zh/dynamic_dictionaries/variants.md +274 -16
  77. package/docs/zh/plugins/sync-json.md +0 -1
  78. package/docs/zh/releases/v9.md +35 -12
  79. package/package.json +6 -6
  80. package/src/generated/docs.entry.ts +0 -20
  81. package/docs/ar/dynamic_dictionaries/dynamic_content.md +0 -271
  82. package/docs/de/dynamic_dictionaries/dynamic_content.md +0 -271
  83. package/docs/en/dynamic_dictionaries/dynamic_content.md +0 -271
  84. package/docs/en-GB/dynamic_dictionaries/dynamic_content.md +0 -271
  85. package/docs/es/dynamic_dictionaries/dynamic_content.md +0 -271
  86. package/docs/fr/dynamic_dictionaries/dynamic_content.md +0 -271
  87. package/docs/hi/dynamic_dictionaries/dynamic_content.md +0 -271
  88. package/docs/id/dynamic_dictionaries/dynamic_content.md +0 -271
  89. package/docs/it/dynamic_dictionaries/dynamic_content.md +0 -271
  90. package/docs/ja/dynamic_dictionaries/dynamic_content.md +0 -271
  91. package/docs/ko/dynamic_dictionaries/dynamic_content.md +0 -271
  92. package/docs/pl/dynamic_dictionaries/dynamic_content.md +0 -271
  93. package/docs/pt/dynamic_dictionaries/dynamic_content.md +0 -271
  94. package/docs/ru/dynamic_dictionaries/dynamic_content.md +0 -271
  95. package/docs/tr/dynamic_dictionaries/dynamic_content.md +0 -271
  96. package/docs/uk/dynamic_dictionaries/dynamic_content.md +0 -271
  97. package/docs/vi/dynamic_dictionaries/dynamic_content.md +0 -271
  98. package/docs/zh/dynamic_dictionaries/dynamic_content.md +0 -271
@@ -1,13 +1,15 @@
1
1
  ---
2
2
  createdAt: 2026-06-12
3
- updatedAt: 2026-06-12
3
+ updatedAt: 2026-06-26
4
4
  title: Variants
5
- description: Use the variant metadata field in Intlayer content files to declare named content alternatives — A/B tests, seasonal banners, feature-flagged copy — and switch between them at runtime without code changes.
5
+ description: Use the variant metadata field in Intlayer content files to declare named or structured content alternatives — A/B tests, seasonal banners, feature-flagged copy, CMS records, user-specific content — and switch between them at runtime without code changes.
6
6
  keywords:
7
7
  - Variants
8
8
  - A/B Testing
9
9
  - Feature Flags
10
10
  - Dynamic Content
11
+ - Dynamic Records
12
+ - CMS
11
13
  - Intlayer
12
14
  - Internationalization
13
15
  slugs:
@@ -18,14 +20,24 @@ history:
18
20
  - version: 9.0.0
19
21
  date: 2026-06-12
20
22
  changes: "Release of the variants feature"
23
+ - version: 9.1.0
24
+ date: 2026-06-26
25
+ changes: "`variant` now accepts a string or an object — the former `meta` / dynamic records are declared as object variants"
21
26
  author: aymericzip
22
27
  ---
23
28
 
24
29
  # Variants
25
30
 
26
- A **variant** is a set of content files that share the same dictionary `key` but each carry a different `variant` name. Intlayer serves the appropriate file based on the selector passed to `useIntlayer`.
31
+ A **variant** is a set of content files that share the same dictionary `key` but each carry a different `variant` value. Intlayer serves the appropriate file based on the selector passed to `useIntlayer`.
27
32
 
28
- ## Declaring variants
33
+ The `variant` value can take **two forms**:
34
+
35
+ - **A string** — a single named alternative (A/B tests, seasonal banners, feature flags).
36
+ - **An object** — a structured discriminator addressed by a set of fields (CMS records, user-specific copy, any content keyed by an opaque ID). The whole object is the identity: the selector must provide an **equal** object to resolve the entry.
37
+
38
+ > The object form replaces the former `meta` field. Anywhere you previously wrote `meta: { id, … }`, write `variant: { id, … }`, and select it with `{ variant: { id, … } }`.
39
+
40
+ ## Named (string) variants
29
41
 
30
42
  Each file represents one named alternative. Omitting `variant` (or setting it to `"default"`) marks it as the fallback.
31
43
 
@@ -65,9 +77,9 @@ const dictionary = {
65
77
  export default dictionary;
66
78
  ```
67
79
 
68
- ## Consuming variants
80
+ ### Consuming named variants
69
81
 
70
- ### Default variant
82
+ #### Default variant
71
83
 
72
84
  <Tabs group="framework">
73
85
  <Tab label="React" value="react">
@@ -209,7 +221,7 @@ export default dictionary;
209
221
  </Tab>
210
222
  </Tabs>
211
223
 
212
- ### Named variant
224
+ #### Named variant
213
225
 
214
226
  ```tsx
215
227
  const { headline, cta } = useIntlayer("hero-banner", {
@@ -217,7 +229,7 @@ const { headline, cta } = useIntlayer("hero-banner", {
217
229
  });
218
230
  ```
219
231
 
220
- ### Named variant with explicit locale
232
+ #### Named variant with explicit locale
221
233
 
222
234
  ```tsx
223
235
  const content = useIntlayer("hero-banner", {
@@ -226,9 +238,255 @@ const content = useIntlayer("hero-banner", {
226
238
  });
227
239
  ```
228
240
 
241
+ ## Object (structured) variants
242
+
243
+ An object variant addresses content by an arbitrary set of key-value pairs declared in the `variant` field — making it possible to model CMS records, user-specific copy, or any content whose key is an opaque ID. The **whole object** is the identity: the selector must provide an equal object for the entry to resolve.
244
+
245
+ ```ts fileName="product.abc.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
246
+ import { t, type Dictionary } from "intlayer";
247
+
248
+ const dictionary = {
249
+ key: "product",
250
+ variant: { id: "prod_abc", userId: "user_123" },
251
+ content: {
252
+ name: t({ en: "Widget Pro", fr: "Widget Pro" }),
253
+ description: t({ en: "The best widget.", fr: "Le meilleur widget." }),
254
+ },
255
+ } satisfies Dictionary;
256
+
257
+ export default dictionary;
258
+ ```
259
+
260
+ ```ts fileName="product.abcd.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
261
+ import { t, type Dictionary } from "intlayer";
262
+
263
+ const dictionary = {
264
+ key: "product",
265
+ variant: { id: "prod_abcd", userId: "user_123" },
266
+ content: {
267
+ name: t({ en: "Widget Lite", fr: "Widget Lite" }),
268
+ description: t({ en: "A lighter option.", fr: "Une option plus légère." }),
269
+ },
270
+ } satisfies Dictionary;
271
+
272
+ export default dictionary;
273
+ ```
274
+
275
+ ### Consuming object variants
276
+
277
+ Pass the matching object to `variant`. Every field declared on the dictionary must be provided and equal; otherwise the result is `null`. Field order does not matter.
278
+
279
+ <Tabs group="framework">
280
+ <Tab label="React" value="react">
281
+ ```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
282
+ import { useIntlayer } from "react-intlayer";
283
+
284
+ export const Product = ({
285
+ productId,
286
+ userId,
287
+ }: {
288
+ productId: string;
289
+ userId: string;
290
+ }) => {
291
+ const content = useIntlayer("product", {
292
+ variant: { id: productId, userId },
293
+ });
294
+
295
+ if (!content) return null;
296
+
297
+ return <p>{content.description}</p>;
298
+ };
299
+ ```
300
+
301
+ </Tab>
302
+ <Tab label="Next.js" value="nextjs">
303
+ ```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
304
+ import { useIntlayer } from "next-intlayer";
305
+
306
+ export const Product = ({
307
+ productId,
308
+ userId,
309
+ }: {
310
+ productId: string;
311
+ userId: string;
312
+ }) => {
313
+ const content = useIntlayer("product", {
314
+ variant: { id: productId, userId },
315
+ });
316
+
317
+ if (!content) return null;
318
+
319
+ return <p>{content.description}</p>;
320
+ };
321
+ ```
322
+
323
+ </Tab>
324
+ <Tab label="Vue" value="vue">
325
+ ```vue fileName="Product.vue" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
326
+ <script setup>
327
+ import { useIntlayer } from "vue-intlayer";
328
+
329
+ const props = defineProps({
330
+ productId: String,
331
+ userId: String,
332
+ });
333
+
334
+ const content = useIntlayer("product", {
335
+ variant: { id: props.productId, userId: props.userId },
336
+ });
337
+ </script>
338
+
339
+ <template>
340
+ <p v-if="content">{{ content.description }}</p>
341
+ </template>
342
+ ```
343
+
344
+ </Tab>
345
+ <Tab label="Svelte" value="svelte">
346
+ ```svelte fileName="Product.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
347
+ <script lang="ts">
348
+ import { useIntlayer } from "svelte-intlayer";
349
+
350
+ export let productId: string;
351
+ export let userId: string;
352
+
353
+ const content = useIntlayer("product", {
354
+ variant: { id: productId, userId },
355
+ });
356
+ </script>
357
+
358
+ {#if $content}
359
+ <p>{$content.description}</p>
360
+ {/if}
361
+ ```
362
+
363
+ </Tab>
364
+ <Tab label="Preact" value="preact">
365
+ ```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
366
+ import { useIntlayer } from "preact-intlayer";
367
+
368
+ export const Product = ({
369
+ productId,
370
+ userId,
371
+ }: {
372
+ productId: string;
373
+ userId: string;
374
+ }) => {
375
+ const content = useIntlayer("product", {
376
+ variant: { id: productId, userId },
377
+ });
378
+
379
+ if (!content) return null;
380
+
381
+ return <p>{content.description}</p>;
382
+ };
383
+ ```
384
+
385
+ </Tab>
386
+ <Tab label="Solid" value="solid">
387
+ ```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
388
+ import { useIntlayer } from "solid-intlayer";
389
+
390
+ export const Product = (props: {
391
+ productId: string;
392
+ userId: string;
393
+ }) => {
394
+ const content = useIntlayer("product", {
395
+ variant: { id: props.productId, userId: props.userId },
396
+ });
397
+
398
+ return (
399
+ <>
400
+ {content() && <p>{content().description}</p>}
401
+ </>
402
+ );
403
+ };
404
+ ```
405
+
406
+ </Tab>
407
+ <Tab label="Angular" value="angular">
408
+ ```typescript fileName="product.component.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
409
+ import { Component, Input, OnInit } from "@angular/core";
410
+ import { useIntlayer } from "angular-intlayer";
411
+
412
+ @Component({
413
+ selector: "app-product",
414
+ template: `
415
+ @if (content()) {
416
+ <p>{{ content().description }}</p>
417
+ }
418
+ `,
419
+ })
420
+ export class ProductComponent implements OnInit {
421
+ @Input() productId!: string;
422
+ @Input() userId!: string;
423
+
424
+ content: any;
425
+
426
+ ngOnInit() {
427
+ this.content = useIntlayer("product", {
428
+ variant: { id: this.productId, userId: this.userId },
429
+ });
430
+ }
431
+ }
432
+ ```
433
+
434
+ </Tab>
435
+ <Tab label="Vanilla JS" value="vanilla">
436
+ ```javascript fileName="product.js"
437
+ import { useIntlayer } from "vanilla-intlayer";
438
+
439
+ const content = useIntlayer("product", {
440
+ variant: { id: "prod_abcd", userId: "user_123" },
441
+ });
442
+
443
+ if (content) {
444
+ document.body.innerHTML = `<p>${content.description}</p>`;
445
+ }
446
+ ```
447
+
448
+ </Tab>
449
+ </Tabs>
450
+
451
+ #### With explicit locale
452
+
453
+ ```tsx
454
+ const content = useIntlayer("product", {
455
+ variant: { id: "prod_abc", userId: "user_123" },
456
+ locale: "fr",
457
+ });
458
+ ```
459
+
460
+ #### Missing field — no match
461
+
462
+ ```ts
463
+ // Returns null: `userId` is missing, so the object does not match the declared variant
464
+ const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
+ ```
466
+
467
+ ## Loading mode
468
+
469
+ Object variants are often loaded lazily. Set `importMode` on the dictionary to control this:
470
+
471
+ ```ts contentDeclarationFormat={["typescript", "esm", "commonjs"]}
472
+ const dictionary = {
473
+ key: "product",
474
+ importMode: "fetch", // or "dynamic"
475
+ variant: { id: "prod_abc", userId: "user_123" },
476
+ content: { … },
477
+ } satisfies Dictionary;
478
+
479
+ export default dictionary;
480
+ ```
481
+
482
+ See [bundle optimization](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/bundle_optimization.md) for details on `static`, `dynamic`, and `fetch` modes.
483
+
229
484
  ## Typical use-cases
230
485
 
231
486
  - A/B copy tests driven by an experiment key
232
487
  - Seasonal or promotional banners
233
488
  - Feature-flagged messaging
234
489
  - Locale-specific marketing campaigns
490
+ - Per-product marketing copy managed in a CMS
491
+ - User-specific or account-specific content
492
+ - Any content keyed by an opaque runtime ID
@@ -108,7 +108,6 @@ const config: IntlayerConfig = {
108
108
  * Will load, and write the output and translations back to the JSON files in the locales directory
109
109
  */
110
110
  syncJSON({
111
- format: "i18next",
112
111
  source: ({ key, locale }) => `./locales/${locale}/${key}.json`,
113
112
  priority: 0,
114
113
  format: "i18next",
@@ -1,15 +1,14 @@
1
1
  ---
2
2
  createdAt: 2026-06-14
3
- updatedAt: 2026-06-25
3
+ updatedAt: 2026-06-26
4
4
  title: New Intlayer v9 - What's new?
5
- description: Discover what's new in Intlayer v9. Introducing drop-in compatibility packages for popular i18n libraries and support for Collections, Variants, and Dynamic Records.
5
+ description: Discover what's new in Intlayer v9. Introducing drop-in compatibility packages for popular i18n libraries and support for Collections and Variants.
6
6
  keywords:
7
7
  - Intlayer
8
8
  - Compatibility
9
9
  - Migration
10
10
  - Collections
11
11
  - Variants
12
- - Dynamic Records
13
12
  - i18next
14
13
  - next-intl
15
14
  - vue-i18n
@@ -22,7 +21,7 @@ author: aymericzip
22
21
 
23
22
  # New Intlayer v9 - What's new?
24
23
 
25
- Welcome to Intlayer v9! This major release marks a huge milestone in simplifying the migration path to Intlayer with **Compat Adapter Packages** for major i18n libraries (`react-i18next`, `next-intl`, `vue-i18n`, etc.) and adds support for rich content structures: **Collections**, **Variants**, and **Dynamic Records**.
24
+ Welcome to Intlayer v9! This major release marks a huge milestone in simplifying the migration path to Intlayer with **Compat Adapter Packages** for major i18n libraries (`react-i18next`, `next-intl`, `vue-i18n`, etc.) and adds support for rich content structures: **Collections** and **Variants**.
26
25
 
27
26
  ## Table of contents
28
27
 
@@ -41,8 +40,10 @@ By replacing imports, you get all the benefits of Intlayer (including compile-ti
41
40
  - `@intlayer/i18next`
42
41
  - `@intlayer/react-i18next`
43
42
  - `@intlayer/next-intl`
43
+ - `@intlayer/react-intl`
44
44
  - `@intlayer/next-i18next`
45
45
  - `@intlayer/vue-i18n`
46
+ - `@intlayer/lingui`
46
47
 
47
48
  For example, simply change:
48
49
 
@@ -100,7 +101,7 @@ All compat adapters now route translation resolution through a single, highly op
100
101
 
101
102
  ---
102
103
 
103
- ## Feature Spec: Collections, Variants & Dynamic Records
104
+ ## Feature Spec: Collections & Variants
104
105
 
105
106
  Intlayer v9 expands beyond static key-value objects, allowing dictionaries to declare dynamic layout structures that are fully typed end-to-end.
106
107
 
@@ -136,6 +137,8 @@ const faq = useIntlayer("faq", { item: 1 }); // -> { question: string, answer: s
136
137
 
137
138
  Deliver A/B tests, seasonal headers, feature flags, or custom landing pages:
138
139
 
140
+ #### String variants (e.g. A/B testing)
141
+
139
142
  ```ts fileName="hero.content.ts"
140
143
  import { t, type Dictionary } from "intlayer";
141
144
 
@@ -155,16 +158,14 @@ export default {
155
158
  const banner = useIntlayer("hero-banner", { variant: "black_friday" });
156
159
  ```
157
160
 
158
- ### 3. Dynamic Records
159
-
160
- Define dictionaries whose entries are loaded dynamically at runtime via query IDs:
161
+ #### Object variants (e.g. Dynamic Records)
161
162
 
162
163
  ```ts fileName="product.content.ts"
163
164
  import { t, type Dictionary } from "intlayer";
164
165
 
165
166
  export default {
166
167
  key: "product-copy",
167
- meta: {
168
+ variant: {
168
169
  id: "prod_123",
169
170
  category: "books",
170
171
  },
@@ -217,7 +218,7 @@ export default defineConfig({
217
218
  });
218
219
  ```
219
220
 
220
- - **Compiler**: Activates automatically when `compiler.enabled` is set and a `compiler.output` path is configured. You no longer need to register `intlayerCompiler()` separately.
221
+ - **Compiler**: Activates automatically when `compiler.enabled` is set to `true` and a `compiler.output` path is configured. You no longer need to register `intlayerCompiler()` separately.
221
222
  - **Proxy**: Activates automatically based on the new `routing.enableProxy` option (`true` by default). It wires the locale detection / redirect / rewrite middleware in development, preview, and production SSR. You no longer need to register `intlayerProxy()` separately.
222
223
 
223
224
  ### `routing.enableProxy` option
@@ -240,6 +241,27 @@ The standalone `intlayerCompiler()` and `intlayerProxy()` plugins remain exporte
240
241
 
241
242
  ---
242
243
 
244
+ ## Compiler disabled by default
245
+
246
+ Starting with Intlayer v9, the **compiler is disabled by default** (`compiler.enabled` now defaults to `false`). To opt in to build-time extraction of your `.content.ts` files, set `compiler.enabled: true` in your configuration:
247
+
248
+ ```ts fileName="intlayer.config.ts"
249
+ import type { IntlayerConfig } from "intlayer";
250
+
251
+ const config: IntlayerConfig = {
252
+ compiler: {
253
+ enabled: true, // Default: false — required to enable the compiler since v9
254
+ output: ({ fileName }) => `./${fileName}.content.ts`,
255
+ },
256
+ };
257
+
258
+ export default config;
259
+ ```
260
+
261
+ When the compiler is disabled, Intlayer skips the build-time extraction step and relies on your already-declared dictionaries. Enable it only when you want the bundler plugin (`@intlayer/swc`, `@intlayer/babel`, or the `intlayer()` Vite plugin) to extract content automatically.
262
+
263
+ ---
264
+
243
265
  ## React Native: single-package imports
244
266
 
245
267
  In a React Native or Expo app, you no longer need to juggle both `react-intlayer` and `react-native-intlayer`. The `react-native-intlayer` package now **re-exports the full `react-intlayer` API** (hooks, utilities, and the `/format`, `/html`, and `/markdown` subpaths), and its `IntlayerProvider` automatically applies the React Native polyfills.
@@ -266,9 +288,10 @@ npm install intlayer react-native-intlayer
266
288
 
267
289
  If you are upgrading from v8, note that the v9 does not include breaking changes. But here are the key changes:
268
290
 
291
+ - **Compiler disabled by default**: `compiler.enabled` now defaults to `false`. If you rely on build-time extraction of your `.content.ts` files, set `compiler.enabled: true` in your `intlayer.config.ts`.
269
292
  - **Vite plugin**: The compiler and locale-routing proxy are now bundled into `intlayer()`. If you previously registered `intlayerCompiler()` or `intlayerProxy()` manually, you can remove them — they are deduplicated automatically, so keeping them is harmless. Use `routing.enableProxy: false` to opt out of the proxy.
270
293
  - **Locales & Dialects**: If using external i18n dependencies, add their respective compat adapter plugins in your configuration or bundler setup to automatically rewrite imports.
271
- - **Custom Selectors**: When calling `useIntlayer`, the second parameter is now reserved for an option object containing `{ locale, item, variant, id }`. If you previously passed a locale string directly, you can still do so, but using the options object is recommended for advanced selections.
294
+ - **Custom Selectors**: When calling `useIntlayer`, the second parameter is now reserved for an option object containing `{ locale, item, variant }`. If you previously passed a locale string directly, you can still do so, but using the options object is recommended for advanced selections.
272
295
  - **React Native**: `react-native-intlayer` now re-exports the entire `react-intlayer` API. In a React Native app, import everything from `react-native-intlayer` and drop the direct `react-intlayer` dependency. Existing `react-intlayer` imports continue to work.
273
296
 
274
297
  ---
@@ -276,6 +299,6 @@ If you are upgrading from v8, note that the v9 does not include breaking changes
276
299
  ## Useful links
277
300
 
278
301
  - [Compat Adapter Packages Guide](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/compat/index.md)
279
- - [Dynamic Dictionaries - Collections, Variants & Dynamic Records](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dynamic_dictionaries/index.md)
302
+ - [Dynamic Dictionaries - Collections & Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dynamic_dictionaries/index.md)
280
303
  - [Configuration Reference](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md)
281
304
  - [React Native & Expo Guide](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_react_native+expo.md)
@@ -1,15 +1,14 @@
1
1
  ---
2
2
  createdAt: 2026-06-12
3
- updatedAt: 2026-06-12
3
+ updatedAt: 2026-06-26
4
4
  title: Dynamic Dictionaries
5
- description: Overview of Intlayer's three dynamic dictionary features — collections, variants, and dynamic records — for building flexible, runtime-driven i18n content.
5
+ description: Overview of Intlayer's dynamic dictionary features — collections and variants — for building flexible, runtime-driven i18n content.
6
6
  keywords:
7
7
  - Dynamic Dictionaries
8
8
  - Collections
9
9
  - Variants
10
- - Dynamic Records
11
10
  - Intlayer
12
- - Internationalisation
11
+ - Internationalization
13
12
  slugs:
14
13
  - doc
15
14
  - concept
@@ -18,31 +17,38 @@ history:
18
17
  - version: 9.0.0
19
18
  date: 2026-06-12
20
19
  changes: "Release of the dynamic dictionaries feature"
20
+ - version: 9.1.0
21
+ date: 2026-06-26
22
+ changes: "Merged dynamic records into variants — `variant` now accepts a string or an object"
21
23
  author: aymericzip
22
24
  ---
23
25
 
24
26
  # Dynamic Dictionaries
25
27
 
26
- Intlayer supports three mechanisms for expressing content that goes beyond a single static dictionary per key. Each is declared through a **top-level metadata field** in the content file; no wrapper function is needed.
28
+ Intlayer supports two mechanisms for expressing content that goes beyond a single static dictionary per key. Each is declared through a **top-level metadata field** in the content file; no wrapper function is needed.
27
29
 
28
- | Feature | Metadata field | Selector in `useIntlayer` |
29
- | --------------------------------------------------------------------------------------------------------------------------- | ----------------- | ------------------------- |
30
- | [Collections](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
31
- | [Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dynamic_dictionaries/variants.md) | `variant: "name"` | `{ variant: "name" }` |
32
- | [Dynamic Records](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dynamic_dictionaries/dynamic_content.md) | `meta: { id, … }` | `{ id, … }` |
30
+ | Feature | Metadata field | Selector in `useIntlayer` |
31
+ | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------- |
32
+ | [Collections](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
33
+ | [Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dynamic_dictionaries/variants.md) | `variant: "name"` _or_ `variant: { … }` | `{ variant: "name" }` _or_ `{ variant: { … } }` |
33
34
 
34
- All three compose with the locale argument and support selective / lazy loading via `importMode`.
35
+ Both compose with the locale argument and support selective / lazy loading via `importMode`.
35
36
 
36
37
  ## When to use which
37
38
 
38
39
  - **Collections** — ordered list of items managed in separate files (FAQ entries, blog posts, products).
39
- - **Variants** — named content alternatives for A/B tests, seasonal banners, or feature flags.
40
- - **Dynamic records** content fetched at runtime by an opaque ID (CMS records, user-specific copy).
40
+ - **Variants** — named or structured content alternatives:
41
+ - a **string** variant for A/B tests, seasonal banners, or feature flags;
42
+ - an **object** variant for CMS records, user-specific copy, or any content addressed by a set of fields (the former "dynamic records").
43
+
44
+ > Earlier versions exposed a separate `meta` field for record-keyed content. It has been merged into `variant`: pass an **object** to `variant` instead of using `meta`.
41
45
 
42
46
  ## Selector disambiguation
43
47
 
44
- When multiple selectors are present on a dictionary, the resolution order is:
48
+ A key may declare both dimensions at once (e.g. a collection whose items each have a variant). They are resolved in the order:
45
49
 
46
50
  ```
47
- variant → meta → item
51
+ variant → item
48
52
  ```
53
+
54
+ So `{ variant: "promo" }` on a variant × item key returns every promo item as an array, and adding `{ item: 2 }` narrows it to a single entry.