@intlayer/docs 9.0.0-canary.7 → 9.0.0-canary.8
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,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
4
|
title: Варіанти
|
|
5
|
-
description: Використовуйте поле метаданих variant у файлах
|
|
5
|
+
description: Використовуйте поле метаданих variant у файлах контенту Intlayer, щоб оголошувати іменовані або структуровані альтернативи контенту — A/B-тести, сезонні банери, тексти під feature-прапорцями, записи CMS, контент конкретного користувача — і перемикатися між ними під час виконання без змін коду.
|
|
6
6
|
keywords:
|
|
7
7
|
- Варіанти
|
|
8
|
-
- A/B
|
|
9
|
-
-
|
|
10
|
-
- Динамічний
|
|
8
|
+
- A/B-тестування
|
|
9
|
+
- Feature-прапорці
|
|
10
|
+
- Динамічний контент
|
|
11
|
+
- Динамічні записи
|
|
12
|
+
- CMS
|
|
11
13
|
- Intlayer
|
|
12
14
|
- Інтернаціоналізація
|
|
13
15
|
slugs:
|
|
@@ -17,17 +19,27 @@ slugs:
|
|
|
17
19
|
history:
|
|
18
20
|
- version: 9.0.0
|
|
19
21
|
date: 2026-06-12
|
|
20
|
-
changes: "Випуск функції варіантів
|
|
22
|
+
changes: "Випуск функції варіантів"
|
|
23
|
+
- version: 9.1.0
|
|
24
|
+
date: 2026-06-26
|
|
25
|
+
changes: "`variant` тепер приймає рядок або об'єкт — колишні `meta` / динамічні записи оголошуються як об'єктні варіанти"
|
|
21
26
|
author: aymericzip
|
|
22
27
|
---
|
|
23
28
|
|
|
24
29
|
# Варіанти
|
|
25
30
|
|
|
26
|
-
**Варіант**
|
|
31
|
+
**Варіант** — це набір файлів контенту, що мають спільний ключ словника (`key`), але кожен несе своє значення `variant`. Intlayer віддає відповідний файл на основі селектора, переданого до `useIntlayer`.
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
Значення `variant` може набувати **двох форм**:
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
- **Рядок** — одна іменована альтернатива (A/B-тести, сезонні банери, feature-прапорці).
|
|
36
|
+
- **Об'єкт** — структурований дискримінатор, адресований набором полів (записи CMS, контент конкретного користувача, будь-який контент із непрозорим ID як ключем). Ідентичністю є весь об'єкт: селектор має надати **рівний** об'єкт, щоб розв'язати запис.
|
|
37
|
+
|
|
38
|
+
> Об'єктна форма замінює колишнє поле `meta`. Усюди, де раніше ви писали `meta: { id, … }`, пишіть `variant: { id, … }` і вибирайте її через `{ variant: { id, … } }`.
|
|
39
|
+
|
|
40
|
+
## Іменовані (рядкові) варіанти
|
|
41
|
+
|
|
42
|
+
Кожен файл представляє одну іменовану альтернативу. Пропуск `variant` (або значення `"default"`) позначає його як запасний.
|
|
31
43
|
|
|
32
44
|
```ts fileName="hero-banner.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
33
45
|
import { t, type Dictionary } from "intlayer";
|
|
@@ -65,9 +77,9 @@ const dictionary = {
|
|
|
65
77
|
export default dictionary;
|
|
66
78
|
```
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
### Використання іменованих варіантів
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
#### Варіант за замовчуванням
|
|
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
|
+
#### Іменований варіант
|
|
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
|
+
#### Іменований варіант із явною локаллю
|
|
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
|
|
|
229
|
-
##
|
|
241
|
+
## Об'єктні (структуровані) варіанти
|
|
242
|
+
|
|
243
|
+
Об'єктний варіант адресує контент довільним набором пар ключ-значення, оголошених у полі `variant`, — що дозволяє моделювати записи CMS, контент конкретного користувача або будь-який контент із непрозорим ID як ключем. Ідентичністю є **весь об'єкт**: селектор має надати рівний об'єкт, щоб запис було розв'язано.
|
|
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
|
+
### Використання об'єктних варіантів
|
|
276
|
+
|
|
277
|
+
Передайте відповідний об'єкт у `variant`. Кожне поле, оголошене у словнику, має бути надане й рівне; інакше результат — `null`. Порядок полів не має значення.
|
|
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
|
+
#### З явною локаллю
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
const content = useIntlayer("product", {
|
|
455
|
+
variant: { id: "prod_abc", userId: "user_123" },
|
|
456
|
+
locale: "fr",
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### Відсутнє поле — немає збігу
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
// Повертає null: відсутній `userId`, тож об'єкт не збігається з оголошеним варіантом
|
|
464
|
+
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Режим завантаження
|
|
468
|
+
|
|
469
|
+
Об'єктні варіанти часто завантажуються ліниво. Задайте `importMode` у словнику, щоб керувати цим:
|
|
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
|
+
Див. [оптимізацію бандла](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/bundle_optimization.md) для деталей про режими `static`, `dynamic` і `fetch`.
|
|
483
|
+
|
|
484
|
+
## Типові сценарії використання
|
|
230
485
|
|
|
231
|
-
- A/B
|
|
232
|
-
- Сезонні або
|
|
233
|
-
-
|
|
234
|
-
- Маркетингові кампанії для
|
|
486
|
+
- A/B-тести тексту, керовані ключем експерименту
|
|
487
|
+
- Сезонні або рекламні банери
|
|
488
|
+
- Повідомлення під feature-прапорцями
|
|
489
|
+
- Маркетингові кампанії для конкретної локалі
|
|
490
|
+
- Маркетинговий текст за товарами, керований у CMS
|
|
491
|
+
- Контент конкретного користувача або акаунта
|
|
492
|
+
- Будь-який контент, адресований непрозорим ID під час виконання
|
|
@@ -108,7 +108,6 @@ const config: IntlayerConfig = {
|
|
|
108
108
|
* Завантажить та запише результати й переклади назад у JSON-файли в директорії locales
|
|
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",
|
package/docs/uk/releases/v9.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-14
|
|
3
|
-
updatedAt: 2026-06-
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
4
|
title: Новий Intlayer v9 - Що нового?
|
|
5
|
-
description: Дізнайтеся, що нового в Intlayer v9. Представляємо сумісні пакети швидкої заміни (drop-in) для популярних бібліотек i18n та підтримку Collections
|
|
5
|
+
description: Дізнайтеся, що нового в Intlayer v9. Представляємо сумісні пакети швидкої заміни (drop-in) для популярних бібліотек i18n та підтримку Collections та Variants.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- Сумісність
|
|
9
9
|
- Міграція
|
|
10
10
|
- Колекції
|
|
11
11
|
- Варіанти
|
|
12
|
-
- Динамічні записи
|
|
13
12
|
- i18next
|
|
14
13
|
- next-intl
|
|
15
14
|
- vue-i18n
|
|
@@ -22,7 +21,7 @@ author: aymericzip
|
|
|
22
21
|
|
|
23
22
|
# Новий Intlayer v9 - Що нового?
|
|
24
23
|
|
|
25
|
-
Ласкаво просимо до Intlayer v9! Цей мажорний реліз є величезною віхою у спрощенні шляху міграції на Intlayer завдяки **Compat Adapter Packages** (пакетам адаптерів сумісності) для основних бібліотек i18n (`react-i18next`, `next-intl`, `vue-i18n` тощо) та додає підтримку складних структур контенту: **Collections** (Колекцій)
|
|
24
|
+
Ласкаво просимо до Intlayer v9! Цей мажорний реліз є величезною віхою у спрощенні шляху міграції на Intlayer завдяки **Compat Adapter Packages** (пакетам адаптерів сумісності) для основних бібліотек i18n (`react-i18next`, `next-intl`, `vue-i18n` тощо) та додає підтримку складних структур контенту: **Collections** (Колекцій) та **Variants** (Варіантів).
|
|
26
25
|
|
|
27
26
|
## Зміст
|
|
28
27
|
|
|
@@ -41,8 +40,10 @@ author: aymericzip
|
|
|
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
|
Наприклад, просто змініть:
|
|
48
49
|
|
|
@@ -100,7 +101,7 @@ export default defineConfig({
|
|
|
100
101
|
|
|
101
102
|
---
|
|
102
103
|
|
|
103
|
-
## Специфікація функцій: Collections
|
|
104
|
+
## Специфікація функцій: Collections та Variants
|
|
104
105
|
|
|
105
106
|
Intlayer v9 виходить за рамки статичних об'єктів типу ключ-значення, дозволяючи словникам оголошувати динамічні структури макетів, які повністю типізовані від початку до кінця (end-to-end).
|
|
106
107
|
|
|
@@ -144,6 +145,8 @@ const faq = useIntlayer("faq", { item: 1 }); // -> { question: string, answer: s
|
|
|
144
145
|
|
|
145
146
|
Надавайте A/B тести, сезонні заголовки, feature flags або кастомні цільові сторінки (landing pages):
|
|
146
147
|
|
|
148
|
+
#### Рядкові варіанти (наприклад, A/B-тестування)
|
|
149
|
+
|
|
147
150
|
```ts fileName="hero.content.ts"
|
|
148
151
|
import { t, type Dictionary } from "intlayer";
|
|
149
152
|
|
|
@@ -167,16 +170,14 @@ export default {
|
|
|
167
170
|
const banner = useIntlayer("hero-banner", { variant: "black_friday" });
|
|
168
171
|
```
|
|
169
172
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
Визначайте словники, записи яких завантажуються динамічно під час виконання за допомогою ідентифікаторів запитів (query IDs):
|
|
173
|
+
#### Об'єктні варіанти (наприклад, динамічні записи)
|
|
173
174
|
|
|
174
175
|
```ts fileName="product.content.ts"
|
|
175
176
|
import { t, type Dictionary } from "intlayer";
|
|
176
177
|
|
|
177
178
|
export default {
|
|
178
179
|
key: "product-copy",
|
|
179
|
-
|
|
180
|
+
variant: {
|
|
180
181
|
id: "prod_123",
|
|
181
182
|
category: "books",
|
|
182
183
|
},
|
|
@@ -229,7 +230,7 @@ export default defineConfig({
|
|
|
229
230
|
});
|
|
230
231
|
```
|
|
231
232
|
|
|
232
|
-
- **Compiler**: Активується автоматично, коли
|
|
233
|
+
- **Compiler**: Активується автоматично, коли `compiler.enabled` встановлено у `true` та налаштовано шлях `compiler.output`. Вам більше не потрібно реєструвати `intlayerCompiler()` окремо.
|
|
233
234
|
- **Proxy**: Активується автоматично на основі нового параметра `routing.enableProxy` (`true` за замовчуванням). Він підключає middleware виявлення локалей / перенаправлення / переписування в режимі розробки, попереднього перегляду та production SSR. Вам більше не потрібно реєструвати `intlayerProxy()` окремо.
|
|
234
235
|
|
|
235
236
|
### Опція `routing.enableProxy`
|
|
@@ -252,6 +253,27 @@ export default config;
|
|
|
252
253
|
|
|
253
254
|
---
|
|
254
255
|
|
|
256
|
+
## Компілятор вимкнено за замовчуванням
|
|
257
|
+
|
|
258
|
+
Починаючи з Intlayer v9, **компілятор вимкнено за замовчуванням** (значення `compiler.enabled` тепер за замовчуванням дорівнює `false`). Щоб увімкнути вилучення ваших файлів `.content.ts` під час збірки, встановіть `compiler.enabled: true` у своїй конфігурації:
|
|
259
|
+
|
|
260
|
+
```ts fileName="intlayer.config.ts"
|
|
261
|
+
import type { IntlayerConfig } from "intlayer";
|
|
262
|
+
|
|
263
|
+
const config: IntlayerConfig = {
|
|
264
|
+
compiler: {
|
|
265
|
+
enabled: true, // За замовчуванням: false — потрібно для увімкнення компілятора починаючи з v9
|
|
266
|
+
output: ({ fileName }) => `./${fileName}.content.ts`,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export default config;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Коли компілятор вимкнено, Intlayer пропускає крок вилучення під час збірки та покладається на вже оголошені вами словники. Вмикайте його лише тоді, коли хочете, щоб плагін збирача (`@intlayer/swc`, `@intlayer/babel` або Vite-плагін `intlayer()`) вилучав вміст автоматично.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
255
277
|
## React Native: імпорт з одного пакета
|
|
256
278
|
|
|
257
279
|
У програмі React Native або Expo вам більше не потрібно жонглювати `react-intlayer` та `react-native-intlayer`. Пакет `react-native-intlayer` тепер **реекспортує весь API `react-intlayer`** (хуки, утиліти та підшляхи `/format`, `/html` і `/markdown`), а його `IntlayerProvider` автоматично застосовує поліфіли React Native.
|
|
@@ -278,13 +300,14 @@ npm install intlayer react-native-intlayer
|
|
|
278
300
|
|
|
279
301
|
Якщо ви оновлюєтеся з v8, зверніть увагу, що v9 не містить критичних змін (breaking changes). Проте ось ключові зміни:
|
|
280
302
|
|
|
303
|
+
- **Компілятор вимкнено за замовчуванням**: значення `compiler.enabled` тепер за замовчуванням дорівнює `false`. Якщо ви покладаєтеся на вилучення ваших файлів `.content.ts` під час збірки, встановіть `compiler.enabled: true` у своєму `intlayer.config.ts`.
|
|
281
304
|
- **Locales & Dialects**: Якщо ви використовуєте зовнішні залежності i18n, додайте відповідні плагіни адаптерів сумісності у вашу конфігурацію або налаштування бандлера для автоматичного перезапису імпортів.
|
|
282
|
-
- **Custom Selectors**: При виклику `useIntlayer` другий параметр тепер зарезервований для об'єкта опцій, що містить `{ locale, item, variant
|
|
305
|
+
- **Custom Selectors**: При виклику `useIntlayer` другий параметр тепер зарезервований для об'єкта опцій, що містить `{ locale, item, variant }`. Якщо раніше ви передавали рядок локалі безпосередньо, ви все ще можете це робити, але для розширеного вибору рекомендується використовувати об'єкт опцій.
|
|
283
306
|
|
|
284
307
|
---
|
|
285
308
|
|
|
286
309
|
## Корисні посилання
|
|
287
310
|
|
|
288
311
|
- [Посібник з пакетів адаптерів сумісності (Compat Adapter Packages)](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/compat/index.md)
|
|
289
|
-
- [Динамічні словники - Collections
|
|
312
|
+
- [Динамічні словники - Collections та Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/dynamic_dictionaries/index.md)
|
|
290
313
|
- [Довідник з конфігурації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/configuration.md)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
4
|
-
title: Từ
|
|
5
|
-
description: Tổng quan về
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
|
+
title: Từ điển động
|
|
5
|
+
description: Tổng quan về các tính năng từ điển động của Intlayer — bộ sưu tập và biến thể — để xây dựng nội dung i18n linh hoạt, được điều khiển trong thời gian chạy.
|
|
6
6
|
keywords:
|
|
7
|
-
- Từ
|
|
8
|
-
- Bộ
|
|
9
|
-
- Biến
|
|
10
|
-
- Bản Ghi Động
|
|
7
|
+
- Từ điển động
|
|
8
|
+
- Bộ sưu tập
|
|
9
|
+
- Biến thể
|
|
11
10
|
- Intlayer
|
|
12
11
|
- Quốc tế hóa
|
|
13
12
|
slugs:
|
|
@@ -18,31 +17,38 @@ history:
|
|
|
18
17
|
- version: 9.0.0
|
|
19
18
|
date: 2026-06-12
|
|
20
19
|
changes: "Phát hành tính năng từ điển động"
|
|
20
|
+
- version: 9.1.0
|
|
21
|
+
date: 2026-06-26
|
|
22
|
+
changes: "Hợp nhất bản ghi động vào biến thể — `variant` giờ chấp nhận một chuỗi hoặc một đối tượng"
|
|
21
23
|
author: aymericzip
|
|
22
24
|
---
|
|
23
25
|
|
|
24
|
-
# Từ
|
|
26
|
+
# Từ điển động
|
|
25
27
|
|
|
26
|
-
Intlayer hỗ trợ
|
|
28
|
+
Intlayer hỗ trợ hai cơ chế để diễn đạt nội dung vượt ra ngoài một từ điển tĩnh duy nhất cho mỗi khóa. Mỗi cơ chế được khai báo qua một **trường metadata cấp cao nhất** trong tệp nội dung; không cần hàm bao bọc.
|
|
27
29
|
|
|
28
|
-
| Tính năng
|
|
29
|
-
|
|
|
30
|
-
| [Bộ
|
|
31
|
-
| [Biến
|
|
32
|
-
| [Bản Ghi Động](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dynamic_dictionaries/dynamic_content.md) | `meta: { id, … }` | `{ id, … }` |
|
|
30
|
+
| Tính năng | Trường metadata | Bộ chọn trong `useIntlayer` |
|
|
31
|
+
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------- |
|
|
32
|
+
| [Bộ sưu tập](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
|
|
33
|
+
| [Biến thể](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dynamic_dictionaries/variants.md) | `variant: "name"` _hoặc_ `variant: { … }` | `{ variant: "name" }` _hoặc_ `{ variant: { … } }` |
|
|
33
34
|
|
|
34
|
-
Cả
|
|
35
|
+
Cả hai đều kết hợp với đối số locale và hỗ trợ tải chọn lọc / lười qua `importMode`.
|
|
35
36
|
|
|
36
|
-
## Khi nào
|
|
37
|
+
## Khi nào dùng cái nào
|
|
37
38
|
|
|
38
|
-
- **Bộ sưu tập** — danh sách
|
|
39
|
-
- **Biến thể** — các lựa chọn nội dung
|
|
40
|
-
-
|
|
39
|
+
- **Bộ sưu tập** — danh sách mục được sắp xếp, quản lý trong các tệp riêng (mục FAQ, bài blog, sản phẩm).
|
|
40
|
+
- **Biến thể** — các lựa chọn nội dung được đặt tên hoặc có cấu trúc:
|
|
41
|
+
- biến thể **chuỗi** cho thử nghiệm A/B, banner theo mùa hoặc feature flag;
|
|
42
|
+
- biến thể **đối tượng** cho bản ghi CMS, nội dung riêng theo người dùng, hoặc bất kỳ nội dung nào được định địa chỉ bằng một tập hợp trường ("bản ghi động" trước đây).
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
> Các phiên bản trước cung cấp một trường `meta` riêng cho nội dung được khóa theo bản ghi. Nó đã được hợp nhất vào `variant`: hãy truyền một **đối tượng** cho `variant` thay vì dùng `meta`.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
## Khử nhập nhằng bộ chọn
|
|
47
|
+
|
|
48
|
+
Một khóa có thể khai báo cả hai chiều cùng lúc (ví dụ một bộ sưu tập mà mỗi mục có một biến thể). Chúng được phân giải theo thứ tự:
|
|
45
49
|
|
|
46
50
|
```
|
|
47
|
-
variant →
|
|
51
|
+
variant → item
|
|
48
52
|
```
|
|
53
|
+
|
|
54
|
+
Vì vậy, `{ variant: "promo" }` trên khóa variant × item trả về mọi mục promo dưới dạng mảng, và thêm `{ item: 2 }` thu hẹp lại còn một mục duy nhất.
|