@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.
- package/dist/cjs/generated/docs.entry.cjs +0 -20
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +0 -20
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +0 -1
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/dynamic_dictionaries/index.md +24 -18
- package/docs/ar/dynamic_dictionaries/variants.md +280 -22
- package/docs/ar/plugins/sync-json.md +0 -1
- package/docs/ar/releases/v9.md +35 -12
- package/docs/de/dynamic_dictionaries/index.md +22 -22
- package/docs/de/dynamic_dictionaries/variants.md +272 -14
- package/docs/de/plugins/sync-json.md +0 -1
- package/docs/de/releases/v9.md +35 -12
- package/docs/en/dynamic_dictionaries/index.md +20 -14
- package/docs/en/dynamic_dictionaries/variants.md +266 -8
- package/docs/en/plugins/sync-json.md +0 -1
- package/docs/en/releases/v9.md +35 -12
- package/docs/en-GB/dynamic_dictionaries/index.md +21 -15
- package/docs/en-GB/dynamic_dictionaries/variants.md +268 -10
- package/docs/en-GB/plugins/sync-json.md +0 -1
- package/docs/en-GB/releases/v9.md +35 -12
- package/docs/es/dynamic_dictionaries/index.md +25 -19
- package/docs/es/dynamic_dictionaries/variants.md +275 -17
- package/docs/es/plugins/sync-json.md +0 -1
- package/docs/es/releases/v9.md +35 -12
- package/docs/fr/dynamic_dictionaries/index.md +26 -20
- package/docs/fr/dynamic_dictionaries/variants.md +273 -15
- package/docs/fr/plugins/sync-json.md +0 -1
- package/docs/fr/releases/v9.md +35 -12
- package/docs/hi/dynamic_dictionaries/index.md +28 -22
- package/docs/hi/dynamic_dictionaries/variants.md +282 -24
- package/docs/hi/plugins/sync-json.md +0 -1
- package/docs/hi/releases/v9.md +35 -12
- package/docs/id/dynamic_dictionaries/index.md +25 -19
- package/docs/id/dynamic_dictionaries/variants.md +274 -16
- package/docs/id/plugins/sync-json.md +0 -1
- package/docs/id/releases/v9.md +35 -12
- package/docs/it/dynamic_dictionaries/index.md +26 -20
- package/docs/it/dynamic_dictionaries/variants.md +273 -15
- package/docs/it/plugins/sync-json.md +0 -1
- package/docs/it/releases/v9.md +35 -12
- package/docs/ja/dynamic_dictionaries/index.md +27 -21
- package/docs/ja/dynamic_dictionaries/variants.md +276 -18
- package/docs/ja/plugins/sync-json.md +0 -1
- package/docs/ja/releases/v9.md +35 -12
- package/docs/ko/dynamic_dictionaries/index.md +23 -17
- package/docs/ko/dynamic_dictionaries/variants.md +273 -15
- package/docs/ko/plugins/sync-json.md +0 -1
- package/docs/ko/releases/v9.md +35 -12
- package/docs/pl/dynamic_dictionaries/index.md +26 -20
- package/docs/pl/dynamic_dictionaries/variants.md +275 -17
- package/docs/pl/plugins/sync-json.md +0 -1
- package/docs/pl/releases/v9.md +35 -12
- package/docs/pt/dynamic_dictionaries/index.md +25 -19
- package/docs/pt/dynamic_dictionaries/variants.md +276 -18
- package/docs/pt/plugins/sync-json.md +0 -1
- package/docs/pt/releases/v9.md +35 -12
- package/docs/ru/dynamic_dictionaries/index.md +25 -19
- package/docs/ru/dynamic_dictionaries/variants.md +277 -19
- package/docs/ru/plugins/sync-json.md +0 -1
- package/docs/ru/releases/v9.md +35 -12
- package/docs/tr/dynamic_dictionaries/index.md +27 -21
- package/docs/tr/dynamic_dictionaries/variants.md +274 -16
- package/docs/tr/plugins/sync-json.md +0 -1
- package/docs/tr/releases/v9.md +35 -12
- package/docs/uk/dynamic_dictionaries/index.md +25 -19
- package/docs/uk/dynamic_dictionaries/variants.md +277 -19
- package/docs/uk/plugins/sync-json.md +0 -1
- package/docs/uk/releases/v9.md +35 -12
- package/docs/vi/dynamic_dictionaries/index.md +28 -22
- package/docs/vi/dynamic_dictionaries/variants.md +278 -20
- package/docs/vi/plugins/sync-json.md +0 -1
- package/docs/vi/releases/v9.md +35 -12
- package/docs/zh/dynamic_dictionaries/index.md +24 -18
- package/docs/zh/dynamic_dictionaries/variants.md +274 -16
- package/docs/zh/plugins/sync-json.md +0 -1
- package/docs/zh/releases/v9.md +35 -12
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +0 -20
- package/docs/ar/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/de/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/en/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/en-GB/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/es/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/fr/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/hi/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/id/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/it/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ja/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ko/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/pl/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/pt/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ru/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/tr/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/uk/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/vi/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/zh/dynamic_dictionaries/dynamic_content.md +0 -271
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
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:
|
|
14
16
|
- doc
|
|
15
17
|
- concept
|
|
@@ -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`
|
|
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
|
-
|
|
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
|
-
|
|
80
|
+
### Consuming named variants
|
|
69
81
|
|
|
70
|
-
|
|
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
|
-
|
|
224
|
+
#### Named variant
|
|
213
225
|
|
|
214
226
|
```tsx
|
|
215
227
|
const { headline, cta } = useIntlayer("hero-banner", {
|
|
@@ -217,18 +229,264 @@ const { headline, cta } = useIntlayer("hero-banner", {
|
|
|
217
229
|
});
|
|
218
230
|
```
|
|
219
231
|
|
|
220
|
-
|
|
232
|
+
#### Named variant with explicit locale
|
|
221
233
|
|
|
222
234
|
```tsx
|
|
223
235
|
const content = useIntlayer("hero-banner", {
|
|
224
236
|
variant: "black_friday",
|
|
225
|
-
locale: "
|
|
237
|
+
locale: "fr",
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,13 +288,14 @@ 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
|
- **Locales & Dialects**: If using external i18n dependencies, add their respective compat adapter plugins in your configuration or bundler setup to automatically rewrite imports.
|
|
270
|
-
- **Custom Selectors**: When calling `useIntlayer`, the second parameter is now reserved for an option object containing `{ locale, item, variant
|
|
293
|
+
- **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.
|
|
271
294
|
|
|
272
295
|
---
|
|
273
296
|
|
|
274
297
|
## Useful links
|
|
275
298
|
|
|
276
299
|
- [Compat Adapter Packages Guide](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/compat/index.md)
|
|
277
|
-
- [Dynamic Dictionaries - Collections
|
|
300
|
+
- [Dynamic Dictionaries - Collections & Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dynamic_dictionaries/index.md)
|
|
278
301
|
- [Configuration Reference](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
4
|
-
title: Diccionarios
|
|
5
|
-
description:
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
|
+
title: Diccionarios dinámicos
|
|
5
|
+
description: Resumen de las funciones de diccionarios dinámicos de Intlayer — colecciones y variantes — para crear contenido i18n flexible y dirigido en tiempo de ejecución.
|
|
6
6
|
keywords:
|
|
7
|
-
- Diccionarios
|
|
7
|
+
- Diccionarios dinámicos
|
|
8
8
|
- Colecciones
|
|
9
9
|
- Variantes
|
|
10
|
-
- Registros Dinámicos
|
|
11
10
|
- Intlayer
|
|
12
11
|
- Internacionalización
|
|
13
12
|
slugs:
|
|
@@ -18,31 +17,38 @@ history:
|
|
|
18
17
|
- version: 9.0.0
|
|
19
18
|
date: 2026-06-12
|
|
20
19
|
changes: "Lanzamiento de la función de diccionarios dinámicos"
|
|
20
|
+
- version: 9.1.0
|
|
21
|
+
date: 2026-06-26
|
|
22
|
+
changes: "Fusión de los registros dinámicos en las variantes — `variant` ahora acepta una cadena o un objeto"
|
|
21
23
|
author: aymericzip
|
|
22
24
|
---
|
|
23
25
|
|
|
24
|
-
# Diccionarios
|
|
26
|
+
# Diccionarios dinámicos
|
|
25
27
|
|
|
26
|
-
Intlayer admite
|
|
28
|
+
Intlayer admite dos mecanismos para expresar contenido que va más allá de un único diccionario estático por clave. Cada uno se declara mediante un **campo de metadatos de nivel superior** en el archivo de contenido; no se necesita ninguna función envolvente.
|
|
27
29
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
| [Colecciones](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/collections.md)
|
|
31
|
-
| [Variantes](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/variants.md)
|
|
32
|
-
| [Registros Dinámicos](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/dynamic_content.md) | `meta: { id, … }` | `{ id, … }` |
|
|
30
|
+
| Función | Campo de metadatos | Selector en `useIntlayer` |
|
|
31
|
+
| ---------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------- |
|
|
32
|
+
| [Colecciones](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
|
|
33
|
+
| [Variantes](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/variants.md) | `variant: "name"` _o_ `variant: { … }` | `{ variant: "name" }` _o_ `{ variant: { … } }` |
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
Ambos se combinan con el argumento de locale y admiten la carga selectiva / diferida mediante `importMode`.
|
|
35
36
|
|
|
36
37
|
## Cuándo usar cada uno
|
|
37
38
|
|
|
38
|
-
- **Colecciones
|
|
39
|
-
- **Variantes
|
|
40
|
-
-
|
|
39
|
+
- **Colecciones** — lista ordenada de elementos gestionados en archivos separados (entradas de FAQ, artículos de blog, productos).
|
|
40
|
+
- **Variantes** — alternativas de contenido con nombre o estructuradas:
|
|
41
|
+
- una variante de **cadena** para pruebas A/B, banners de temporada o feature flags;
|
|
42
|
+
- una variante de **objeto** para registros de CMS, contenido específico de usuario o cualquier contenido direccionado por un conjunto de campos (los antiguos «registros dinámicos»).
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
> Las versiones anteriores exponían un campo `meta` separado para el contenido indexado por registro. Se ha fusionado en `variant`: pase un **objeto** a `variant` en lugar de usar `meta`.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
## Desambiguación del selector
|
|
47
|
+
|
|
48
|
+
Una clave puede declarar ambas dimensiones a la vez (p. ej. una colección cuyos elementos tienen cada uno una variante). Se resuelven en el orden:
|
|
45
49
|
|
|
46
50
|
```
|
|
47
|
-
variant →
|
|
51
|
+
variant → item
|
|
48
52
|
```
|
|
53
|
+
|
|
54
|
+
Así, `{ variant: "promo" }` en una clave variante × item devuelve todos los elementos promo como un array, y añadir `{ item: 2 }` lo reduce a una sola entrada.
|