@intlayer/docs 9.1.0 → 9.1.2
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/docs/ar/dynamic_dictionaries/variants.md +248 -5
- package/docs/de/dynamic_dictionaries/variants.md +208 -1
- package/docs/en/dynamic_dictionaries/variants.md +208 -1
- package/docs/en-GB/dynamic_dictionaries/variants.md +208 -1
- package/docs/es/dynamic_dictionaries/variants.md +208 -1
- package/docs/fr/dynamic_dictionaries/variants.md +208 -1
- package/docs/hi/dynamic_dictionaries/variants.md +210 -3
- package/docs/id/dynamic_dictionaries/variants.md +208 -1
- package/docs/it/dynamic_dictionaries/variants.md +209 -2
- package/docs/ja/dynamic_dictionaries/variants.md +209 -2
- package/docs/ko/dynamic_dictionaries/variants.md +209 -2
- package/docs/pl/dynamic_dictionaries/variants.md +209 -2
- package/docs/pt/dynamic_dictionaries/variants.md +208 -1
- package/docs/ru/dynamic_dictionaries/variants.md +209 -2
- package/docs/tr/dynamic_dictionaries/variants.md +209 -2
- package/docs/uk/dynamic_dictionaries/variants.md +208 -1
- package/docs/vi/dynamic_dictionaries/variants.md +210 -3
- package/docs/zh/dynamic_dictionaries/variants.md +209 -2
- package/package.json +6 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-08-04
|
|
4
4
|
title: Biến thể
|
|
5
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:
|
|
@@ -22,7 +22,13 @@ history:
|
|
|
22
22
|
changes: "Phát hành tính năng biến thể"
|
|
23
23
|
- version: 9.1.0
|
|
24
24
|
date: 2026-06-26
|
|
25
|
-
changes: "`variant`
|
|
25
|
+
changes: "`variant` hiện chấp nhận một chuỗi hoặc một đối tượng — trước đây `meta` / bản ghi động được khai báo là biến thể đối tượng"
|
|
26
|
+
- version: 9.1.1
|
|
27
|
+
date: 2026-07-31
|
|
28
|
+
changes: "Biến thể chỉ khai báo các khóa mà nó ghi đè; các biến thể không được khai báo sẽ quay lại mục mặc định"
|
|
29
|
+
- version: 9.1.2
|
|
30
|
+
date: 2026-08-04
|
|
31
|
+
changes: "Provider chấp nhận prop `variant` bao trùm; bộ chọn chấp nhận chuỗi ưu tiên có thứ tự"
|
|
26
32
|
author: aymericzip
|
|
27
33
|
---
|
|
28
34
|
|
|
@@ -77,7 +83,38 @@ const dictionary = {
|
|
|
77
83
|
export default dictionary;
|
|
78
84
|
```
|
|
79
85
|
|
|
80
|
-
###
|
|
86
|
+
### Biến thể một phần
|
|
87
|
+
|
|
88
|
+
Một biến thể **chỉ khai báo các khóa mà nó ghi đè**; phần còn lại được kế thừa từ mục mặc định.
|
|
89
|
+
|
|
90
|
+
```ts fileName="hero-banner.summer.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
91
|
+
import { t, type Dictionary } from "intlayer";
|
|
92
|
+
|
|
93
|
+
const dictionary = {
|
|
94
|
+
key: "hero-banner",
|
|
95
|
+
variant: "summer",
|
|
96
|
+
content: {
|
|
97
|
+
headline: t({
|
|
98
|
+
en: "Build faster all summer",
|
|
99
|
+
fr: "Développez plus vite tout l'été",
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
} satisfies Dictionary;
|
|
103
|
+
|
|
104
|
+
export default dictionary;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
109
|
+
// → { headline: "Développez plus vite tout l'été", cta: "Commencer" } — `cta` được kế thừa
|
|
110
|
+
|
|
111
|
+
useIntlayer("hero-banner", { variant: "never-declared" });
|
|
112
|
+
// → mục mặc định
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Vì vậy, bạn chỉ thêm một tệp biến thể ở nơi văn bản thực sự khác biệt. Một khóa chỉ giải quyết thành `null` khi nó khai báo các biến thể nhưng không có mục mặc định.
|
|
116
|
+
|
|
117
|
+
### Tiêu thụ các biến thể được đặt tên
|
|
81
118
|
|
|
82
119
|
#### Biến thể mặc định
|
|
83
120
|
|
|
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
|
|
|
464
501
|
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
465
502
|
```
|
|
466
503
|
|
|
504
|
+
## Biến thể bao trùm
|
|
505
|
+
|
|
506
|
+
Một số chiều biến thể cố định trong suốt phiên làm việc — tenant, loại trường học, hạng gói. Chúng được xác định một lần, và không component nào phải truyền chúng thủ công.
|
|
507
|
+
|
|
508
|
+
> Đừng bọc `useIntlayer` trong hook riêng của bạn để chèn chúng. Tối ưu hóa lúc build chỉ viết lại lời gọi `useIntlayer("key")` dạng literal được import từ gói framework, nên mọi thứ nằm sau một lớp bọc sẽ không được đóng gói.
|
|
509
|
+
|
|
510
|
+
Thay vào đó, hãy khai báo biến thể một lần trên provider, y như `locale`:
|
|
511
|
+
|
|
512
|
+
<Tabs group="framework">
|
|
513
|
+
<Tab label="React" value="react">
|
|
514
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
515
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
516
|
+
|
|
517
|
+
export const App = ({ locale, schoolType }) => (
|
|
518
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
519
|
+
<Hero />
|
|
520
|
+
</IntlayerProvider>
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
</Tab>
|
|
525
|
+
<Tab label="Next.js" value="nextjs">
|
|
526
|
+
```tsx fileName="layout.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
527
|
+
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
528
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
529
|
+
|
|
530
|
+
export default async function Layout({ children, params }) {
|
|
531
|
+
const { locale } = await params;
|
|
532
|
+
const schoolType = await getSchoolType();
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<IntlayerServerProvider locale={locale} variant={schoolType}>
|
|
536
|
+
<IntlayerClientProvider locale={locale} variant={schoolType}>
|
|
537
|
+
{children}
|
|
538
|
+
</IntlayerClientProvider>
|
|
539
|
+
</IntlayerServerProvider>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
</Tab>
|
|
545
|
+
<Tab label="Vue" value="vue">
|
|
546
|
+
```ts fileName="main.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
547
|
+
import { createApp } from "vue";
|
|
548
|
+
import { installIntlayer } from "vue-intlayer";
|
|
549
|
+
import App from "./App.vue";
|
|
550
|
+
|
|
551
|
+
const app = createApp(App);
|
|
552
|
+
|
|
553
|
+
installIntlayer(app, { locale: "en", variant: schoolType });
|
|
554
|
+
|
|
555
|
+
app.mount("#app");
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
</Tab>
|
|
559
|
+
<Tab label="Svelte" value="svelte">
|
|
560
|
+
```svelte fileName="+layout.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
561
|
+
<script lang="ts">
|
|
562
|
+
import { setupIntlayer } from "svelte-intlayer";
|
|
563
|
+
|
|
564
|
+
export let schoolType: string;
|
|
565
|
+
|
|
566
|
+
setupIntlayer("en", schoolType);
|
|
567
|
+
</script>
|
|
568
|
+
|
|
569
|
+
<slot />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
</Tab>
|
|
573
|
+
<Tab label="Preact" value="preact">
|
|
574
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
575
|
+
import { IntlayerProvider } from "preact-intlayer";
|
|
576
|
+
|
|
577
|
+
export const App = ({ locale, schoolType }) => (
|
|
578
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
579
|
+
<Hero />
|
|
580
|
+
</IntlayerProvider>
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
</Tab>
|
|
585
|
+
<Tab label="Solid" value="solid">
|
|
586
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
587
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
588
|
+
|
|
589
|
+
export const App = (props) => (
|
|
590
|
+
<IntlayerProvider locale={props.locale} variant={props.schoolType}>
|
|
591
|
+
<Hero />
|
|
592
|
+
</IntlayerProvider>
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</Tab>
|
|
597
|
+
<Tab label="Angular" value="angular">
|
|
598
|
+
```typescript fileName="app.config.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
599
|
+
import { ApplicationConfig } from "@angular/core";
|
|
600
|
+
import { provideIntlayer } from "angular-intlayer";
|
|
601
|
+
|
|
602
|
+
export const appConfig: ApplicationConfig = {
|
|
603
|
+
providers: [provideIntlayer("en", true, schoolType)],
|
|
604
|
+
};
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
</Tab>
|
|
608
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
609
|
+
```javascript fileName="main.js"
|
|
610
|
+
import { installIntlayer } from "vanilla-intlayer";
|
|
611
|
+
|
|
612
|
+
installIntlayer({ locale: "en", variant: schoolType });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
</Tab>
|
|
616
|
+
</Tabs>
|
|
617
|
+
|
|
618
|
+
Mọi lần đọc từ điển bên dưới provider giờ đây được phân giải theo biến thể đó, và bộ chọn tại nơi gọi luôn thắng:
|
|
619
|
+
|
|
620
|
+
```tsx
|
|
621
|
+
useIntlayer("hero-banner");
|
|
622
|
+
// → biến thể của provider
|
|
623
|
+
|
|
624
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
625
|
+
// → "summer" — thay thế biến thể của provider, không mở rộng nó
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Các dạng
|
|
629
|
+
|
|
630
|
+
Prop `variant` chấp nhận ba dạng:
|
|
631
|
+
|
|
632
|
+
| Dạng | Ý nghĩa |
|
|
633
|
+
| --------------------------------------------------------- | --------------------------------- |
|
|
634
|
+
| `variant="school1"` | một biến thể có tên cho mọi khóa |
|
|
635
|
+
| `variant={["school1", "default"]}` | một chuỗi ưu tiên có thứ tự |
|
|
636
|
+
| `variant={{ "hero-banner": "school1", default: "base" }}` | một biến thể cho mỗi khóa từ điển |
|
|
637
|
+
|
|
638
|
+
#### Chuỗi ưu tiên
|
|
639
|
+
|
|
640
|
+
Chuỗi được thử từ trái sang phải theo các mục mà mỗi khóa khai báo, và mục được khai báo đầu tiên sẽ thắng. Khi không có mục nào được khai báo, mục mặc định ngầm định sẽ được dùng — hệt như với một giá trị đơn.
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
<IntlayerProvider variant={["school1", "school2"]} />
|
|
644
|
+
// `hero-banner` không khai báo mục `school1` nhưng có khai báo `school2` → "school2"
|
|
645
|
+
// một khóa không khai báo mục nào trong hai → mục mặc định
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Vậy `["black_friday", "summer"]` đọc là «black friday nếu khóa này có, nếu không thì summer, nếu không nữa thì mặc định». Chuỗi cũng được chấp nhận tại nơi gọi:
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
> Lưu ý đây là hình ảnh phản chiếu của mảng được **trường** `variant` trong tệp nội dung chấp nhận: ở đó một mảng _khai báo_ mỗi phần tử một mục, còn ở đây nó _tiêu thụ_ chúng theo thứ tự ưu tiên.
|
|
655
|
+
|
|
656
|
+
#### Ánh xạ theo khóa
|
|
657
|
+
|
|
658
|
+
Chỉ định riêng từng khóa từ điển. Mục `default` được dành riêng sẽ bao phủ mọi khóa không được liệt kê:
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
<IntlayerProvider
|
|
662
|
+
variant={{
|
|
663
|
+
"hero-banner": "school1",
|
|
664
|
+
product: ["school1", "default"],
|
|
665
|
+
default: "base",
|
|
666
|
+
}}
|
|
667
|
+
/>
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
> Trên provider, một object thuần **luôn** được đọc là ánh xạ theo khóa, không bao giờ là biến thể object — hai thứ này giống hệt nhau về cấu trúc. Để cố định một biến thể object trên toàn cục, hãy lồng nó dưới một mục: `variant={{ default: { id: "prod_abc" } }}`.
|
|
671
|
+
|
|
672
|
+
Vì các khóa của ánh xạ được đối chiếu với các khóa từ điển bạn đã khai báo, một lỗi gõ nhầm — hoặc một biến thể object viết trực tiếp, chẳng hạn `variant={{ id: "prod_abc" }}` — sẽ là lỗi biên dịch.
|
|
673
|
+
|
|
467
674
|
## Chế độ tải
|
|
468
675
|
|
|
469
676
|
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:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-08-04
|
|
4
4
|
title: 变体
|
|
5
5
|
description: 在 Intlayer 内容文件中使用 variant 元数据字段来声明具名或结构化的内容替代项——A/B 测试、季节性横幅、功能开关文案、CMS 记录、用户特定内容——并在运行时无需更改代码即可在它们之间切换。
|
|
6
6
|
keywords:
|
|
@@ -22,7 +22,13 @@ history:
|
|
|
22
22
|
changes: "变体功能发布"
|
|
23
23
|
- version: 9.1.0
|
|
24
24
|
date: 2026-06-26
|
|
25
|
-
changes: "`variant`
|
|
25
|
+
changes: "`variant` 现在接受字符串或对象 — 以前的 `meta` / 动态记录现在声明为对象变体"
|
|
26
|
+
- version: 9.1.1
|
|
27
|
+
date: 2026-07-31
|
|
28
|
+
changes: "变体仅声明它覆盖的键;未声明的变体将回退到默认条目"
|
|
29
|
+
- version: 9.1.2
|
|
30
|
+
date: 2026-08-04
|
|
31
|
+
changes: "提供者接受环境级 `variant` 属性;选择器接受有序的优先级链"
|
|
26
32
|
author: aymericzip
|
|
27
33
|
---
|
|
28
34
|
|
|
@@ -77,6 +83,37 @@ const dictionary = {
|
|
|
77
83
|
export default dictionary;
|
|
78
84
|
```
|
|
79
85
|
|
|
86
|
+
### 部分变体
|
|
87
|
+
|
|
88
|
+
变体**仅声明它覆盖的键**;其余部分从默认条目继承。
|
|
89
|
+
|
|
90
|
+
```ts fileName="hero-banner.summer.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
91
|
+
import { t, type Dictionary } from "intlayer";
|
|
92
|
+
|
|
93
|
+
const dictionary = {
|
|
94
|
+
key: "hero-banner",
|
|
95
|
+
variant: "summer",
|
|
96
|
+
content: {
|
|
97
|
+
headline: t({
|
|
98
|
+
en: "Build faster all summer",
|
|
99
|
+
fr: "Développez plus vite tout l'été",
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
} satisfies Dictionary;
|
|
103
|
+
|
|
104
|
+
export default dictionary;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
109
|
+
// → { headline: "Développez plus vite tout l'été", cta: "Commencer" } — 继承了 `cta`
|
|
110
|
+
|
|
111
|
+
useIntlayer("hero-banner", { variant: "never-declared" });
|
|
112
|
+
// → 默认条目
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
因此,您只需在文本确实不同的地方添加变体文件。只有在声明了变体但没有默认条目的情况下,键才会解析为 `null`。
|
|
116
|
+
|
|
80
117
|
### 使用具名变体
|
|
81
118
|
|
|
82
119
|
#### 默认变体
|
|
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
|
|
|
464
501
|
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
465
502
|
```
|
|
466
503
|
|
|
504
|
+
## 环境变体
|
|
505
|
+
|
|
506
|
+
有些变体维度在整个会话中都是固定的——租户、学校类型、套餐等级。它们只需解析一次,任何组件都不应手动传递它们。
|
|
507
|
+
|
|
508
|
+
> 不要为了注入它们而把 `useIntlayer` 包装进你自己的 Hook。构建期优化只会重写从框架包中导入的字面量 `useIntlayer("key")` 调用,因此包装器背后的内容不会被打包。
|
|
509
|
+
|
|
510
|
+
请改为在提供者上声明一次变体,就像 `locale` 一样:
|
|
511
|
+
|
|
512
|
+
<Tabs group="framework">
|
|
513
|
+
<Tab label="React" value="react">
|
|
514
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
515
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
516
|
+
|
|
517
|
+
export const App = ({ locale, schoolType }) => (
|
|
518
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
519
|
+
<Hero />
|
|
520
|
+
</IntlayerProvider>
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
</Tab>
|
|
525
|
+
<Tab label="Next.js" value="nextjs">
|
|
526
|
+
```tsx fileName="layout.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
527
|
+
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
528
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
529
|
+
|
|
530
|
+
export default async function Layout({ children, params }) {
|
|
531
|
+
const { locale } = await params;
|
|
532
|
+
const schoolType = await getSchoolType();
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<IntlayerServerProvider locale={locale} variant={schoolType}>
|
|
536
|
+
<IntlayerClientProvider locale={locale} variant={schoolType}>
|
|
537
|
+
{children}
|
|
538
|
+
</IntlayerClientProvider>
|
|
539
|
+
</IntlayerServerProvider>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
</Tab>
|
|
545
|
+
<Tab label="Vue" value="vue">
|
|
546
|
+
```ts fileName="main.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
547
|
+
import { createApp } from "vue";
|
|
548
|
+
import { installIntlayer } from "vue-intlayer";
|
|
549
|
+
import App from "./App.vue";
|
|
550
|
+
|
|
551
|
+
const app = createApp(App);
|
|
552
|
+
|
|
553
|
+
installIntlayer(app, { locale: "en", variant: schoolType });
|
|
554
|
+
|
|
555
|
+
app.mount("#app");
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
</Tab>
|
|
559
|
+
<Tab label="Svelte" value="svelte">
|
|
560
|
+
```svelte fileName="+layout.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
561
|
+
<script lang="ts">
|
|
562
|
+
import { setupIntlayer } from "svelte-intlayer";
|
|
563
|
+
|
|
564
|
+
export let schoolType: string;
|
|
565
|
+
|
|
566
|
+
setupIntlayer("en", schoolType);
|
|
567
|
+
</script>
|
|
568
|
+
|
|
569
|
+
<slot />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
</Tab>
|
|
573
|
+
<Tab label="Preact" value="preact">
|
|
574
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
575
|
+
import { IntlayerProvider } from "preact-intlayer";
|
|
576
|
+
|
|
577
|
+
export const App = ({ locale, schoolType }) => (
|
|
578
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
579
|
+
<Hero />
|
|
580
|
+
</IntlayerProvider>
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
</Tab>
|
|
585
|
+
<Tab label="Solid" value="solid">
|
|
586
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
587
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
588
|
+
|
|
589
|
+
export const App = (props) => (
|
|
590
|
+
<IntlayerProvider locale={props.locale} variant={props.schoolType}>
|
|
591
|
+
<Hero />
|
|
592
|
+
</IntlayerProvider>
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</Tab>
|
|
597
|
+
<Tab label="Angular" value="angular">
|
|
598
|
+
```typescript fileName="app.config.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
599
|
+
import { ApplicationConfig } from "@angular/core";
|
|
600
|
+
import { provideIntlayer } from "angular-intlayer";
|
|
601
|
+
|
|
602
|
+
export const appConfig: ApplicationConfig = {
|
|
603
|
+
providers: [provideIntlayer("en", true, schoolType)],
|
|
604
|
+
};
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
</Tab>
|
|
608
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
609
|
+
```javascript fileName="main.js"
|
|
610
|
+
import { installIntlayer } from "vanilla-intlayer";
|
|
611
|
+
|
|
612
|
+
installIntlayer({ locale: "en", variant: schoolType });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
</Tab>
|
|
616
|
+
</Tabs>
|
|
617
|
+
|
|
618
|
+
现在提供者下的每次字典读取都会基于该变体解析,而调用处的选择器始终优先:
|
|
619
|
+
|
|
620
|
+
```tsx
|
|
621
|
+
useIntlayer("hero-banner");
|
|
622
|
+
// → 提供者的变体
|
|
623
|
+
|
|
624
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
625
|
+
// → "summer" —— 替换提供者的变体,而不是扩展它
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### 形式
|
|
629
|
+
|
|
630
|
+
`variant` 属性接受三种形式:
|
|
631
|
+
|
|
632
|
+
| 形式 | 含义 |
|
|
633
|
+
| --------------------------------------------------------- | -------------------------- |
|
|
634
|
+
| `variant="school1"` | 对所有键使用同一个具名变体 |
|
|
635
|
+
| `variant={["school1", "default"]}` | 有序的优先级链 |
|
|
636
|
+
| `variant={{ "hero-banner": "school1", default: "base" }}` | 按字典键分别指定变体 |
|
|
637
|
+
|
|
638
|
+
#### 优先级链
|
|
639
|
+
|
|
640
|
+
链会针对每个键所声明的条目从左到右依次尝试,第一个已声明的胜出。若都未声明,则使用隐式的默认条目——与单个值的行为完全一致。
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
<IntlayerProvider variant={["school1", "school2"]} />
|
|
644
|
+
// `hero-banner` 未声明 `school1` 条目,但声明了 `school2` → "school2"
|
|
645
|
+
// 两者都未声明的键 → 默认条目
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
因此 `["black_friday", "summer"]` 可读作「若该键有 black friday 则用它,否则用 summer,再否则用默认」。调用处同样接受链:
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
> 请注意,这与内容文件中 `variant` **字段**所接受的数组正好相反:在那里,数组为每个元素*声明*一个条目;而在这里,它按优先级顺序*消费*这些条目。
|
|
655
|
+
|
|
656
|
+
#### 按键映射
|
|
657
|
+
|
|
658
|
+
分别指定每个字典键。保留的 `default` 条目覆盖所有未列出的键:
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
<IntlayerProvider
|
|
662
|
+
variant={{
|
|
663
|
+
"hero-banner": "school1",
|
|
664
|
+
product: ["school1", "default"],
|
|
665
|
+
default: "base",
|
|
666
|
+
}}
|
|
667
|
+
/>
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
> 在提供者上,普通对象**始终**被解读为按键映射,而绝不会被当作对象变体——两者在结构上完全相同。若要全局指定对象变体,请将其嵌套在某个条目下:`variant={{ default: { id: "prod_abc" } }}`。
|
|
671
|
+
|
|
672
|
+
由于映射的键会与你声明的字典键进行校验,拼写错误——或直接写成对象变体,例如 `variant={{ id: "prod_abc" }}`——都会导致编译期错误。
|
|
673
|
+
|
|
467
674
|
## 加载模式
|
|
468
675
|
|
|
469
676
|
对象变体通常被惰性加载。在字典上设置 `importMode` 以控制此行为:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/docs",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.2",
|
|
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.1.
|
|
77
|
-
"@intlayer/core": "9.1.
|
|
78
|
-
"@intlayer/types": "9.1.
|
|
76
|
+
"@intlayer/config": "9.1.2",
|
|
77
|
+
"@intlayer/core": "9.1.2",
|
|
78
|
+
"@intlayer/types": "9.1.2"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@intlayer/api": "9.1.
|
|
82
|
-
"@intlayer/cli": "9.1.
|
|
81
|
+
"@intlayer/api": "9.1.2",
|
|
82
|
+
"@intlayer/cli": "9.1.2",
|
|
83
83
|
"@types/node": "26.1.2",
|
|
84
84
|
"@utils/ts-config": "1.0.4",
|
|
85
85
|
"@utils/ts-config-types": "1.0.4",
|