@intlayer/docs 8.4.5 → 8.4.7
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/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -3
- 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/intlayer_with_storybook.md +521 -0
- package/docs/bn/intlayer_with_hono.md +428 -0
- package/docs/de/intlayer_with_storybook.md +521 -0
- package/docs/en/configuration.md +160 -508
- package/docs/en/intlayer_with_storybook.md +521 -0
- package/docs/en-GB/intlayer_with_storybook.md +521 -0
- package/docs/es/configuration.md +387 -754
- package/docs/es/intlayer_with_storybook.md +521 -0
- package/docs/fr/configuration.md +384 -757
- package/docs/fr/intlayer_with_storybook.md +521 -0
- package/docs/hi/intlayer_with_storybook.md +521 -0
- package/docs/id/intlayer_with_storybook.md +521 -0
- package/docs/it/intlayer_with_storybook.md +521 -0
- package/docs/ja/intlayer_with_storybook.md +521 -0
- package/docs/ko/intlayer_with_storybook.md +521 -0
- package/docs/pl/intlayer_with_storybook.md +521 -0
- package/docs/pt/intlayer_with_storybook.md +521 -0
- package/docs/ru/intlayer_with_storybook.md +521 -0
- package/docs/tr/intlayer_with_storybook.md +521 -0
- package/docs/uk/intlayer_with_storybook.md +521 -0
- package/docs/ur/intlayer_with_hono.md +428 -0
- package/docs/vi/intlayer_with_storybook.md +521 -0
- package/docs/zh/intlayer_with_storybook.md +521 -0
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +20 -0
- package/docs/ar/configuration.md +0 -1124
- package/docs/de/configuration.md +0 -1296
- package/docs/en-GB/configuration.md +0 -1123
- package/docs/hi/configuration.md +0 -1118
- package/docs/id/configuration.md +0 -1235
- package/docs/it/configuration.md +0 -1301
- package/docs/ja/configuration.md +0 -1121
- package/docs/ko/configuration.md +0 -1121
- package/docs/pl/configuration.md +0 -1226
- package/docs/pt/configuration.md +0 -1293
- package/docs/ru/configuration.md +0 -1112
- package/docs/tr/configuration.md +0 -1114
- package/docs/uk/configuration.md +0 -1241
- package/docs/vi/configuration.md +0 -1263
- package/docs/zh/configuration.md +0 -1115
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-03-20
|
|
3
|
+
updatedAt: 2026-03-20
|
|
4
|
+
title: Cara Menyiapkan Intlayer dengan Storybook
|
|
5
|
+
description: Pelajari cara membuat sistem desain Anda multibahasa menggunakan Intlayer dengan Storybook — kompilasi deklarasi konten, tambahkan pengalih lokal, dan pratinjau komponen Anda dalam bahasa apa pun.
|
|
6
|
+
keywords:
|
|
7
|
+
- Internasionalisasi
|
|
8
|
+
- Dokumentasi
|
|
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 dengan Storybook
|
|
26
|
+
|
|
27
|
+
## Daftar Isi
|
|
28
|
+
|
|
29
|
+
<TOC/>
|
|
30
|
+
|
|
31
|
+
## Apa itu Intlayer?
|
|
32
|
+
|
|
33
|
+
**Intlayer** adalah perpustakaan internasionalisasi (i18n) sumber terbuka yang inovatif yang dirancang untuk menyederhanakan dukungan multibahasa dalam aplikasi web modern. Ini bekerja pada **tingkat komponen** — setiap komponen memiliki deklarasi kontennya sendiri — menjaga terjemahan tetap berada di tempat yang sama dengan kode yang menggunakannya.
|
|
34
|
+
|
|
35
|
+
Dengan Intlayer Anda dapat:
|
|
36
|
+
|
|
37
|
+
- **Mengelola terjemahan secara deklaratif** dengan file konten per komponen.
|
|
38
|
+
- **Mendapatkan dukungan TypeScript penuh** melalui tipe yang dibuat secara otomatis dan autolengkap IDE.
|
|
39
|
+
- **Beralih lokal saat runtime** tanpa perlu memuat ulang halaman.
|
|
40
|
+
- **Menerjemahkan secara otomatis** dengan integrasi penyedia AI bawaan.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Mengapa menggunakan Intlayer dengan Storybook?
|
|
45
|
+
|
|
46
|
+
Storybook adalah alat standar industri untuk mengembangkan dan mendokumentasikan komponen UI secara terisolasi. Menggabungkannya dengan Intlayer memungkinkan Anda untuk:
|
|
47
|
+
|
|
48
|
+
- **Pratinjau setiap lokal** langsung di dalam kanvas Storybook menggunakan pengalih bilah alat.
|
|
49
|
+
- **Menemukan terjemahan yang hilang** sebelum mencapai tahap produksi.
|
|
50
|
+
- **Mendokumentasikan komponen multibahasa** dengan konten asli yang aman secara tipe, bukan string yang dikodekan secara statis.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Pengaturan Langkah demi Langkah
|
|
55
|
+
|
|
56
|
+
<Tabs>
|
|
57
|
+
<Tab value="Vite Setup">
|
|
58
|
+
|
|
59
|
+
### Langkah 1: Instal Dependensi
|
|
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
|
+
| Paket | Peran |
|
|
82
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
83
|
+
| `intlayer` | Inti — konfigurasi, kompilasi konten, CLI |
|
|
84
|
+
| `react-intlayer` | Pengikatan React — `IntlayerProvider`, hook `useIntlayer` |
|
|
85
|
+
| `vite-intlayer` | Plugin Vite — memantau dan mengompilasi file deklarasi konten |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### Langkah 2: Buat Konfigurasi Intlayer
|
|
90
|
+
|
|
91
|
+
Buat `intlayer.config.ts` di root proyek Anda (atau di dalam paket sistem desain Anda):
|
|
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
|
+
// tambahkan lebih banyak lokal jika diperlukan
|
|
103
|
+
],
|
|
104
|
+
defaultLocale: Locales.ENGLISH,
|
|
105
|
+
},
|
|
106
|
+
content: {
|
|
107
|
+
contentDir: ["./src"], // lokasi file *.content.ts Anda
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export default config;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
> Untuk daftar lengkap opsi, lihat [referensi konfigurasi](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/configuration.md).
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### Langkah 3: Tambahkan Plugin Vite ke Storybook
|
|
119
|
+
|
|
120
|
+
Hook `viteFinal` Storybook memungkinkan Anda memperluas konfigurasi Vite internal. Impor dan tambahkan plugin `intlayer()` di sana:
|
|
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
|
+
// …addons lainnya
|
|
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()` memantau file `*.content.ts` Anda dan membangun kembali kamus secara otomatis setiap kali ada perubahan selama pengembangan Storybook.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### Langkah 4: Tambahkan Dekorator `IntlayerProvider` dan Bilah Alat Lokal
|
|
160
|
+
|
|
161
|
+
File `preview` Storybook adalah tempat yang tepat untuk membungkus setiap story dengan `IntlayerProvider` dan mengekspos pengalih lokal di bilah alat:
|
|
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
|
+
// Bungkus setiap story di dalam 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
|
+
// Ekspos pengalih lokal di bilah alat Storybook
|
|
181
|
+
globalTypes: {
|
|
182
|
+
locale: {
|
|
183
|
+
description: "Lokal yang aktif",
|
|
184
|
+
defaultValue: "en",
|
|
185
|
+
toolbar: {
|
|
186
|
+
title: "Lokal",
|
|
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
|
+
> Nilai `locale` harus sesuai dengan lokal yang dideklarasikan dalam `intlayer.config.ts` Anda.
|
|
212
|
+
|
|
213
|
+
</Tab>
|
|
214
|
+
<Tab value="Webpack Setup">
|
|
215
|
+
|
|
216
|
+
### Langkah 1: Instal Dependensi
|
|
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
|
+
### Langkah 2: Buat Konfigurasi Intlayer
|
|
241
|
+
|
|
242
|
+
Buat `intlayer.config.ts` di root proyek Anda:
|
|
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
|
+
### Langkah 3: Konfigurasi Webpack Storybook
|
|
263
|
+
|
|
264
|
+
Untuk pengaturan Storybook berbasis Webpack (misalnya `@storybook/react-webpack5`), perluas konfigurasi webpack melalui `webpackFinal` untuk menambahkan alias dan loader 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
|
+
### Langkah 4: Tambahkan Dekorator `IntlayerProvider` dan Bilah Alat Lokal
|
|
293
|
+
|
|
294
|
+
Sama seperti pengaturan Vite — tambahkan dekorator dan tipe lokal global di `.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: "Lokal yang aktif",
|
|
315
|
+
defaultValue: "en",
|
|
316
|
+
toolbar: {
|
|
317
|
+
title: "Lokal",
|
|
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
|
+
## Mendeklarasikan Konten
|
|
339
|
+
|
|
340
|
+
Buat file `*.content.ts` di samping setiap komponen. Intlayer akan mengambilnya secara otomatis selama proses kompilasi.
|
|
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
|
+
> Untuk format dan fitur deklarasi konten lainnya, lihat [dokumentasi deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/content_file.md).
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Menggunakan `useIntlayer` dalam Komponen
|
|
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
|
+
Salin
|
|
421
|
+
</button>
|
|
422
|
+
);
|
|
423
|
+
};
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`useIntlayer` mengembalikan kamus yang telah dikompilasi untuk lokal saat ini yang disediakan oleh `IntlayerProvider` terdekat. Mengalihkan lokal di bilah alat Storybook akan secara otomatis me-render ulang story dengan terjemahan yang diperbarui.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Menulis Story untuk Komponen yang di-Internasionalisasi
|
|
431
|
+
|
|
432
|
+
Dengan adanya dekorator `IntlayerProvider`, story Anda akan bekerja sama persis seperti sebelumnya. Bilah alat lokal mengontrol lokal aktif untuk seluruh kanvas:
|
|
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
|
+
/** Story default — ubah lokal di bilah alat untuk melihat pratinjau terjemahan. */
|
|
451
|
+
export const Default: Story = {
|
|
452
|
+
args: {
|
|
453
|
+
content: "npm install intlayer react-intlayer",
|
|
454
|
+
},
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/** Me-render tombol di dalam blok kode, kasus penggunaan dunia nyata yang umum. */
|
|
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
|
+
> Setiap story mewarisi global `locale` dari bilah alat, jadi Anda dapat memverifikasi setiap lokal tanpa mengubah kode story apa pun.
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Menguji Terjemahan dalam Story
|
|
481
|
+
|
|
482
|
+
Gunakan fungsi `play` Storybook untuk menegaskan bahwa teks terjemahan yang benar telah dirender untuk lokal tertentu:
|
|
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
|
+
// Verifikasi tombol memiliki nama aksesibel yang tidak kosong
|
|
505
|
+
await expect(button).toHaveAccessibleName();
|
|
506
|
+
// Verifikasi tombol tidak dinonaktifkan
|
|
507
|
+
await expect(button).not.toBeDisabled();
|
|
508
|
+
// Verifikasi aksesibilitas keyboard
|
|
509
|
+
await expect(button).toHaveAttribute("tabindex", "0");
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Sumber Daya Tambahan
|
|
517
|
+
|
|
518
|
+
- [Referensi konfigurasi Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/configuration.md)
|
|
519
|
+
- [Dokumentasi deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/content_file.md)
|
|
520
|
+
- [Dokumentasi CLI Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/cli/index.md)
|
|
521
|
+
- [Dokumentasi Storybook](https://storybook.js.org/docs)
|