@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
4
- title: Biến Thể
5
- description: Sử dụng trường siêu dữ liệu variant trong các tệp nội dung Intlayer để khai báo các lựa chọn nội dung thay thế được đặt tên (thử nghiệm A/B, biểu ngữ theo mùa, văn bản gắn cờ tính năng) và chuyển đổi giữa chúng tại runtime mà không cần thay đổi mã.
3
+ updatedAt: 2026-06-26
4
+ title: Biến thể
5
+ description: Dùng trường metadata variant trong các tệp nội dung Intlayer để khai báo các lựa chọn nội dung được đặt tên hoặc có cấu trúc — thử nghiệm A/B, banner theo mùa, nội dung gắn feature flag, bản ghi CMS, nội dung riêng theo người dùng — và chuyển đổi giữa chúng trong thời gian chạy mà không cần đổi mã.
6
6
  keywords:
7
- - Biến Thể
7
+ - Biến thể
8
8
  - Thử nghiệm A/B
9
- - Cờ Tính Năng
10
- - Nội Dung Động
9
+ - Feature Flag
10
+ - Nội dung động
11
+ - Bản ghi động
12
+ - CMS
11
13
  - Intlayer
12
14
  - Quốc tế hóa
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: "Phát hành tính năng từ điển biến thể"
22
+ changes: "Phát hành tính năng biến thể"
23
+ - version: 9.1.0
24
+ date: 2026-06-26
25
+ changes: "`variant` giờ chấp nhận một chuỗi hoặc một đối tượng — `meta` / bản ghi động trước đây được khai báo dưới dạng biến thể đối tượng"
21
26
  author: aymericzip
22
27
  ---
23
28
 
24
- # Biến Thể
29
+ # Biến thể
25
30
 
26
- Một **biến thể** (variant) là một tập hợp các tệp nội dung chia sẻ cùng một khóa từ điển (`key`) nhưng mỗi tệp mang một tên `variant` khác nhau. Intlayer phục vụ tệp phù hợp dựa trên bộ chọn được truyền vào `useIntlayer`.
31
+ Một **biến thể** là một tập hợp các tệp nội dung dùng chung `key` từ điển nhưng mỗi tệp mang một giá trị `variant` khác nhau. Intlayer phục vụ tệp phù hợp dựa trên bộ chọn được truyền cho `useIntlayer`.
27
32
 
28
- ## Khai báo các biến thể
33
+ Giá trị `variant` thể có **hai dạng**:
29
34
 
30
- Mỗi tệp đại diện cho một lựa chọn thay thế tên. Việc bỏ qua `variant` (hoặc đặt thành `"default"`) sẽ đánh dấu tệp đó làm phương án mặc định (fallback).
35
+ - **Một chuỗi** một lựa chọn được đặt tên duy nhất (thử nghiệm A/B, banner theo mùa, feature flag).
36
+ - **Một đối tượng** — một bộ phân biệt có cấu trúc được định địa chỉ bằng một tập hợp trường (bản ghi CMS, nội dung riêng theo người dùng, bất kỳ nội dung nào được khóa bằng một ID mờ). Toàn bộ đối tượng chính là danh tính: bộ chọn phải cung cấp một đối tượng **bằng nhau** để phân giải mục.
37
+
38
+ > Dạng đối tượng thay thế trường `meta` trước đây. Ở bất cứ đâu trước kia bạn viết `meta: { id, … }`, hãy viết `variant: { id, … }`, và chọn nó bằng `{ variant: { id, … } }`.
39
+
40
+ ## Biến thể được đặt tên (chuỗi)
41
+
42
+ Mỗi tệp đại diện cho một lựa chọn được đặt tên. Bỏ qua `variant` (hoặc đặt thành `"default"`) đánh dấu nó là dự phòng.
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
- ## Sử dụng biến thể
80
+ ### Sử dụng biến thể được đặt tên
69
81
 
70
- ### Biến thể mặc định
82
+ #### Biến thể mặc định
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
- ### Biến thể tên
224
+ #### Biến thể được đặt tên
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
- ### Biến thể tên với ngôn ngữ cụ thể
232
+ #### Biến thể được đặt tên với locale tường minh
221
233
 
222
234
  ```tsx
223
235
  const content = useIntlayer("hero-banner", {
224
236
  variant: "black_friday",
225
- locale: "vi",
237
+ locale: "fr",
226
238
  });
227
239
  ```
228
240
 
241
+ ## Biến thể đối tượng (có cấu trúc)
242
+
243
+ Một biến thể đối tượng định địa chỉ nội dung bằng một tập hợp cặp khóa-giá trị tùy ý được khai báo trong trường `variant` — giúp mô hình hóa 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ó khóa là một ID mờ. **Toàn bộ đối tượng** chính là danh tính: bộ chọn phải cung cấp một đối tượng bằng nhau để mục được phân giải.
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
+ ### Sử dụng biến thể đối tượng
276
+
277
+ Truyền đối tượng khớp cho `variant`. Mọi trường được khai báo trên từ điển phải được cung cấp và bằng nhau; nếu không, kết quả là `null`. Thứ tự các trường không quan trọng.
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
+ #### Với locale tường minh
452
+
453
+ ```tsx
454
+ const content = useIntlayer("product", {
455
+ variant: { id: "prod_abc", userId: "user_123" },
456
+ locale: "fr",
457
+ });
458
+ ```
459
+
460
+ #### Thiếu trường — không khớp
461
+
462
+ ```ts
463
+ // Trả về null: thiếu `userId`, nên đối tượng không khớp với biến thể đã khai báo
464
+ const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
+ ```
466
+
467
+ ## Chế độ tải
468
+
469
+ Biến thể đối tượng thường được tải lười. Đặt `importMode` trên từ điển để kiểm soát điều này:
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
+ Xem [tối ưu hóa bundle](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/bundle_optimization.md) để biết chi tiết về các chế độ `static`, `dynamic` và `fetch`.
483
+
229
484
  ## Các trường hợp sử dụng điển hình
230
485
 
231
- - Các thử nghiệm A/B nội dung được điều hướng bởi một khóa thử nghiệm
232
- - Biểu ngữ theo mùa hoặc biểu ngữ quảng cáo
233
- - Thông điệp được gắn cờ tính năng (feature flag)
234
- - Các chiến dịch tiếp thị cụ thể theo từng vùng địa lý
486
+ - Thử nghiệm A/B nội dung được điều khiển bằng khóa thí nghiệm
487
+ - Banner theo mùa hoặc khuyến mãi
488
+ - Thông điệp gắn feature flag
489
+ - Chiến dịch tiếp thị riêng theo locale
490
+ - Nội dung tiếp thị theo từng sản phẩm được quản lý trong CMS
491
+ - Nội dung riêng theo người dùng hoặc tài khoản
492
+ - Bất kỳ nội dung nào được khóa bằng một ID mờ trong thời gian chạy
@@ -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: Intlayer v9 Mới - Có gì mới?
5
- description: Khám phá các tính năng mới trong Intlayer v9. Giới thiệu các package tương thích drop-in cho các thư viện i18n phổ biến và hỗ trợ Collections, Variants, Dynamic Records.
5
+ description: Khám phá các tính năng mới trong Intlayer v9. Giới thiệu các package tương thích drop-in cho các thư viện i18n phổ biến và hỗ trợ Collections và 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
  # Intlayer v9 Mới - Có gì mới?
24
23
 
25
- Chào mừng bạn đến với Intlayer v9! Bản phát hành lớn này đánh dấu một cột mốc quan trọng trong việc đơn giản hóa lộ trình migration sang Intlayer với các **Compat Adapter Packages** dành cho các thư viện i18n phổ biến (`react-i18next`, `next-intl`, `vue-i18n`, v.v.) và bổ sung hỗ trợ cho các cấu trúc nội dung phong phú: **Collections**, **Variants**, và **Dynamic Records**.
24
+ Chào mừng bạn đến với Intlayer v9! Bản phát hành lớn này đánh dấu một cột mốc quan trọng trong việc đơn giản hóa lộ trình migration sang Intlayer với các **Compat Adapter Packages** dành cho các thư viện i18n phổ biến (`react-i18next`, `next-intl`, `vue-i18n`, v.v.) và bổ sung hỗ trợ cho các cấu trúc nội dung phong phú: **Collections** và **Variants**.
26
25
 
27
26
  ## Mục lục
28
27
 
@@ -41,8 +40,10 @@ Bằng cách thay thế các import, bạn sẽ nhận được tất cả các
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
  Ví dụ, chỉ cần thay đổi:
48
49
 
@@ -100,7 +101,7 @@ Tất cả các compat adapter giờ đây đều định tuyến việc xử l
100
101
 
101
102
  ---
102
103
 
103
- ## Chi tiết tính năng: Collections, Variants & Dynamic Records
104
+ ## Chi tiết tính năng: Collections & Variants
104
105
 
105
106
  Intlayer v9 mở rộng vượt ra ngoài các đối tượng key-value tĩnh, cho phép các dictionary khai báo các cấu trúc layout động được định kiểu đầy đủ (fully typed) từ đầu đến cuối.
106
107
 
@@ -144,6 +145,8 @@ const faq = useIntlayer("faq", { item: 1 }); // -> { question: string, answer: s
144
145
 
145
146
  Cung cấp các bản thử nghiệm A/B, seasonal header, feature flag, hoặc các landing page tùy chỉnh:
146
147
 
148
+ #### Các biến thể chuỗi (ví dụ: thử nghiệm 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
- ### 3. Dynamic Records
171
-
172
- Định nghĩa các dictionary có các mục nhập được tải động tại runtime thông qua các query ID:
173
+ #### Các biến thể đối tượng (ví dụ: Dynamic Records)
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
- meta: {
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**: Kích hoạt tự động khi `compiler.enabled` được đặt và một đường dẫn `compiler.output` được cấu hình. Bạn không còn cần phải đăng ký `intlayerCompiler()` riêng biệt.
233
+ - **Compiler**: Kích hoạt tự động khi `compiler.enabled` được đặt thành `true` và một đường dẫn `compiler.output` được cấu hình. Bạn không còn cần phải đăng ký `intlayerCompiler()` riêng biệt.
233
234
  - **Proxy**: Kích hoạt tự động dựa trên tùy chọn `routing.enableProxy` mới (`true` theo mặc định). Nó kết nối middleware phát hiện ngôn ngữ / chuyển hướng / ghi đè trong phát triển, xem trước và SSR sản xuất. Bạn không còn cần phải đăng ký `intlayerProxy()` riêng biệt.
234
235
 
235
236
  ### Tùy chọn `routing.enableProxy`
@@ -252,6 +253,27 @@ Các plugin độc lập `intlayerCompiler()` và `intlayerProxy()` vẫn đư
252
253
 
253
254
  ---
254
255
 
256
+ ## Compiler bị tắt theo mặc định
257
+
258
+ Kể từ Intlayer v9, **compiler bị tắt theo mặc định** (`compiler.enabled` hiện mặc định là `false`). Để bật trích xuất các file `.content.ts` của bạn tại thời điểm build, hãy đặt `compiler.enabled: true` trong cấu hình của bạn:
259
+
260
+ ```ts fileName="intlayer.config.ts"
261
+ import type { IntlayerConfig } from "intlayer";
262
+
263
+ const config: IntlayerConfig = {
264
+ compiler: {
265
+ enabled: true, // Mặc định: false — bắt buộc để bật compiler kể từ v9
266
+ output: ({ fileName }) => `./${fileName}.content.ts`,
267
+ },
268
+ };
269
+
270
+ export default config;
271
+ ```
272
+
273
+ Khi compiler bị tắt, Intlayer bỏ qua bước trích xuất tại thời điểm build và dựa vào các dictionary mà bạn đã khai báo. Chỉ bật nó khi bạn muốn plugin bundler (`@intlayer/swc`, `@intlayer/babel`, hoặc plugin Vite `intlayer()`) tự động trích xuất nội dung.
274
+
275
+ ---
276
+
255
277
  ## React Native: import từ một package duy nhất
256
278
 
257
279
  Trong ứng dụng React Native hoặc Expo, bạn không còn cần phải xoay sở giữa `react-intlayer` và `react-native-intlayer` nữa. Package `react-native-intlayer` hiện **xuất lại toàn bộ API của `react-intlayer`** (các hook, tiện ích và các đường dẫn phụ `/format`, `/html`, và `/markdown`), và `IntlayerProvider` của nó tự động áp dụng các polyfill của React Native.
@@ -278,13 +300,14 @@ npm install intlayer react-native-intlayer
278
300
 
279
301
  Nếu bạn đang nâng cấp từ v8, lưu ý rằng v9 không bao gồm các breaking change. Tuy nhiên, dưới đây là các thay đổi chính:
280
302
 
303
+ - **Compiler bị tắt theo mặc định**: `compiler.enabled` hiện mặc định là `false`. Nếu bạn dựa vào việc trích xuất các file `.content.ts` tại thời điểm build, hãy đặt `compiler.enabled: true` trong `intlayer.config.ts` của bạn.
281
304
  - **Locales & Dialects**: Nếu sử dụng các dependency i18n bên ngoài, hãy thêm các compat adapter plugin tương ứng của chúng vào cấu hình hoặc thiết lập bundler của bạn để tự động rewrite các import.
282
- - **Custom Selectors**: Khi gọi `useIntlayer`, tham số thứ hai giờ đây được dành riêng cho một đối tượng option chứa `{ locale, item, variant, id }`. Nếu trước đây bạn đã truyền trực tiếp một chuỗi locale, bạn vẫn có thể làm như vậy, nhưng việc sử dụng đối tượng options được khuyến nghị cho các lựa chọn nâng cao.
305
+ - **Custom Selectors**: Khi gọi `useIntlayer`, tham số thứ hai giờ đây được dành riêng cho một đối tượng option chứa `{ locale, item, variant }`. Nếu trước đây bạn đã truyền trực tiếp một chuỗi locale, bạn vẫn có thể làm như vậy, nhưng việc sử dụng đối tượng options được khuyến nghị cho các lựa chọn nâng cao.
283
306
 
284
307
  ---
285
308
 
286
309
  ## Liên kết hữu ích
287
310
 
288
311
  - [Hướng dẫn về Compat Adapter Packages](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/compat/index.md)
289
- - [Dynamic Dictionaries - Collections, Variants & Dynamic Records](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dynamic_dictionaries/index.md)
312
+ - [Dynamic Dictionaries - Collections & Variants](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dynamic_dictionaries/index.md)
290
313
  - [Tài liệu tham khảo cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/configuration.md)
@@ -1,13 +1,12 @@
1
1
  ---
2
2
  createdAt: 2026-06-12
3
- updatedAt: 2026-06-12
3
+ updatedAt: 2026-06-26
4
4
  title: 动态字典
5
- description: Intlayer 的三种动态字典功能 — 集合、变体和动态记录 — 概述,用于构建灵活、运行时驱动的 i18n 内容。
5
+ description: Intlayer 动态字典功能(集合与变体)的概览,用于构建灵活的、由运行时驱动的 i18n 内容。
6
6
  keywords:
7
7
  - 动态字典
8
8
  - 集合
9
9
  - 变体
10
- - 动态记录
11
10
  - Intlayer
12
11
  - 国际化
13
12
  slugs:
@@ -17,32 +16,39 @@ slugs:
17
16
  history:
18
17
  - version: 9.0.0
19
18
  date: 2026-06-12
20
- changes: "发布动态字典功能"
19
+ changes: "动态字典功能发布"
20
+ - version: 9.1.0
21
+ date: 2026-06-26
22
+ changes: "将动态记录合并到变体中——`variant` 现在接受字符串或对象"
21
23
  author: aymericzip
22
24
  ---
23
25
 
24
26
  # 动态字典
25
27
 
26
- Intlayer 支持三种机制来表达超出每个键单个静态字典范围的内容。每种机制都是通过内容文件中的**顶层元数据字段**声明 ponder 的;不需要包装函数。
28
+ Intlayer 支持两种机制来表达超出每个键单一静态字典的内容。每种机制都通过内容文件中的**顶层元数据字段**声明;无需包装函数。
27
29
 
28
- | 功能 | 元数据字段 | `useIntlayer` 中的选择器 |
29
- | ----------------------------------------------------------------------------------------------------------------- | ----------------- | ------------------------ |
30
- | [集合](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
31
- | [变体](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dynamic_dictionaries/variants.md) | `variant: "name"` | `{ variant: "name" }` |
32
- | [动态记录](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dynamic_dictionaries/dynamic_content.md) | `meta: { id, … }` | `{ id, … }` |
30
+ | 功能 | 元数据字段 | `useIntlayer` 中的选择器 |
31
+ | --------------------------------------------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------- |
32
+ | [集合](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
33
+ | [变体](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dynamic_dictionaries/variants.md) | `variant: "name"` _或_ `variant: { … }` | `{ variant: "name" }` _或_ `{ variant: { … } }` |
33
34
 
34
- 这三种机制都与语言环境参数结合使用,并支持通过 `importMode` 进行选择性/延迟加载。
35
+ 两者都可与 locale 参数组合,并支持通过 `importMode` 进行选择性 / 惰性加载。
35
36
 
36
- ## 什么时候使用哪一个
37
+ ## 何时使用哪一个
37
38
 
38
- - **集合** — 在单独文件中管理的有序项目列表(常见问题条目、博客文章、产品)。
39
- - **变体** — 用于 A/B 测试、季节性横幅或功能标志(feature flags)的命名内容替代方案。
40
- - **动态记录** 在运行时通过不透明 ID 获取的内容(CMS 记录、用户特定文案)。
39
+ - **集合** — 在单独文件中管理的有序项目列表(FAQ 条目、博客文章、产品)。
40
+ - **变体** — 具名或结构化的内容替代项:
41
+ - 用于 A/B 测试、季节性横幅或功能开关的**字符串**变体;
42
+ - 用于 CMS 记录、用户特定文案,或由一组字段寻址的任何内容的**对象**变体(即以前的“动态记录”)。
41
43
 
42
- ## 选择器消除歧义
44
+ > 早期版本为按记录键控的内容提供单独的 `meta` 字段。它已合并到 `variant` 中:向 `variant` 传递一个**对象**,而不是使用 `meta`。
43
45
 
44
- 当字典中存在多个选择器时,解析顺序为:
46
+ ## 选择器消歧
47
+
48
+ 一个键可以同时声明两个维度(例如每个项目都有变体的集合)。它们按以下顺序解析:
45
49
 
46
50
  ```
47
- variant → meta → item
51
+ variant → item
48
52
  ```
53
+
54
+ 因此,对 variant × item 键使用 `{ variant: "promo" }` 会以数组形式返回所有 promo 项目,而添加 `{ item: 2 }` 则将其缩小到单个条目。