@intlayer/docs 9.0.2 → 9.1.1
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 +20 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +20 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/dictionary/content_file.md +24 -1
- package/docs/ar/dictionary/select.md +386 -0
- package/docs/ar/dynamic_dictionaries/variants.md +37 -7
- package/docs/de/dictionary/content_file.md +24 -1
- package/docs/de/dictionary/select.md +386 -0
- package/docs/de/dynamic_dictionaries/variants.md +34 -0
- package/docs/en/dictionary/content_file.md +24 -1
- package/docs/en/dictionary/select.md +382 -0
- package/docs/en/dynamic_dictionaries/variants.md +35 -1
- package/docs/en-GB/dictionary/content_file.md +24 -1
- package/docs/en-GB/dictionary/select.md +385 -0
- package/docs/en-GB/dynamic_dictionaries/variants.md +34 -0
- package/docs/es/dictionary/content_file.md +24 -1
- package/docs/es/dictionary/select.md +385 -0
- package/docs/es/dynamic_dictionaries/variants.md +34 -0
- package/docs/fr/dictionary/content_file.md +24 -1
- package/docs/fr/dictionary/select.md +382 -0
- package/docs/fr/dynamic_dictionaries/variants.md +34 -0
- package/docs/hi/dictionary/content_file.md +24 -1
- package/docs/hi/dictionary/select.md +386 -0
- package/docs/hi/dynamic_dictionaries/variants.md +36 -2
- package/docs/id/dictionary/content_file.md +24 -1
- package/docs/id/dictionary/select.md +386 -0
- package/docs/id/dynamic_dictionaries/variants.md +34 -0
- package/docs/it/dictionary/content_file.md +24 -1
- package/docs/it/dictionary/select.md +386 -0
- package/docs/it/dynamic_dictionaries/variants.md +35 -1
- package/docs/ja/dictionary/content_file.md +24 -1
- package/docs/ja/dictionary/select.md +386 -0
- package/docs/ja/dynamic_dictionaries/variants.md +35 -1
- package/docs/ko/dictionary/content_file.md +24 -1
- package/docs/ko/dictionary/select.md +386 -0
- package/docs/ko/dynamic_dictionaries/variants.md +35 -1
- package/docs/pl/dictionary/content_file.md +24 -1
- package/docs/pl/dictionary/select.md +386 -0
- package/docs/pl/dynamic_dictionaries/variants.md +35 -1
- package/docs/pt/dictionary/content_file.md +24 -1
- package/docs/pt/dictionary/select.md +386 -0
- package/docs/pt/dynamic_dictionaries/variants.md +34 -0
- package/docs/ru/dictionary/content_file.md +25 -2
- package/docs/ru/dictionary/select.md +386 -0
- package/docs/ru/dynamic_dictionaries/variants.md +35 -1
- package/docs/tr/dictionary/content_file.md +24 -1
- package/docs/tr/dictionary/select.md +386 -0
- package/docs/tr/dynamic_dictionaries/variants.md +35 -1
- package/docs/uk/dictionary/content_file.md +24 -1
- package/docs/uk/dictionary/select.md +386 -0
- package/docs/uk/dynamic_dictionaries/variants.md +34 -0
- package/docs/vi/dictionary/content_file.md +24 -1
- package/docs/vi/dictionary/select.md +386 -0
- package/docs/vi/dynamic_dictionaries/variants.md +36 -2
- package/docs/zh/dictionary/content_file.md +24 -1
- package/docs/zh/dictionary/select.md +387 -0
- package/docs/zh/dynamic_dictionaries/variants.md +35 -1
- package/package.json +7 -7
- package/src/generated/docs.entry.ts +20 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-07-30
|
|
3
|
+
updatedAt: 2026-07-30
|
|
4
|
+
title: Nội dung dựa trên lựa chọn (Select)
|
|
5
|
+
description: Tìm hiểu cách sử dụng nội dung dựa trên lựa chọn (select) trong Intlayer để hiển thị động nội dung dựa trên giá trị chuỗi tùy ý. Theo dõi tài liệu này để triển khai hiệu quả nội dung giống như switch trong dự án của bạn.
|
|
6
|
+
keywords:
|
|
7
|
+
- Nội dung dựa trên lựa chọn
|
|
8
|
+
- Select Content
|
|
9
|
+
- Nội dung Switch
|
|
10
|
+
- ICU select
|
|
11
|
+
- Kết xuất động (Dynamic rendering)
|
|
12
|
+
- Tài liệu
|
|
13
|
+
- Intlayer
|
|
14
|
+
- Next.js
|
|
15
|
+
- JavaScript
|
|
16
|
+
- React
|
|
17
|
+
slugs:
|
|
18
|
+
- doc
|
|
19
|
+
- concept
|
|
20
|
+
- content
|
|
21
|
+
- select
|
|
22
|
+
history:
|
|
23
|
+
- version: 9.1.0
|
|
24
|
+
date: 2026-07-30
|
|
25
|
+
changes: "Giới thiệu nội dung dựa trên lựa chọn"
|
|
26
|
+
author: aymericzip
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Nội dung dựa trên lựa chọn (Select) / Intlayer
|
|
30
|
+
|
|
31
|
+
## Select hoạt động như thế nào
|
|
32
|
+
|
|
33
|
+
Trong Intlayer, nội dung dựa trên lựa chọn đạt được thông qua hàm `select`, hàm này ánh xạ các giá trị chuỗi tùy ý tới nội dung tương ứng của chúng. Hàm này tương đương với thông báo ICU `{value, select, …}`, hoặc giống như một câu lệnh `switch` trong mã ứng dụng của bạn.
|
|
34
|
+
|
|
35
|
+
Sử dụng `select` khi yếu tố phân biệt (discriminant) là một chuỗi dạng tự do: trạng thái (status), gói đăng ký (plan), nền tảng (platform) hoặc vai trò (role). Đối với các yếu tố phân biệt khác, Intlayer cung cấp các nút (nodes) chuyên dụng:
|
|
36
|
+
|
|
37
|
+
| Yếu tố phân biệt (Discriminant) | Nút (Node) |
|
|
38
|
+
| ------------------------------- | ---------- |
|
|
39
|
+
| Số lượng (Quantity) | `enu()` |
|
|
40
|
+
| Boolean | `cond()` |
|
|
41
|
+
| Giới tính (Gender) | `gender()` |
|
|
42
|
+
| Bất kỳ chuỗi nào khác | `select()` |
|
|
43
|
+
|
|
44
|
+
## Thiết lập nội dung dựa trên lựa chọn
|
|
45
|
+
|
|
46
|
+
Để thiết lập nội dung dựa trên lựa chọn trong dự án Intlayer của bạn, hãy tạo một module nội dung bao gồm các định nghĩa lựa chọn (select) của bạn. Dưới đây là ví dụ trong các định dạng khác nhau.
|
|
47
|
+
|
|
48
|
+
```typescript fileName="**/*.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
49
|
+
import { select, type Dictionary } from "intlayer";
|
|
50
|
+
|
|
51
|
+
const myPostContent = {
|
|
52
|
+
key: "my_key",
|
|
53
|
+
content: {
|
|
54
|
+
publishStatus: select({
|
|
55
|
+
draft: "This post is a draft",
|
|
56
|
+
published: "This post is live",
|
|
57
|
+
scheduled: "This post is scheduled",
|
|
58
|
+
fallback: "Unknown status", // tùy chọn (optional)
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
} satisfies Dictionary;
|
|
62
|
+
|
|
63
|
+
export default myPostContent;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```json5 fileName="**/*.content.json" contentDeclarationFormat="json"
|
|
67
|
+
{
|
|
68
|
+
"$schema": "https://intlayer.org/schema.json",
|
|
69
|
+
"key": "my_key",
|
|
70
|
+
"content": {
|
|
71
|
+
"publishStatus": {
|
|
72
|
+
"nodeType": "select",
|
|
73
|
+
"select": {
|
|
74
|
+
"draft": "This post is a draft",
|
|
75
|
+
"published": "This post is live",
|
|
76
|
+
"scheduled": "This post is scheduled",
|
|
77
|
+
"fallback": "Unknown status", // tùy chọn (optional)
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> Nếu không có `fallback` nào được khai báo, khóa (key) được khai báo cuối cùng sẽ được coi là dự phòng khi giá trị được cung cấp không khớp với bất kỳ trường hợp nào đã được khai báo: giống hệt như thỏa thuận (contract) của `cond()` và `gender()`.
|
|
85
|
+
|
|
86
|
+
### An toàn kiểu (Type Safety)
|
|
87
|
+
|
|
88
|
+
Tham số được chấp nhận được suy luận từ các trường hợp đã được khai báo:
|
|
89
|
+
|
|
90
|
+
- Nếu không có `fallback`, chỉ các trường hợp đã khai báo mới được chấp nhận: việc đánh máy sai sẽ tạo ra một lỗi kiểu (type error).
|
|
91
|
+
- Nếu có `fallback`, bất kỳ chuỗi nào cũng được chấp nhận (bởi vì fallback bao gồm các giá trị không khớp) trong khi các trường hợp đã khai báo vẫn cung cấp tính năng tự động hoàn thành (autocompletion).
|
|
92
|
+
|
|
93
|
+
## Tại sao không sử dụng một đối tượng thông thường?
|
|
94
|
+
|
|
95
|
+
Sẽ rất hấp dẫn nếu khai báo một đối tượng (object) thông thường và lập chỉ mục (index) vào đó bằng cách sử dụng một giá trị trong thời gian chạy (runtime value):
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
// ❌ Đừng làm điều này
|
|
99
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
100
|
+
|
|
101
|
+
return <p>{publishStatus[publishType]}</p>;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Trình biên dịch (compiler) Intlayer phân tích mã nguồn của bạn để loại bỏ nội dung không sử dụng và thu nhỏ (minify) các khóa còn lại. Việc truy cập được tính toán động (`obj[expr]`) không thể được giải quyết tĩnh (statically resolved), do đó toàn bộ nhánh sẽ được đánh dấu là mờ (opaque): nó sẽ được giữ lại trong gói (bundle) và các khóa của nó sẽ không được thu nhỏ.
|
|
105
|
+
|
|
106
|
+
Bằng cách sử dụng `select()`, việc giải quyết trường hợp (case resolution) diễn ra bên trong một lệnh gọi hàm thay vì là một truy cập thuộc tính (property access). Trình biên dịch coi nó là một truy cập trường tĩnh (static field access) đơn lẻ, và tối ưu hóa nút này một cách chính xác như những gì nó làm với `enu()`, `cond()`, hoặc `gender()`:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// ✅ Hãy làm điều này
|
|
110
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
111
|
+
|
|
112
|
+
return <p>{publishStatus(publishType)}</p>;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Sử dụng nội dung dựa trên lựa chọn
|
|
116
|
+
|
|
117
|
+
<Tabs group="framework">
|
|
118
|
+
<Tab label="React" value="react">
|
|
119
|
+
|
|
120
|
+
Để tận dụng nội dung dựa trên lựa chọn trong một component React, hãy nhập khẩu (import) và sử dụng hook `useIntlayer` từ gói `react-intlayer`. Hook này lấy (fetch) nội dung cho khóa (key) đã chỉ định và cho phép bạn truyền một giá trị vào để chọn đầu ra thích hợp.
|
|
121
|
+
|
|
122
|
+
```tsx fileName="**/*.tsx" codeFormat={["typescript", "esm"]}
|
|
123
|
+
import type { FC } from "react";
|
|
124
|
+
import { useIntlayer } from "react-intlayer";
|
|
125
|
+
|
|
126
|
+
const PostStatus: FC = () => {
|
|
127
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div>
|
|
131
|
+
<p>
|
|
132
|
+
{
|
|
133
|
+
/* Đầu ra: This post is a draft */
|
|
134
|
+
publishStatus("draft")
|
|
135
|
+
}
|
|
136
|
+
</p>
|
|
137
|
+
<p>
|
|
138
|
+
{
|
|
139
|
+
/* Đầu ra: This post is live */
|
|
140
|
+
publishStatus("published")
|
|
141
|
+
}
|
|
142
|
+
</p>
|
|
143
|
+
<p>
|
|
144
|
+
{
|
|
145
|
+
/* Đầu ra: Unknown status */
|
|
146
|
+
publishStatus("Archived")
|
|
147
|
+
}
|
|
148
|
+
</p>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default PostStatus;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
</Tab>
|
|
157
|
+
<Tab label="Next.js" value="nextjs">
|
|
158
|
+
|
|
159
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các Client Components của Next.js, hãy lấy nội dung thông qua hook `useIntlayer`. Đây là một ví dụ:
|
|
160
|
+
|
|
161
|
+
```tsx fileName="**/*.tsx" codeFormat={["typescript", "esm"]}
|
|
162
|
+
"use client";
|
|
163
|
+
|
|
164
|
+
import type { FC } from "react";
|
|
165
|
+
import { useIntlayer } from "next-intlayer";
|
|
166
|
+
|
|
167
|
+
const PostStatus: FC = () => {
|
|
168
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div>
|
|
172
|
+
<p>{publishStatus("draft")}</p>
|
|
173
|
+
<p>{publishStatus("published")}</p>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export default PostStatus;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
</Tab>
|
|
182
|
+
<Tab label="Vue" value="vue">
|
|
183
|
+
|
|
184
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các component Vue, hãy lấy nội dung thông qua hook `useIntlayer`. Đây là một ví dụ:
|
|
185
|
+
|
|
186
|
+
```vue fileName="**/*.vue"
|
|
187
|
+
<script setup lang="ts">
|
|
188
|
+
import { useIntlayer } from "vue-intlayer";
|
|
189
|
+
|
|
190
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
191
|
+
</script>
|
|
192
|
+
|
|
193
|
+
<template>
|
|
194
|
+
<div>
|
|
195
|
+
<p>{{ publishStatus("draft") }}</p>
|
|
196
|
+
<p>{{ publishStatus("published") }}</p>
|
|
197
|
+
</div>
|
|
198
|
+
</template>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
</Tab>
|
|
202
|
+
<Tab label="Svelte" value="svelte">
|
|
203
|
+
|
|
204
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các component Svelte, hãy lấy nội dung thông qua hook `useIntlayer`. Store (kho lưu trữ) được truy cập bằng cách sử dụng dấu `$`. Đây là một ví dụ:
|
|
205
|
+
|
|
206
|
+
```svelte fileName="**/*.svelte"
|
|
207
|
+
<script lang="ts">
|
|
208
|
+
import { useIntlayer } from "svelte-intlayer";
|
|
209
|
+
|
|
210
|
+
const content = useIntlayer("my_key");
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<div>
|
|
214
|
+
<p>{$content.publishStatus("draft")}</p>
|
|
215
|
+
<p>{$content.publishStatus("published")}</p>
|
|
216
|
+
</div>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
</Tab>
|
|
220
|
+
<Tab label="Preact" value="preact">
|
|
221
|
+
|
|
222
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các component Preact, hãy lấy nội dung thông qua hook `useIntlayer`. Đây là một ví dụ:
|
|
223
|
+
|
|
224
|
+
```tsx fileName="**/*.tsx" codeFormat={["typescript", "esm"]}
|
|
225
|
+
import type { FC } from "preact";
|
|
226
|
+
import { useIntlayer } from "preact-intlayer";
|
|
227
|
+
|
|
228
|
+
const PostStatus: FC = () => {
|
|
229
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<div>
|
|
233
|
+
<p>{publishStatus("draft")}</p>
|
|
234
|
+
<p>{publishStatus("published")}</p>
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export default PostStatus;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
</Tab>
|
|
243
|
+
<Tab label="Solid" value="solid">
|
|
244
|
+
|
|
245
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các component SolidJS, hãy lấy nội dung thông qua hook `useIntlayer`. Đây là một ví dụ:
|
|
246
|
+
|
|
247
|
+
```tsx fileName="**/*.tsx" codeFormat={["typescript", "esm"]}
|
|
248
|
+
import type { Component } from "solid-js";
|
|
249
|
+
import { useIntlayer } from "solid-intlayer";
|
|
250
|
+
|
|
251
|
+
const PostStatus: Component = () => {
|
|
252
|
+
const { publishStatus } = useIntlayer("my_key");
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<div>
|
|
256
|
+
<p>{publishStatus("draft")}</p>
|
|
257
|
+
<p>{publishStatus("published")}</p>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export default PostStatus;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
</Tab>
|
|
266
|
+
<Tab label="Angular" value="angular">
|
|
267
|
+
|
|
268
|
+
Để tận dụng nội dung dựa trên lựa chọn trong các component Angular, hãy lấy nội dung thông qua hook `useIntlayer`. Đây là một ví dụ:
|
|
269
|
+
|
|
270
|
+
```typescript fileName="app.component.ts" codeFormat="typescript"
|
|
271
|
+
import { Component } from "@angular/core";
|
|
272
|
+
import { useIntlayer } from "angular-intlayer";
|
|
273
|
+
|
|
274
|
+
@Component({
|
|
275
|
+
selector: "app-post-status",
|
|
276
|
+
template: `
|
|
277
|
+
<div>
|
|
278
|
+
<p>{{ content().publishStatus("draft") }}</p>
|
|
279
|
+
<p>{{ content().publishStatus("published") }}</p>
|
|
280
|
+
</div>
|
|
281
|
+
`,
|
|
282
|
+
})
|
|
283
|
+
export class PostStatusComponent {
|
|
284
|
+
content = useIntlayer("my_key");
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
</Tab>
|
|
289
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
290
|
+
|
|
291
|
+
Để tận dụng nội dung dựa trên lựa chọn với `vanilla-intlayer`, hãy lấy nội dung thông qua hàm `useIntlayer`. Đây là một ví dụ:
|
|
292
|
+
|
|
293
|
+
```typescript fileName="**/*.ts" codeFormat={["typescript", "esm"]}
|
|
294
|
+
import { installIntlayer, useIntlayer } from "vanilla-intlayer";
|
|
295
|
+
|
|
296
|
+
installIntlayer();
|
|
297
|
+
|
|
298
|
+
const content = useIntlayer("my_key").onChange((newContent) => {
|
|
299
|
+
document.getElementById("status")!.textContent =
|
|
300
|
+
newContent.publishStatus("draft");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Lần hiển thị ban đầu (Initial render)
|
|
304
|
+
document.getElementById("status")!.textContent = content.publishStatus("draft");
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
</Tab>
|
|
308
|
+
</Tabs>
|
|
309
|
+
|
|
310
|
+
## Kết hợp Select với các Nút (Nodes) khác
|
|
311
|
+
|
|
312
|
+
Bởi vì mỗi trường hợp (case) chứa một nút nội dung đầy đủ (full content node), `select` có thể được kết hợp với các nút như `t()`, `insert()`, `md()`, v.v.:
|
|
313
|
+
|
|
314
|
+
```typescript fileName="**/*.content.ts" codeFormat="typescript"
|
|
315
|
+
import { insert, select, t, type Dictionary } from "intlayer";
|
|
316
|
+
|
|
317
|
+
const myPostContent = {
|
|
318
|
+
key: "my_key",
|
|
319
|
+
content: {
|
|
320
|
+
publishStatus: select({
|
|
321
|
+
draft: insert(
|
|
322
|
+
t({
|
|
323
|
+
en: "{{name}} saved a draft",
|
|
324
|
+
fr: "{{name}} a enregistré un brouillon",
|
|
325
|
+
vi: "{{name}} đã lưu một bản nháp",
|
|
326
|
+
})
|
|
327
|
+
),
|
|
328
|
+
published: insert(
|
|
329
|
+
t({
|
|
330
|
+
en: "{{name}} published the post",
|
|
331
|
+
fr: "{{name}} a publié l’article",
|
|
332
|
+
vi: "{{name}} đã xuất bản bài viết",
|
|
333
|
+
})
|
|
334
|
+
),
|
|
335
|
+
fallback: insert(
|
|
336
|
+
t({
|
|
337
|
+
en: "{{name}} updated the post",
|
|
338
|
+
fr: "{{name}} a mis à jour l’article",
|
|
339
|
+
vi: "{{name}} đã cập nhật bài viết",
|
|
340
|
+
})
|
|
341
|
+
),
|
|
342
|
+
}),
|
|
343
|
+
},
|
|
344
|
+
} satisfies Dictionary;
|
|
345
|
+
|
|
346
|
+
export default myPostContent;
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
publishStatus("draft")({ name: "Alice" }); // Đầu ra: Alice đã lưu một bản nháp
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Chuyển đổi từ ICU `select`
|
|
354
|
+
|
|
355
|
+
Các thông báo sử dụng tham số `select` của ICU sẽ được nhập (imported) dưới dạng nút (node) `select`:
|
|
356
|
+
|
|
357
|
+
```text
|
|
358
|
+
{publishType, select, draft {draft} published {published} other {Unknown}}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Sẽ trở thành:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
select(
|
|
365
|
+
{
|
|
366
|
+
draft: "draft",
|
|
367
|
+
published: "published",
|
|
368
|
+
fallback: "Unknown",
|
|
369
|
+
},
|
|
370
|
+
"publishType"
|
|
371
|
+
);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Trường hợp `other` của ICU được đổi tên thành `fallback`, tên chuẩn (canonical name) trong Intlayer cho tất cả các trường hợp bao gồm (catch-all cases). Tham số thứ hai lưu lại tên biến ICU để thông báo sẽ biến đổi trở lại thành đúng chuỗi ICU đó khi xuất (export).
|
|
375
|
+
|
|
376
|
+
> Xin lưu ý, thông báo ICU `select` nơi các trường hợp là các giá trị giới tính (`male` / `female` / `other`) thay vào đó sẽ được nhập dưới dạng nút [`gender`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/gender.md).
|
|
377
|
+
|
|
378
|
+
## Tài nguyên Bổ sung
|
|
379
|
+
|
|
380
|
+
Để biết thêm thông tin chi tiết về cấu hình và cách sử dụng, hãy xem các tài nguyên sau:
|
|
381
|
+
|
|
382
|
+
- [Tài liệu Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/cli/index.md)
|
|
383
|
+
- [Tài liệu Intlayer React](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_with_create_react_app.md)
|
|
384
|
+
- [Tài liệu Intlayer Next.js](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/intlayer_with_nextjs_15.md)
|
|
385
|
+
|
|
386
|
+
Các tài nguyên này cung cấp thêm thông tin chi tiết về việc thiết lập và sử dụng Intlayer trong các môi trường và framework khác nhau.
|
|
@@ -22,7 +22,10 @@ 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"
|
|
26
29
|
author: aymericzip
|
|
27
30
|
---
|
|
28
31
|
|
|
@@ -77,7 +80,38 @@ const dictionary = {
|
|
|
77
80
|
export default dictionary;
|
|
78
81
|
```
|
|
79
82
|
|
|
80
|
-
###
|
|
83
|
+
### Biến thể một phần
|
|
84
|
+
|
|
85
|
+
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.
|
|
86
|
+
|
|
87
|
+
```ts fileName="hero-banner.summer.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
88
|
+
import { t, type Dictionary } from "intlayer";
|
|
89
|
+
|
|
90
|
+
const dictionary = {
|
|
91
|
+
key: "hero-banner",
|
|
92
|
+
variant: "summer",
|
|
93
|
+
content: {
|
|
94
|
+
headline: t({
|
|
95
|
+
en: "Build faster all summer",
|
|
96
|
+
fr: "Développez plus vite tout l'été",
|
|
97
|
+
}),
|
|
98
|
+
},
|
|
99
|
+
} satisfies Dictionary;
|
|
100
|
+
|
|
101
|
+
export default dictionary;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
106
|
+
// → { headline: "Développez plus vite tout l'été", cta: "Commencer" } — `cta` được kế thừa
|
|
107
|
+
|
|
108
|
+
useIntlayer("hero-banner", { variant: "never-declared" });
|
|
109
|
+
// → mục mặc định
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
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.
|
|
113
|
+
|
|
114
|
+
### Tiêu thụ các biến thể được đặt tên
|
|
81
115
|
|
|
82
116
|
#### Biến thể mặc định
|
|
83
117
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-02-07
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-07-30
|
|
4
4
|
title: 内容文件
|
|
5
5
|
description: 学习如何自定义内容声明文件的扩展。按照本指南高效地在项目中实现条件。
|
|
6
6
|
keywords:
|
|
@@ -12,6 +12,9 @@ slugs:
|
|
|
12
12
|
- concept
|
|
13
13
|
- content
|
|
14
14
|
history:
|
|
15
|
+
- version: 9.1.0
|
|
16
|
+
date: 2026-07-30
|
|
17
|
+
changes: "引入基于选择的内容"
|
|
15
18
|
- version: 8.10.0
|
|
16
19
|
date: 2026-05-19
|
|
17
20
|
changes: "添加对 YAML 和 Markdown 文件格式的支持"
|
|
@@ -254,6 +257,7 @@ Intlayer 通过类型化节点支持多种内容类型:
|
|
|
254
257
|
- **HTML 内容**:富 HTML 内容,可使用标准标签或自定义组件 [参见 HTML 内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/html.md)
|
|
255
258
|
- **嵌套内容**:对其他字典的引用 [参见 嵌套内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/nested_content.md)
|
|
256
259
|
- **性别内容**:基于性别变化的内容 [参见 性别内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/gender_content.md)
|
|
260
|
+
- **基于选择的内容**:基于任意字符串值变化的内容 [参见 基于选择的内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/select.md)
|
|
257
261
|
- **文件内容**:对外部文件的引用 [参见 文件内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/file_content.md)
|
|
258
262
|
|
|
259
263
|
## 字典结构
|
|
@@ -753,6 +757,25 @@ genderContent: gender({
|
|
|
753
757
|
|
|
754
758
|
> 请参阅 [性别内容 (`gender`) 文档](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/gender.md) 以获取更多信息。
|
|
755
759
|
|
|
760
|
+
### 基于选择的内容 (`select`)
|
|
761
|
+
|
|
762
|
+
基于任意字符串值变化的内容——相当于 ICU 的 `select`:
|
|
763
|
+
|
|
764
|
+
```typescript
|
|
765
|
+
import { select } from "intlayer";
|
|
766
|
+
|
|
767
|
+
selectContent: select({
|
|
768
|
+
draft: "This post is a draft",
|
|
769
|
+
published: "This post is live",
|
|
770
|
+
scheduled: "This post is scheduled",
|
|
771
|
+
fallback: "Unknown status",
|
|
772
|
+
});
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
当判别条件不是数量 (`enu`)、布尔值 (`cond`),也不是性别 (`gender`) 时,请使用 `select`。将其优先于使用运行时值索引简单对象:动态计算访问无法由 Intlayer 编译器静态解析。
|
|
776
|
+
|
|
777
|
+
> 参见 [基于选择的内容](https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/dictionary/select.md) 了解更多信息。
|
|
778
|
+
|
|
756
779
|
### 文件内容 (`file`)
|
|
757
780
|
|
|
758
781
|
引用外部文件:
|