@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: 在 Intlayer 内容文件中使用 variant
|
|
5
|
+
description: 在 Intlayer 内容文件中使用 variant 元数据字段来声明具名或结构化的内容替代项——A/B 测试、季节性横幅、功能开关文案、CMS 记录、用户特定内容——并在运行时无需更改代码即可在它们之间切换。
|
|
6
6
|
keywords:
|
|
7
7
|
- 变体
|
|
8
8
|
- A/B 测试
|
|
9
|
-
-
|
|
9
|
+
- 功能开关
|
|
10
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 测试、季节性横幅、功能开关)。
|
|
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
|
+
有关 `static`、`dynamic` 和 `fetch` 模式的详细信息,请参阅[包优化](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/bundle_optimization.md)。
|
|
483
|
+
|
|
484
|
+
## 典型用例
|
|
230
485
|
|
|
231
|
-
-
|
|
486
|
+
- 由实验键驱动的 A/B 文案测试
|
|
232
487
|
- 季节性或促销横幅
|
|
233
|
-
-
|
|
234
|
-
-
|
|
488
|
+
- 功能开关消息
|
|
489
|
+
- 特定语言环境的营销活动
|
|
490
|
+
- 在 CMS 中管理的按产品营销文案
|
|
491
|
+
- 用户特定或账户特定的内容
|
|
492
|
+
- 在运行时以不透明 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",
|
package/docs/zh/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: 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**: 当 `compiler.enabled`
|
|
221
|
+
- **Compiler**: 当 `compiler.enabled` 被设置为 `true` 且配置了 `compiler.output` 路径时,自动激活。您不再需要单独注册 `intlayerCompiler()`。
|
|
221
222
|
- **Proxy**: 根据新的 `routing.enableProxy` 选项自动激活(默认为 `true`)。它在开发、预览和生产 SSR 中连接区域设置检测 / 重定向 / 重写中间件。您不再需要单独注册 `intlayerProxy()`。
|
|
222
223
|
|
|
223
224
|
### `routing.enableProxy` 选项
|
|
@@ -240,6 +241,27 @@ export default config;
|
|
|
240
241
|
|
|
241
242
|
---
|
|
242
243
|
|
|
244
|
+
## 默认禁用编译器
|
|
245
|
+
|
|
246
|
+
从 Intlayer v9 开始,**编译器默认被禁用**(`compiler.enabled` 现在默认为 `false`)。要启用对 `.content.ts` 文件的构建时提取,请在配置中设置 `compiler.enabled: true`:
|
|
247
|
+
|
|
248
|
+
```ts fileName="intlayer.config.ts"
|
|
249
|
+
import type { IntlayerConfig } from "intlayer";
|
|
250
|
+
|
|
251
|
+
const config: IntlayerConfig = {
|
|
252
|
+
compiler: {
|
|
253
|
+
enabled: true, // 默认值:false —— 自 v9 起启用编译器所必需
|
|
254
|
+
output: ({ fileName }) => `./${fileName}.content.ts`,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export default config;
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
当编译器被禁用时,Intlayer 会跳过构建时提取步骤,并依赖您已声明的字典。仅当您希望打包器插件(`@intlayer/swc`、`@intlayer/babel` 或 `intlayer()` Vite 插件)自动提取内容时才启用它。
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
243
265
|
## React Native:单包导入
|
|
244
266
|
|
|
245
267
|
在 React Native 或 Expo 应用中,您不再需要同时管理 `react-intlayer` 和 `react-native-intlayer`。`react-native-intlayer` 包现在**重新导出了完整的 `react-intlayer` API**(hooks、工具函数以及 `/format`、`/html` 和 `/markdown` 子路径),并且其 `IntlayerProvider` 会自动应用 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.enabled` 现在默认为 `false`。如果您依赖对 `.content.ts` 文件的构建时提取,请在 `intlayer.config.ts` 中设置 `compiler.enabled: true`。
|
|
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)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/docs",
|
|
3
|
-
"version": "9.0.0-canary.
|
|
3
|
+
"version": "9.0.0-canary.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Intlayer documentation",
|
|
6
6
|
"keywords": [
|
|
@@ -73,13 +73,13 @@
|
|
|
73
73
|
"watch": "webpack --config ./webpack.config.ts --watch"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@intlayer/config": "9.0.0-canary.
|
|
77
|
-
"@intlayer/core": "9.0.0-canary.
|
|
78
|
-
"@intlayer/types": "9.0.0-canary.
|
|
76
|
+
"@intlayer/config": "9.0.0-canary.8",
|
|
77
|
+
"@intlayer/core": "9.0.0-canary.8",
|
|
78
|
+
"@intlayer/types": "9.0.0-canary.8"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@intlayer/api": "9.0.0-canary.
|
|
82
|
-
"@intlayer/cli": "9.0.0-canary.
|
|
81
|
+
"@intlayer/api": "9.0.0-canary.8",
|
|
82
|
+
"@intlayer/cli": "9.0.0-canary.8",
|
|
83
83
|
"@types/node": "25.9.4",
|
|
84
84
|
"@utils/ts-config": "1.0.4",
|
|
85
85
|
"@utils/ts-config-types": "1.0.4",
|
|
@@ -1373,26 +1373,6 @@ export const docsEntry = {
|
|
|
1373
1373
|
vi: readLocale('dynamic_dictionaries/collections.md', 'vi'),
|
|
1374
1374
|
uk: readLocale('dynamic_dictionaries/collections.md', 'uk'),
|
|
1375
1375
|
} as unknown as Record<LocalesValues, Promise<string>>,
|
|
1376
|
-
'./docs/en/dynamic_dictionaries/dynamic_content.md': {
|
|
1377
|
-
en: readLocale('dynamic_dictionaries/dynamic_content.md', 'en'),
|
|
1378
|
-
ru: readLocale('dynamic_dictionaries/dynamic_content.md', 'ru'),
|
|
1379
|
-
ja: readLocale('dynamic_dictionaries/dynamic_content.md', 'ja'),
|
|
1380
|
-
fr: readLocale('dynamic_dictionaries/dynamic_content.md', 'fr'),
|
|
1381
|
-
ko: readLocale('dynamic_dictionaries/dynamic_content.md', 'ko'),
|
|
1382
|
-
zh: readLocale('dynamic_dictionaries/dynamic_content.md', 'zh'),
|
|
1383
|
-
es: readLocale('dynamic_dictionaries/dynamic_content.md', 'es'),
|
|
1384
|
-
de: readLocale('dynamic_dictionaries/dynamic_content.md', 'de'),
|
|
1385
|
-
ar: readLocale('dynamic_dictionaries/dynamic_content.md', 'ar'),
|
|
1386
|
-
it: readLocale('dynamic_dictionaries/dynamic_content.md', 'it'),
|
|
1387
|
-
'en-GB': readLocale('dynamic_dictionaries/dynamic_content.md', 'en-GB'),
|
|
1388
|
-
pt: readLocale('dynamic_dictionaries/dynamic_content.md', 'pt'),
|
|
1389
|
-
hi: readLocale('dynamic_dictionaries/dynamic_content.md', 'hi'),
|
|
1390
|
-
tr: readLocale('dynamic_dictionaries/dynamic_content.md', 'tr'),
|
|
1391
|
-
pl: readLocale('dynamic_dictionaries/dynamic_content.md', 'pl'),
|
|
1392
|
-
id: readLocale('dynamic_dictionaries/dynamic_content.md', 'id'),
|
|
1393
|
-
vi: readLocale('dynamic_dictionaries/dynamic_content.md', 'vi'),
|
|
1394
|
-
uk: readLocale('dynamic_dictionaries/dynamic_content.md', 'uk'),
|
|
1395
|
-
} as unknown as Record<LocalesValues, Promise<string>>,
|
|
1396
1376
|
'./docs/en/dynamic_dictionaries/index.md': {
|
|
1397
1377
|
en: readLocale('dynamic_dictionaries/index.md', 'en'),
|
|
1398
1378
|
ru: readLocale('dynamic_dictionaries/index.md', 'ru'),
|