@intlayer/docs 8.4.5 → 8.4.6

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 (48) hide show
  1. package/dist/cjs/generated/docs.entry.cjs +20 -0
  2. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  3. package/dist/esm/generated/docs.entry.mjs +20 -0
  4. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  5. package/dist/types/generated/docs.entry.d.ts +1 -0
  6. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  7. package/docs/ar/configuration.md +520 -722
  8. package/docs/ar/intlayer_with_storybook.md +521 -0
  9. package/docs/bn/configuration.md +922 -0
  10. package/docs/bn/intlayer_with_hono.md +428 -0
  11. package/docs/de/configuration.md +369 -743
  12. package/docs/de/intlayer_with_storybook.md +521 -0
  13. package/docs/en/configuration.md +181 -507
  14. package/docs/en/intlayer_with_storybook.md +521 -0
  15. package/docs/en-GB/configuration.md +456 -657
  16. package/docs/en-GB/intlayer_with_storybook.md +521 -0
  17. package/docs/es/configuration.md +379 -754
  18. package/docs/es/intlayer_with_storybook.md +521 -0
  19. package/docs/fr/configuration.md +376 -757
  20. package/docs/fr/intlayer_with_storybook.md +521 -0
  21. package/docs/hi/configuration.md +532 -728
  22. package/docs/hi/intlayer_with_storybook.md +521 -0
  23. package/docs/id/configuration.md +371 -684
  24. package/docs/id/intlayer_with_storybook.md +521 -0
  25. package/docs/it/configuration.md +397 -775
  26. package/docs/it/intlayer_with_storybook.md +521 -0
  27. package/docs/ja/configuration.md +525 -724
  28. package/docs/ja/intlayer_with_storybook.md +521 -0
  29. package/docs/ko/configuration.md +525 -724
  30. package/docs/ko/intlayer_with_storybook.md +521 -0
  31. package/docs/pl/configuration.md +430 -734
  32. package/docs/pl/intlayer_with_storybook.md +521 -0
  33. package/docs/pt/configuration.md +375 -746
  34. package/docs/pt/intlayer_with_storybook.md +521 -0
  35. package/docs/ru/configuration.md +532 -701
  36. package/docs/ru/intlayer_with_storybook.md +521 -0
  37. package/docs/tr/configuration.md +527 -719
  38. package/docs/tr/intlayer_with_storybook.md +521 -0
  39. package/docs/uk/configuration.md +425 -744
  40. package/docs/uk/intlayer_with_storybook.md +521 -0
  41. package/docs/ur/configuration.md +922 -0
  42. package/docs/ur/intlayer_with_hono.md +428 -0
  43. package/docs/vi/configuration.md +412 -753
  44. package/docs/vi/intlayer_with_storybook.md +521 -0
  45. package/docs/zh/configuration.md +521 -714
  46. package/docs/zh/intlayer_with_storybook.md +521 -0
  47. package/package.json +6 -6
  48. package/src/generated/docs.entry.ts +20 -0
@@ -0,0 +1,521 @@
1
+ ---
2
+ createdAt: 2026-03-20
3
+ updatedAt: 2026-03-20
4
+ title: Cách thiết lập Intlayer với Storybook
5
+ description: Tìm hiểu cách làm cho hệ thống thiết kế của bạn đa ngôn ngữ bằng cách sử dụng Intlayer với Storybook — biên dịch các khai báo nội dung, thêm trình chuyển đổi ngôn ngữ và xem trước các thành phần của bạn bằng bất kỳ ngôn ngữ nào.
6
+ keywords:
7
+ - Quốc tế hóa
8
+ - Tài liệu
9
+ - Intlayer
10
+ - Storybook
11
+ - React
12
+ - i18n
13
+ - TypeScript
14
+ - Vite
15
+ - Webpack
16
+ slugs:
17
+ - doc
18
+ - storybook
19
+ history:
20
+ - version: 8.4.5
21
+ date: 2026-03-20
22
+ changes: Init doc
23
+ ---
24
+
25
+ # Intlayer với Storybook
26
+
27
+ ## Mục lục
28
+
29
+ <TOC/>
30
+
31
+ ## Intlayer là gì?
32
+
33
+ **Intlayer** là một thư viện quốc tế hóa (i18n) mã nguồn mở sáng tạo được thiết kế để đơn giản hóa việc hỗ trợ đa ngôn ngữ trong các ứng dụng web hiện đại. Nó hoạt động ở **cấp độ thành phần** — mỗi thành phần sở hữu các khai báo nội dung riêng — giữ cho các bản dịch được đặt cùng với mã nguồn sử dụng chúng.
34
+
35
+ Với Intlayer, bạn có thể:
36
+
37
+ - **Quản lý các bản dịch một cách khai báo** với các tệp nội dung trên từng thành phần.
38
+ - **Hỗ trợ đầy đủ TypeScript** thông qua các kiểu dữ liệu được tạo tự động và tính năng tự động hoàn thành của IDE.
39
+ - **Chuyển đổi ngôn ngữ khi đang chạy** mà không cần tải lại trang.
40
+ - **Tự động dịch** với các tích hợp nhà cung cấp AI được tích hợp sẵn.
41
+
42
+ ---
43
+
44
+ ## Tại sao nên sử dụng Intlayer với Storybook?
45
+
46
+ Storybook là công cụ tiêu chuẩn trong ngành để phát triển và lập tài liệu cho các thành phần UI một cách độc lập. Việc kết hợp nó với Intlayer cho phép bạn:
47
+
48
+ - **Xem trước mọi ngôn ngữ** trực tiếp bên trong canvas của Storybook bằng trình chuyển đổi trên thanh công cụ.
49
+ - **Phát hiện các bản dịch còn thiếu** trước khi chúng được đưa vào sản xuất.
50
+ - **Lập tài liệu cho các thành phần đa ngôn ngữ** với nội dung thực tế, an toàn về kiểu dữ liệu thay vì các chuỗi được mã hóa cứng.
51
+
52
+ ---
53
+
54
+ ## Thiết lập từng bước
55
+
56
+ <Tabs>
57
+ <Tab value="Vite Setup">
58
+
59
+ ### Bước 1: Cài đặt các phụ thuộc
60
+
61
+ ```bash packageManager="npm"
62
+ npm install intlayer react-intlayer
63
+ npm install vite-intlayer --save-dev
64
+ ```
65
+
66
+ ```bash packageManager="pnpm"
67
+ pnpm add intlayer react-intlayer
68
+ pnpm add vite-intlayer --save-dev
69
+ ```
70
+
71
+ ```bash packageManager="yarn"
72
+ yarn add intlayer react-intlayer
73
+ yarn add vite-intlayer --save-dev
74
+ ```
75
+
76
+ ```bash packageManager="bun"
77
+ bun add intlayer react-intlayer
78
+ bun add vite-intlayer --dev
79
+ ```
80
+
81
+ | Gói | Vai trò |
82
+ | ---------------- | ------------------------------------------------------------- |
83
+ | `intlayer` | Cốt lõi — cấu hình, biên dịch nội dung, CLI |
84
+ | `react-intlayer` | Liên kết React — `IntlayerProvider`, hook `useIntlayer` |
85
+ | `vite-intlayer` | Plugin Vite — theo dõi và biên dịch các tệp khai báo nội dung |
86
+
87
+ ---
88
+
89
+ ### Bước 2: Tạo cấu hình Intlayer
90
+
91
+ Tạo `intlayer.config.ts` tại thư mục gốc của dự án (hoặc bên trong gói hệ thống thiết kế của bạn):
92
+
93
+ ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
94
+ import { Locales, type IntlayerConfig } from "intlayer";
95
+
96
+ const config: IntlayerConfig = {
97
+ internationalization: {
98
+ locales: [
99
+ Locales.ENGLISH,
100
+ Locales.FRENCH,
101
+ Locales.SPANISH,
102
+ // thêm các ngôn ngữ khác nếu cần
103
+ ],
104
+ defaultLocale: Locales.ENGLISH,
105
+ },
106
+ content: {
107
+ contentDir: ["./src"], // nơi chứa các tệp *.content.ts của bạn
108
+ },
109
+ };
110
+
111
+ export default config;
112
+ ```
113
+
114
+ > Để xem danh sách đầy đủ các tùy chọn, hãy tham khảo [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/configuration.md).
115
+
116
+ ---
117
+
118
+ ### Bước 3: Thêm Plugin Vite vào Storybook
119
+
120
+ Hook `viteFinal` của Storybook cho phép bạn mở rộng cấu hình Vite nội bộ. Nhập và thêm plugin `intlayer()` tại đó:
121
+
122
+ ```typescript fileName=".storybook/main.ts" codeFormat="typescript"
123
+ import type { StorybookConfig } from "@storybook/react-vite";
124
+ import { defineConfig, mergeConfig } from "vite";
125
+ import { intlayer } from "vite-intlayer";
126
+
127
+ const config: StorybookConfig = {
128
+ stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
129
+ addons: [
130
+ "@storybook/addon-essentials",
131
+ // …các addon khác
132
+ ],
133
+ framework: {
134
+ name: "@storybook/react-vite",
135
+ options: {},
136
+ },
137
+
138
+ async viteFinal(baseConfig, { configType }) {
139
+ const env = {
140
+ command: configType === "DEVELOPMENT" ? "serve" : "build",
141
+ mode: configType === "DEVELOPMENT" ? "development" : "production",
142
+ } as const;
143
+
144
+ const viteConfig = defineConfig(() => ({
145
+ plugins: [intlayer()],
146
+ }));
147
+
148
+ return mergeConfig(baseConfig, viteConfig(env));
149
+ },
150
+ };
151
+
152
+ export default config;
153
+ ```
154
+
155
+ Plugin `intlayer()` theo dõi các tệp `*.content.ts` của bạn và tự động xây dựng lại các từ điển bất cứ khi nào chúng thay đổi trong quá trình phát triển trên Storybook.
156
+
157
+ ---
158
+
159
+ ### Bước 4: Thêm Decorator `IntlayerProvider` và Thanh công cụ Ngôn ngữ
160
+
161
+ Tệp `preview` của Storybook là nơi thích hợp để bao bọc mọi câu chuyện với `IntlayerProvider` và hiển thị trình chuyển đổi ngôn ngữ trên thanh công cụ:
162
+
163
+ ```tsx fileName=".storybook/preview.tsx" codeFormat="typescript"
164
+ import type { Preview, StoryContext } from "@storybook/react";
165
+ import { IntlayerProvider } from "react-intlayer";
166
+
167
+ const preview: Preview = {
168
+ // Bao bọc mọi câu chuyện bên trong IntlayerProvider
169
+ decorators: [
170
+ (Story, context: StoryContext) => {
171
+ const locale = context.globals.locale ?? "en";
172
+ return (
173
+ <IntlayerProvider locale={locale}>
174
+ <Story />
175
+ </IntlayerProvider>
176
+ );
177
+ },
178
+ ],
179
+
180
+ // Hiển thị trình chuyển đổi ngôn ngữ trên thanh công cụ Storybook
181
+ globalTypes: {
182
+ locale: {
183
+ description: "Ngôn ngữ đang kích hoạt",
184
+ defaultValue: "en",
185
+ toolbar: {
186
+ title: "Ngôn ngữ",
187
+ icon: "globe",
188
+ items: [
189
+ { value: "en", title: "English" },
190
+ { value: "fr", title: "Français" },
191
+ { value: "es", title: "Español" },
192
+ ],
193
+ dynamicTitle: true,
194
+ },
195
+ },
196
+ },
197
+
198
+ parameters: {
199
+ controls: {
200
+ matchers: {
201
+ color: /(background|color)$/i,
202
+ date: /Date$/i,
203
+ },
204
+ },
205
+ },
206
+ };
207
+
208
+ export default preview;
209
+ ```
210
+
211
+ > Các giá trị `locale` phải khớp với các ngôn ngữ được khai báo trong `intlayer.config.ts` của bạn.
212
+
213
+ </Tab>
214
+ <Tab value="Webpack Setup">
215
+
216
+ ### Bước 1: Cài đặt các phụ thuộc
217
+
218
+ ```bash packageManager="npm"
219
+ npm install intlayer react-intlayer
220
+ npm install @intlayer/webpack --save-dev
221
+ ```
222
+
223
+ ```bash packageManager="pnpm"
224
+ pnpm add intlayer react-intlayer
225
+ pnpm add @intlayer/webpack --save-dev
226
+ ```
227
+
228
+ ```bash packageManager="yarn"
229
+ yarn add intlayer react-intlayer
230
+ yarn add @intlayer/webpack --save-dev
231
+ ```
232
+
233
+ ```bash packageManager="bun"
234
+ bun add intlayer react-intlayer
235
+ bun add @intlayer/webpack --dev
236
+ ```
237
+
238
+ ---
239
+
240
+ ### Bước 2: Tạo cấu hình Intlayer
241
+
242
+ Tạo `intlayer.config.ts` tại thư mục gốc của dự án:
243
+
244
+ ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
245
+ import { Locales, type IntlayerConfig } from "intlayer";
246
+
247
+ const config: IntlayerConfig = {
248
+ internationalization: {
249
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
250
+ defaultLocale: Locales.ENGLISH,
251
+ },
252
+ content: {
253
+ contentDir: ["./src"],
254
+ },
255
+ };
256
+
257
+ export default config;
258
+ ```
259
+
260
+ ---
261
+
262
+ ### Bước 3: Cấu hình Webpack của Storybook
263
+
264
+ Đối với các thiết lập Storybook dựa trên Webpack (ví dụ: `@storybook/react-webpack5`), hãy mở rộng cấu hình webpack thông qua `webpackFinal` để thêm các alias và loader của Intlayer:
265
+
266
+ ```typescript fileName=".storybook/main.ts" codeFormat="typescript"
267
+ import type { StorybookConfig } from "@storybook/react-webpack5";
268
+ import { IntlayerWebpackPlugin } from "@intlayer/webpack";
269
+
270
+ const config: StorybookConfig = {
271
+ stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
272
+ addons: ["@storybook/addon-essentials"],
273
+ framework: {
274
+ name: "@storybook/react-webpack5",
275
+ options: {},
276
+ },
277
+
278
+ webpackFinal: async (baseConfig) => {
279
+ baseConfig.plugins = [
280
+ ...(baseConfig.plugins ?? []),
281
+ new IntlayerWebpackPlugin(),
282
+ ];
283
+ return baseConfig;
284
+ },
285
+ };
286
+
287
+ export default config;
288
+ ```
289
+
290
+ ---
291
+
292
+ ### Bước 4: Thêm Decorator `IntlayerProvider` và Thanh công cụ Ngôn ngữ
293
+
294
+ Tương tự như thiết lập Vite — thêm decorator và kiểu ngôn ngữ toàn cục trong tệp `.storybook/preview.tsx`:
295
+
296
+ ```tsx fileName=".storybook/preview.tsx" codeFormat="typescript"
297
+ import type { Preview, StoryContext } from "@storybook/react";
298
+ import { IntlayerProvider } from "react-intlayer";
299
+
300
+ const preview: Preview = {
301
+ decorators: [
302
+ (Story, context: StoryContext) => {
303
+ const locale = context.globals.locale ?? "en";
304
+ return (
305
+ <IntlayerProvider locale={locale}>
306
+ <Story />
307
+ </IntlayerProvider>
308
+ );
309
+ },
310
+ ],
311
+
312
+ globalTypes: {
313
+ locale: {
314
+ description: "Ngôn ngữ đang kích hoạt",
315
+ defaultValue: "en",
316
+ toolbar: {
317
+ title: "Ngôn ngữ",
318
+ icon: "globe",
319
+ items: [
320
+ { value: "en", title: "English" },
321
+ { value: "fr", title: "Français" },
322
+ { value: "es", title: "Español" },
323
+ ],
324
+ dynamicTitle: true,
325
+ },
326
+ },
327
+ },
328
+ };
329
+
330
+ export default preview;
331
+ ```
332
+
333
+ </Tab>
334
+ </Tabs>
335
+
336
+ ---
337
+
338
+ ## Khai báo nội dung
339
+
340
+ Tạo tệp `*.content.ts` bên cạnh mỗi thành phần. Intlayer sẽ tự động nhận diện nó trong quá trình biên dịch.
341
+
342
+ ```typescript fileName="src/components/CopyButton/CopyButton.content.ts" codeFormat="typescript"
343
+ import { type Dictionary, t } from "intlayer";
344
+
345
+ const copyButtonContent = {
346
+ key: "copy-button",
347
+ content: {
348
+ label: t({
349
+ en: "Copy content",
350
+ fr: "Copier le contenu",
351
+ es: "Copiar contenido",
352
+ }),
353
+ },
354
+ } satisfies Dictionary;
355
+
356
+ export default copyButtonContent;
357
+ ```
358
+
359
+ ```javascript fileName="src/components/CopyButton/CopyButton.content.mjs" codeFormat="esm"
360
+ import { t } from "intlayer";
361
+
362
+ /** @type {import('intlayer').Dictionary} */
363
+ const copyButtonContent = {
364
+ key: "copy-button",
365
+ content: {
366
+ label: t({
367
+ en: "Copy content",
368
+ fr: "Copier le contenu",
369
+ es: "Copiar contenido",
370
+ }),
371
+ },
372
+ };
373
+
374
+ export default copyButtonContent;
375
+ ```
376
+
377
+ ```javascript fileName="src/components/CopyButton/CopyButton.content.cjs" codeFormat="commonjs"
378
+ const { t } = require("intlayer");
379
+
380
+ /** @type {import('intlayer').Dictionary} */
381
+ const copyButtonContent = {
382
+ key: "copy-button",
383
+ content: {
384
+ label: t({
385
+ en: "Copy content",
386
+ fr: "Copier le contenu",
387
+ es: "Copiar contenido",
388
+ }),
389
+ },
390
+ };
391
+
392
+ module.exports = copyButtonContent;
393
+ ```
394
+
395
+ > Để biết thêm các định dạng khai báo nội dung và tính năng khác, hãy xem [tài liệu khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/content_file.md).
396
+
397
+ ---
398
+
399
+ ## Sử dụng `useIntlayer` trong một thành phần
400
+
401
+ ```tsx fileName="src/components/CopyButton/index.tsx" codeFormat="typescript"
402
+ "use client";
403
+
404
+ import { type FC } from "react";
405
+ import { useIntlayer } from "react-intlayer";
406
+
407
+ type CopyButtonProps = {
408
+ content: string;
409
+ };
410
+
411
+ export const CopyButton: FC<CopyButtonProps> = ({ content }) => {
412
+ const { label } = useIntlayer("copy-button");
413
+
414
+ return (
415
+ <button
416
+ onClick={() => navigator.clipboard.writeText(content)}
417
+ aria-label={label.value}
418
+ title={label.value}
419
+ >
420
+ Sao chép
421
+ </button>
422
+ );
423
+ };
424
+ ```
425
+
426
+ `useIntlayer` trả về từ điển đã biên dịch cho ngôn ngữ hiện tại được cung cấp bởi `IntlayerProvider` gần nhất. Việc chuyển đổi ngôn ngữ trên thanh công cụ Storybook sẽ tự động hiển thị lại câu chuyện với các bản dịch đã cập nhật.
427
+
428
+ ---
429
+
430
+ ## Viết các câu chuyện (Story) cho các thành phần đa ngôn ngữ
431
+
432
+ Với decorator `IntlayerProvider` đã được thiết lập, các câu chuyện của bạn sẽ hoạt động chính xác như trước đây. Thanh công cụ ngôn ngữ kiểm soát ngôn ngữ đang hoạt động cho toàn bộ canvas:
433
+
434
+ ```tsx fileName="src/components/CopyButton/CopyButton.stories.tsx" codeFormat="typescript"
435
+ import type { Meta, StoryObj } from "@storybook/react";
436
+ import { CopyButton } from ".";
437
+
438
+ const meta: Meta<typeof CopyButton> = {
439
+ title: "Components/CopyButton",
440
+ component: CopyButton,
441
+ tags: ["autodocs"],
442
+ argTypes: {
443
+ content: { control: "text" },
444
+ },
445
+ };
446
+
447
+ export default meta;
448
+ type Story = StoryObj<typeof CopyButton>;
449
+
450
+ /** Câu chuyện mặc định — chuyển đổi ngôn ngữ trên thanh công cụ để xem trước các bản dịch. */
451
+ export const Default: Story = {
452
+ args: {
453
+ content: "npm install intlayer react-intlayer",
454
+ },
455
+ };
456
+
457
+ /** Hiển thị nút bên trong một khối mã, một trường hợp sử dụng thực tế phổ biến. */
458
+ export const InsideCodeBlock: Story = {
459
+ render: (args) => (
460
+ <div style={{ position: "relative", display: "inline-block" }}>
461
+ <pre style={{ background: "#1e1e1e", color: "#fff", padding: "1rem" }}>
462
+ <code>{args.content}</code>
463
+ </pre>
464
+ <CopyButton
465
+ content={args.content}
466
+ style={{ position: "absolute", top: 8, right: 8 }}
467
+ />
468
+ </div>
469
+ ),
470
+ args: {
471
+ content: "npx intlayer init",
472
+ },
473
+ };
474
+ ```
475
+
476
+ > Mỗi câu chuyện kế thừa biến toàn cục `locale` từ thanh công cụ, vì vậy bạn có thể xác minh mọi ngôn ngữ mà không cần thay đổi bất kỳ mã nguồn câu chuyện nào.
477
+
478
+ ---
479
+
480
+ ## Kiểm thử các bản dịch trong các câu chuyện
481
+
482
+ Sử dụng các hàm `play` của Storybook để khẳng định rằng văn bản được dịch chính xác được hiển thị cho một ngôn ngữ nhất định:
483
+
484
+ ```tsx fileName="src/components/CopyButton/CopyButton.stories.tsx" codeFormat="typescript"
485
+ import type { Meta, StoryObj } from "@storybook/react";
486
+ import { expect, within } from "@storybook/test";
487
+ import { CopyButton } from ".";
488
+
489
+ const meta: Meta<typeof CopyButton> = {
490
+ title: "Components/CopyButton",
491
+ component: CopyButton,
492
+ tags: ["autodocs"],
493
+ };
494
+
495
+ export default meta;
496
+ type Story = StoryObj<typeof CopyButton>;
497
+
498
+ export const AccessibleLabel: Story = {
499
+ args: { content: "Hello World" },
500
+ play: async ({ canvasElement }) => {
501
+ const canvas = within(canvasElement);
502
+ const button = canvas.getByRole("button");
503
+
504
+ // Xác minh nút có tên dễ tiếp cận không trống
505
+ await expect(button).toHaveAccessibleName();
506
+ // Xác minh nút không bị vô hiệu hóa
507
+ await expect(button).not.toBeDisabled();
508
+ // Xác minh khả năng tiếp cận bằng bàn phím
509
+ await expect(button).toHaveAttribute("tabindex", "0");
510
+ },
511
+ };
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Tài nguyên bổ sung
517
+
518
+ - [Tài liệu cấu hình Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/configuration.md)
519
+ - [Tài liệu khai báo nội dung](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/dictionary/content_file.md)
520
+ - [Tài liệu Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/vi/cli/index.md)
521
+ - [Tài liệu Storybook](https://storybook.js.org/docs)