@intlayer/docs 8.0.0 → 8.0.1-canary.0
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 +160 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +160 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +8 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/intlayer_with_adonisjs.md +394 -0
- package/docs/ar/intlayer_with_hono.md +223 -0
- package/docs/ar/intlayer_with_vite+preact.md +317 -675
- package/docs/ar/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ar/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ar/packages/adonis-intlayer/t.md +149 -0
- package/docs/ar/packages/hono-intlayer/exports.md +59 -0
- package/docs/ar/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ar/packages/hono-intlayer/t.md +268 -0
- package/docs/de/intlayer_with_adonisjs.md +392 -0
- package/docs/de/intlayer_with_hono.md +418 -0
- package/docs/de/intlayer_with_vite+preact.md +272 -632
- package/docs/de/packages/adonis-intlayer/exports.md +50 -0
- package/docs/de/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/de/packages/adonis-intlayer/t.md +149 -0
- package/docs/de/packages/hono-intlayer/exports.md +59 -0
- package/docs/de/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/de/packages/hono-intlayer/t.md +316 -0
- package/docs/en/index.md +8 -0
- package/docs/en/intlayer_with_adonisjs.md +388 -0
- package/docs/en/intlayer_with_hono.md +418 -0
- package/docs/en/intlayer_with_vite+preact.md +171 -556
- package/docs/en/introduction.md +1 -0
- package/docs/en/packages/adonis-intlayer/exports.md +50 -0
- package/docs/en/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/en/packages/adonis-intlayer/t.md +149 -0
- package/docs/en/packages/hono-intlayer/exports.md +59 -0
- package/docs/en/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/en/packages/hono-intlayer/t.md +316 -0
- package/docs/en-GB/intlayer_with_adonisjs.md +394 -0
- package/docs/en-GB/intlayer_with_hono.md +418 -0
- package/docs/en-GB/intlayer_with_vite+preact.md +236 -583
- package/docs/en-GB/packages/adonis-intlayer/exports.md +50 -0
- package/docs/en-GB/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/en-GB/packages/adonis-intlayer/t.md +149 -0
- package/docs/en-GB/packages/hono-intlayer/exports.md +59 -0
- package/docs/en-GB/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/en-GB/packages/hono-intlayer/t.md +316 -0
- package/docs/es/intlayer_with_adonisjs.md +388 -0
- package/docs/es/intlayer_with_hono.md +418 -0
- package/docs/es/intlayer_with_vite+preact.md +286 -650
- package/docs/es/packages/adonis-intlayer/exports.md +50 -0
- package/docs/es/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/es/packages/adonis-intlayer/t.md +149 -0
- package/docs/es/packages/hono-intlayer/exports.md +59 -0
- package/docs/es/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/es/packages/hono-intlayer/t.md +316 -0
- package/docs/fr/intlayer_with_adonisjs.md +388 -0
- package/docs/fr/intlayer_with_hono.md +418 -0
- package/docs/fr/intlayer_with_vite+preact.md +274 -614
- package/docs/fr/packages/adonis-intlayer/exports.md +50 -0
- package/docs/fr/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/fr/packages/adonis-intlayer/t.md +149 -0
- package/docs/fr/packages/hono-intlayer/exports.md +59 -0
- package/docs/fr/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/fr/packages/hono-intlayer/t.md +316 -0
- package/docs/hi/intlayer_with_adonisjs.md +394 -0
- package/docs/hi/intlayer_with_hono.md +227 -0
- package/docs/hi/intlayer_with_vite+preact.md +304 -680
- package/docs/hi/packages/adonis-intlayer/exports.md +50 -0
- package/docs/hi/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/hi/packages/adonis-intlayer/t.md +149 -0
- package/docs/hi/packages/hono-intlayer/exports.md +59 -0
- package/docs/hi/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/hi/packages/hono-intlayer/t.md +268 -0
- package/docs/id/intlayer_with_adonisjs.md +394 -0
- package/docs/id/intlayer_with_hono.md +227 -0
- package/docs/id/intlayer_with_vite+preact.md +297 -697
- package/docs/id/packages/adonis-intlayer/exports.md +50 -0
- package/docs/id/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/id/packages/adonis-intlayer/t.md +149 -0
- package/docs/id/packages/hono-intlayer/exports.md +59 -0
- package/docs/id/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/id/packages/hono-intlayer/t.md +268 -0
- package/docs/it/intlayer_with_adonisjs.md +394 -0
- package/docs/it/intlayer_with_hono.md +227 -0
- package/docs/it/intlayer_with_vite+preact.md +290 -659
- package/docs/it/packages/adonis-intlayer/exports.md +50 -0
- package/docs/it/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/it/packages/adonis-intlayer/t.md +149 -0
- package/docs/it/packages/hono-intlayer/exports.md +59 -0
- package/docs/it/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/it/packages/hono-intlayer/t.md +268 -0
- package/docs/ja/intlayer_with_adonisjs.md +394 -0
- package/docs/ja/intlayer_with_hono.md +227 -0
- package/docs/ja/intlayer_with_vite+preact.md +307 -662
- package/docs/ja/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ja/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ja/packages/adonis-intlayer/t.md +149 -0
- package/docs/ja/packages/hono-intlayer/exports.md +59 -0
- package/docs/ja/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ja/packages/hono-intlayer/t.md +268 -0
- package/docs/ko/intlayer_with_adonisjs.md +394 -0
- package/docs/ko/intlayer_with_hono.md +227 -0
- package/docs/ko/intlayer_with_vite+preact.md +303 -703
- package/docs/ko/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ko/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ko/packages/adonis-intlayer/t.md +149 -0
- package/docs/ko/packages/hono-intlayer/exports.md +59 -0
- package/docs/ko/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ko/packages/hono-intlayer/t.md +268 -0
- package/docs/pl/intlayer_with_adonisjs.md +394 -0
- package/docs/pl/intlayer_with_hono.md +227 -0
- package/docs/pl/intlayer_with_vite+preact.md +289 -690
- package/docs/pl/packages/adonis-intlayer/exports.md +50 -0
- package/docs/pl/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/pl/packages/adonis-intlayer/t.md +149 -0
- package/docs/pl/packages/hono-intlayer/exports.md +59 -0
- package/docs/pl/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/pl/packages/hono-intlayer/t.md +268 -0
- package/docs/pt/intlayer_with_adonisjs.md +394 -0
- package/docs/pt/intlayer_with_hono.md +227 -0
- package/docs/pt/intlayer_with_vite+preact.md +275 -637
- package/docs/pt/packages/adonis-intlayer/exports.md +50 -0
- package/docs/pt/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/pt/packages/adonis-intlayer/t.md +149 -0
- package/docs/pt/packages/hono-intlayer/exports.md +59 -0
- package/docs/pt/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/pt/packages/hono-intlayer/t.md +268 -0
- package/docs/ru/intlayer_with_adonisjs.md +393 -0
- package/docs/ru/intlayer_with_hono.md +223 -0
- package/docs/ru/intlayer_with_vite+preact.md +319 -683
- package/docs/ru/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ru/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ru/packages/adonis-intlayer/t.md +149 -0
- package/docs/ru/packages/hono-intlayer/exports.md +59 -0
- package/docs/ru/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ru/packages/hono-intlayer/t.md +268 -0
- package/docs/tr/intlayer_with_adonisjs.md +394 -0
- package/docs/tr/intlayer_with_hono.md +227 -0
- package/docs/tr/intlayer_with_vite+preact.md +332 -665
- package/docs/tr/packages/adonis-intlayer/exports.md +50 -0
- package/docs/tr/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/tr/packages/adonis-intlayer/t.md +149 -0
- package/docs/tr/packages/hono-intlayer/exports.md +59 -0
- package/docs/tr/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/tr/packages/hono-intlayer/t.md +268 -0
- package/docs/uk/intlayer_with_adonisjs.md +394 -0
- package/docs/uk/intlayer_with_hono.md +227 -0
- package/docs/uk/intlayer_with_vite+preact.md +228 -626
- package/docs/uk/packages/adonis-intlayer/exports.md +50 -0
- package/docs/uk/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/uk/packages/adonis-intlayer/t.md +149 -0
- package/docs/uk/packages/hono-intlayer/exports.md +59 -0
- package/docs/uk/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/uk/packages/hono-intlayer/t.md +268 -0
- package/docs/vi/intlayer_with_adonisjs.md +394 -0
- package/docs/vi/intlayer_with_hono.md +227 -0
- package/docs/vi/intlayer_with_vite+preact.md +294 -679
- package/docs/vi/packages/adonis-intlayer/exports.md +50 -0
- package/docs/vi/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/vi/packages/adonis-intlayer/t.md +149 -0
- package/docs/vi/packages/hono-intlayer/exports.md +59 -0
- package/docs/vi/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/vi/packages/hono-intlayer/t.md +268 -0
- package/docs/zh/intlayer_with_adonisjs.md +393 -0
- package/docs/zh/intlayer_with_hono.md +418 -0
- package/docs/zh/intlayer_with_vite+preact.md +338 -743
- package/docs/zh/packages/adonis-intlayer/exports.md +50 -0
- package/docs/zh/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/zh/packages/adonis-intlayer/t.md +149 -0
- package/docs/zh/packages/hono-intlayer/exports.md +59 -0
- package/docs/zh/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/zh/packages/hono-intlayer/t.md +294 -0
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +160 -0
|
@@ -48,8 +48,6 @@ history:
|
|
|
48
48
|
</Tab>
|
|
49
49
|
</Tabs>
|
|
50
50
|
|
|
51
|
-
> Paket ini sedang dalam pengembangan. Lihat [issue](https://github.com/aymericzip/intlayer/issues/118) untuk informasi lebih lanjut. Tunjukkan minat Anda pada Intlayer untuk Preact dengan menyukai issue tersebut
|
|
52
|
-
|
|
53
51
|
## Daftar Isi
|
|
54
52
|
|
|
55
53
|
<TOC/>
|
|
@@ -61,22 +59,14 @@ history:
|
|
|
61
59
|
Dengan Intlayer, Anda dapat:
|
|
62
60
|
|
|
63
61
|
- **Mengelola terjemahan dengan mudah** menggunakan kamus deklaratif di tingkat komponen.
|
|
64
|
-
- **Melokalkan metadata
|
|
65
|
-
- **Menjamin dukungan TypeScript** dengan tipe yang dihasilkan secara otomatis, meningkatkan autocompletion
|
|
62
|
+
- **Melokalkan metadata, rute, dan konten secara dinamis**.
|
|
63
|
+
- **Menjamin dukungan TypeScript** dengan tipe yang dihasilkan secara otomatis, meningkatkan autocompletion và deteksi kesalahan.
|
|
66
64
|
- **Memanfaatkan fitur canggih**, seperti deteksi dan pergantian locale secara dinamis.
|
|
67
65
|
|
|
68
66
|
---
|
|
69
67
|
|
|
70
68
|
## Panduan Langkah demi Langkah untuk Mengatur Intlayer dalam Aplikasi Vite dan Preact
|
|
71
69
|
|
|
72
|
-
<iframe
|
|
73
|
-
src="https://stackblitz.com/github/aymericzip/intlayer-vite-preact-template?embed=1&ctl=1&file=intlayer.config.ts"
|
|
74
|
-
className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
|
|
75
|
-
title="Demo CodeSandbox - Cara Menginternasionalisasi aplikasi Anda menggunakan Intlayer"
|
|
76
|
-
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
|
77
|
-
loading="lazy"
|
|
78
|
-
/>
|
|
79
|
-
|
|
80
70
|
Lihat [Template Aplikasi](https://github.com/aymericzip/intlayer-vite-preact-template) di GitHub.
|
|
81
71
|
|
|
82
72
|
### Langkah 1: Instalasi Dependensi
|
|
@@ -109,12 +99,14 @@ bunx intlayer init
|
|
|
109
99
|
|
|
110
100
|
- **intlayer**
|
|
111
101
|
|
|
112
|
-
Paket inti yang menyediakan alat internasionalisasi untuk manajemen konfigurasi, terjemahan, [deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/content_file.md),
|
|
102
|
+
Paket inti yang menyediakan alat internasionalisasi untuk manajemen konfigurasi, terjemahan, [deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/content_file.md), kompilasi, và [perintah CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/cli/index.md).
|
|
113
103
|
|
|
114
104
|
- **preact-intlayer**
|
|
105
|
+
|
|
115
106
|
Paket yang mengintegrasikan Intlayer dengan aplikasi Preact. Ini menyediakan context providers dan hooks untuk internasionalisasi Preact.
|
|
116
107
|
|
|
117
108
|
- **vite-intlayer**
|
|
109
|
+
|
|
118
110
|
Termasuk plugin Vite untuk mengintegrasikan Intlayer dengan [Vite bundler](https://vite.dev/guide/why.html#why-bundle-for-production), serta middleware untuk mendeteksi locale yang dipilih pengguna, mengelola cookie, dan menangani pengalihan URL.
|
|
119
111
|
|
|
120
112
|
### Langkah 2: Konfigurasi proyek Anda
|
|
@@ -159,7 +151,7 @@ const config = {
|
|
|
159
151
|
},
|
|
160
152
|
routing: {
|
|
161
153
|
mode: "prefix-no-default", // Default: prefix semua locale kecuali locale default
|
|
162
|
-
storage: ["cookie", "header"], // Default: simpan locale di cookie
|
|
154
|
+
storage: ["cookie", "header"], // Default: simpan locale di cookie và deteksi dari header
|
|
163
155
|
},
|
|
164
156
|
};
|
|
165
157
|
|
|
@@ -182,7 +174,7 @@ const config = {
|
|
|
182
174
|
},
|
|
183
175
|
routing: {
|
|
184
176
|
mode: "prefix-no-default", // Default: prefix semua locale kecuali locale default
|
|
185
|
-
storage: ["cookie", "header"], // Default: simpan locale di cookie
|
|
177
|
+
storage: ["cookie", "header"], // Default: simpan locale di cookie và deteksi dari header
|
|
186
178
|
},
|
|
187
179
|
};
|
|
188
180
|
|
|
@@ -193,7 +185,7 @@ module.exports = config;
|
|
|
193
185
|
|
|
194
186
|
### Langkah 3: Integrasikan Intlayer dalam Konfigurasi Vite Anda
|
|
195
187
|
|
|
196
|
-
Tambahkan plugin intlayer ke
|
|
188
|
+
Tambahkan plugin intlayer ke trong konfigurasi Anda.
|
|
197
189
|
|
|
198
190
|
```typescript fileName="vite.config.ts" codeFormat="typescript"
|
|
199
191
|
import { defineConfig } from "vite";
|
|
@@ -263,7 +255,7 @@ const appContent = {
|
|
|
263
255
|
edit: t<ComponentChildren>({
|
|
264
256
|
en: (
|
|
265
257
|
<>
|
|
266
|
-
Edit <code>src/app.tsx</code>
|
|
258
|
+
Edit <code>src/app.tsx</code> and save to test HMR
|
|
267
259
|
</>
|
|
268
260
|
),
|
|
269
261
|
fr: (
|
|
@@ -279,7 +271,7 @@ const appContent = {
|
|
|
279
271
|
}),
|
|
280
272
|
|
|
281
273
|
readTheDocs: t({
|
|
282
|
-
en: "
|
|
274
|
+
en: "Click on the Vite and Preact logos to learn more",
|
|
283
275
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
284
276
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
285
277
|
}),
|
|
@@ -323,7 +315,7 @@ const appContent = {
|
|
|
323
315
|
}),
|
|
324
316
|
|
|
325
317
|
readTheDocs: t({
|
|
326
|
-
en: "
|
|
318
|
+
en: "Click on the Vite and Preact logos to learn more",
|
|
327
319
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
328
320
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
329
321
|
}),
|
|
@@ -347,6 +339,7 @@ const appContent = {
|
|
|
347
339
|
es: "Logo Vite",
|
|
348
340
|
}),
|
|
349
341
|
preactLogo: t({
|
|
342
|
+
en: "Preact logo",
|
|
350
343
|
fr: "Logo Preact",
|
|
351
344
|
es: "Logo Preact",
|
|
352
345
|
}),
|
|
@@ -357,21 +350,18 @@ const appContent = {
|
|
|
357
350
|
en: "count is ",
|
|
358
351
|
fr: "le compte est ",
|
|
359
352
|
es: "el recuento es ",
|
|
360
|
-
id: "jumlah adalah ",
|
|
361
353
|
}),
|
|
362
354
|
|
|
363
355
|
edit: t({
|
|
364
356
|
en: "Edit src/app.tsx and save to test HMR",
|
|
365
357
|
fr: "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
366
358
|
es: "Edita src/app.tsx y guarda para probar HMR",
|
|
367
|
-
id: "Edit src/app.tsx dan simpan untuk menguji HMR",
|
|
368
359
|
}),
|
|
369
360
|
|
|
370
361
|
readTheDocs: t({
|
|
371
362
|
en: "Click on the Vite and Preact logos to learn more",
|
|
372
363
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
373
364
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
374
|
-
id: "Klik pada logo Vite dan Preact untuk mempelajari lebih lanjut",
|
|
375
365
|
}),
|
|
376
366
|
},
|
|
377
367
|
};
|
|
@@ -389,8 +379,7 @@ module.exports = appContent;
|
|
|
389
379
|
"translation": {
|
|
390
380
|
"en": "Vite logo",
|
|
391
381
|
"fr": "Logo Vite",
|
|
392
|
-
"es": "Logo Vite"
|
|
393
|
-
"id": "Logo Vite"
|
|
382
|
+
"es": "Logo Vite"
|
|
394
383
|
}
|
|
395
384
|
},
|
|
396
385
|
"preactLogo": {
|
|
@@ -398,8 +387,7 @@ module.exports = appContent;
|
|
|
398
387
|
"translation": {
|
|
399
388
|
"en": "Preact logo",
|
|
400
389
|
"fr": "Logo Preact",
|
|
401
|
-
"es": "Logo Preact"
|
|
402
|
-
"id": "Logo Preact"
|
|
390
|
+
"es": "Logo Preact"
|
|
403
391
|
}
|
|
404
392
|
},
|
|
405
393
|
"title": {
|
|
@@ -407,8 +395,7 @@ module.exports = appContent;
|
|
|
407
395
|
"translation": {
|
|
408
396
|
"en": "Vite + Preact",
|
|
409
397
|
"fr": "Vite + Preact",
|
|
410
|
-
"es": "Vite + Preact"
|
|
411
|
-
"id": "Vite + Preact"
|
|
398
|
+
"es": "Vite + Preact"
|
|
412
399
|
}
|
|
413
400
|
},
|
|
414
401
|
"count": {
|
|
@@ -416,8 +403,7 @@ module.exports = appContent;
|
|
|
416
403
|
"translation": {
|
|
417
404
|
"en": "count is ",
|
|
418
405
|
"fr": "le compte est ",
|
|
419
|
-
"es": "el recuento es "
|
|
420
|
-
"id": "jumlah adalah "
|
|
406
|
+
"es": "el recuento es "
|
|
421
407
|
}
|
|
422
408
|
},
|
|
423
409
|
"edit": {
|
|
@@ -425,8 +411,7 @@ module.exports = appContent;
|
|
|
425
411
|
"translation": {
|
|
426
412
|
"en": "Edit src/app.tsx and save to test HMR",
|
|
427
413
|
"fr": "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
428
|
-
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
429
|
-
"id": "Edit src/app.tsx dan simpan untuk menguji HMR"
|
|
414
|
+
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
430
415
|
}
|
|
431
416
|
},
|
|
432
417
|
"readTheDocs": {
|
|
@@ -434,19 +419,18 @@ module.exports = appContent;
|
|
|
434
419
|
"translation": {
|
|
435
420
|
"en": "Click on the Vite and Preact logos to learn more",
|
|
436
421
|
"fr": "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
437
|
-
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
438
|
-
"id": "Klik pada logo Vite dan Preact untuk mempelajari lebih lanjut"
|
|
422
|
+
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
439
423
|
}
|
|
440
424
|
}
|
|
441
425
|
}
|
|
442
426
|
}
|
|
443
427
|
```
|
|
444
428
|
|
|
445
|
-
> Deklarasi konten Anda dapat didefinisikan di mana saja dalam aplikasi Anda selama sudah dimasukkan ke
|
|
429
|
+
> Deklarasi konten Anda dapat didefinisikan di mana saja dalam aplikasi Anda selama sudah dimasukkan ke trong direktori `contentDir` (secara default, `./src`). Dan sesuai dengan ekstensi file deklarasi konten (secara default, `.content.{json,ts,tsx,js,jsx,mjs,cjs}`).
|
|
446
430
|
|
|
447
|
-
> Untuk detail lebih lanjut, lihat [dokumentasi deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/
|
|
431
|
+
> Untuk detail lebih lanjut, lihat [dokumentasi deklarasi konten](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/dictionary/get_started.md).
|
|
448
432
|
|
|
449
|
-
> Jika file konten Anda menyertakan kode TSX, Anda mungkin perlu mengimpor `import { h } from "preact";`
|
|
433
|
+
> Jika file konten Anda menyertakan kode TSX, Anda mungkin perlu mengimpor `import { h } from "preact";` hoặc đảm bảo pragma JSX Anda sudah diatur dengan benar untuk Preact.
|
|
450
434
|
|
|
451
435
|
### Langkah 5: Gunakan Intlayer dalam Kode Anda
|
|
452
436
|
|
|
@@ -486,6 +470,12 @@ const AppContent: FunctionalComponent = () => {
|
|
|
486
470
|
</button>
|
|
487
471
|
<p>{content.edit}</p>
|
|
488
472
|
</div>
|
|
473
|
+
{/* Konten Markdown */}
|
|
474
|
+
<div>{content.myMarkdownContent}</div>
|
|
475
|
+
|
|
476
|
+
{/* Konten HTML */}
|
|
477
|
+
<div>{content.myHtmlContent}</div>
|
|
478
|
+
|
|
489
479
|
<p class="read-the-docs">{content.readTheDocs}</p>
|
|
490
480
|
</>
|
|
491
481
|
);
|
|
@@ -606,7 +596,7 @@ module.exports = App;
|
|
|
606
596
|
|
|
607
597
|
### (Opsional) Langkah 6: Ubah bahasa konten Anda
|
|
608
598
|
|
|
609
|
-
Untuk mengubah bahasa konten Anda, Anda dapat menggunakan fungsi `setLocale` yang disediakan oleh hook `useLocale`. Fungsi ini memungkinkan Anda
|
|
599
|
+
Untuk mengubah bahasa konten Anda, Anda dapat menggunakan fungsi `setLocale` yang disediakan oleh hook `useLocale`. Fungsi ini memungkinkan Anda để thiết lập locale ứng dụng và cập nhật nội dung tương ứng.
|
|
610
600
|
|
|
611
601
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
612
602
|
import type { FunctionalComponent } from "preact";
|
|
@@ -660,12 +650,12 @@ const LocaleSwitcher = () => {
|
|
|
660
650
|
module.exports = LocaleSwitcher;
|
|
661
651
|
```
|
|
662
652
|
|
|
663
|
-
>
|
|
653
|
+
> Để tìm hiểu thêm về hook `useLocale`, hãy tham khảo [tài liệu](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/react-intlayer/useLocale.md) (API serupa cho `preact-intlayer`).
|
|
664
654
|
|
|
665
|
-
### (Opsional) Langkah 7: Tambahkan
|
|
655
|
+
### (Opsional) Langkah 7: Tambahkan Perutean yang Dilokalkan ke aplikasi Anda
|
|
666
656
|
|
|
667
|
-
Tujuan dari langkah ini adalah untuk membuat rute unik
|
|
668
|
-
|
|
657
|
+
Tujuan dari langkah ini adalah untuk membuat rute unik cho mỗi ngôn ngữ. Điều này hữu ích cho SEO và các URL thân thiện với SEO.
|
|
658
|
+
Ví dụ:
|
|
669
659
|
|
|
670
660
|
```plaintext
|
|
671
661
|
- https://example.com/about
|
|
@@ -673,413 +663,107 @@ Contoh:
|
|
|
673
663
|
- https://example.com/fr/about
|
|
674
664
|
```
|
|
675
665
|
|
|
676
|
-
> Secara default, rute tidak diberi awalan
|
|
677
|
-
|
|
678
|
-
Untuk menambahkan routing yang dilokalkan ke aplikasi Anda, Anda dapat membuat komponen `LocaleRouter` yang membungkus rute aplikasi Anda dan menangani routing berbasis locale. Berikut adalah contoh menggunakan [preact-iso](https://github.com/preactjs/preact-iso):
|
|
679
|
-
|
|
680
|
-
Pertama, instal `preact-iso`:
|
|
681
|
-
|
|
682
|
-
```bash packageManager="npm"
|
|
683
|
-
npm install preact-iso
|
|
684
|
-
npx intlayer init
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
```bash packageManager="pnpm"
|
|
688
|
-
pnpm add preact-iso
|
|
689
|
-
pnpm intlayer init
|
|
690
|
-
```
|
|
666
|
+
> Secara default, rute tidak diberi awalan cho locale mặc định. Nếu bạn muốn thêm tiền tố cho locale mặc định, bạn có thể đặt tùy chọn `routing.mode` thành `"prefix-all"` trong cấu hình của mình. Xem [tài liệu cấu hình](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/configuration.md) để biết thêm thông tin.
|
|
691
667
|
|
|
692
|
-
|
|
693
|
-
yarn add preact-iso
|
|
694
|
-
```
|
|
668
|
+
Để thêm perutean được bản địa hóa vào ứng dụng của bạn, bạn có thể tạo một thành phần `LocaleRouter` bao bọc các tuyến đường của ứng dụng và xử lý định tuyến dựa trên ngôn ngữ. Dưới đây là một ví dụ sử dụng [preact-iso](https://github.com/preactjs/preact-iso):
|
|
695
669
|
|
|
696
670
|
```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
|
|
697
|
-
import {
|
|
698
|
-
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
699
|
-
import { useEffect } from "preact/hooks";
|
|
671
|
+
import { localeMap } from "intlayer";
|
|
700
672
|
import { IntlayerProvider } from "preact-intlayer";
|
|
701
|
-
import { LocationProvider,
|
|
702
|
-
|
|
703
|
-
const { internationalization, routing } = configuration;
|
|
704
|
-
const { locales, defaultLocale } = internationalization;
|
|
705
|
-
|
|
706
|
-
const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({
|
|
707
|
-
to,
|
|
708
|
-
replace,
|
|
709
|
-
}) => {
|
|
710
|
-
const { route } = useLocation();
|
|
711
|
-
useEffect(() => {
|
|
712
|
-
route(to, replace);
|
|
713
|
-
}, [to, replace, route]);
|
|
714
|
-
return null;
|
|
715
|
-
};
|
|
716
|
-
|
|
717
|
-
/**
|
|
718
|
-
/**
|
|
719
|
-
* Sebuah komponen yang menangani lokalisasi dan membungkus children dengan konteks locale yang sesuai.
|
|
720
|
-
* Komponen ini mengelola deteksi dan validasi locale berbasis URL.
|
|
721
|
-
*/
|
|
722
|
-
const AppLocalized: FunctionalComponent<{
|
|
723
|
-
children: ComponentChildren;
|
|
724
|
-
locale?: Locale;
|
|
725
|
-
}> = ({ children, locale }) => {
|
|
726
|
-
const { path: pathname, url } = useLocation();
|
|
727
|
-
|
|
728
|
-
if (!url) {
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
const search = url.substring(pathname.length);
|
|
733
|
-
|
|
734
|
-
// Menentukan locale saat ini, menggunakan default jika tidak disediakan
|
|
735
|
-
const currentLocale = locale ?? defaultLocale;
|
|
736
|
-
|
|
737
|
-
// Menghapus prefix locale dari path untuk membangun path dasar
|
|
738
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
739
|
-
pathname // Path URL saat ini
|
|
740
|
-
);
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Jika routing.mode adalah 'prefix-all', locale default harus selalu diberi prefix.
|
|
744
|
-
*/
|
|
745
|
-
if (routing.mode === "prefix-all") {
|
|
746
|
-
// Validasi locale
|
|
747
|
-
if (!locale || !locales.includes(locale)) {
|
|
748
|
-
// Redirect ke locale default dengan path yang diperbarui
|
|
749
|
-
return (
|
|
750
|
-
<Navigate
|
|
751
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
752
|
-
replace // Ganti entri history saat ini dengan yang baru
|
|
753
|
-
/>
|
|
754
|
-
);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
758
|
-
return (
|
|
759
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
760
|
-
);
|
|
761
|
-
} else {
|
|
762
|
-
/**
|
|
763
|
-
* Ketika routing.mode bukan 'prefix-all', locale default tidak diberi prefix.
|
|
764
|
-
* Pastikan locale saat ini valid dan bukan locale default.
|
|
765
|
-
*/
|
|
766
|
-
if (
|
|
767
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
768
|
-
!locales
|
|
769
|
-
.filter(
|
|
770
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Kecualikan locale default
|
|
771
|
-
)
|
|
772
|
-
.includes(currentLocale) // Periksa apakah locale saat ini ada dalam daftar locale yang valid
|
|
773
|
-
) {
|
|
774
|
-
// Redirect ke path tanpa prefix locale
|
|
775
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
779
|
-
return (
|
|
780
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
};
|
|
784
|
-
|
|
785
|
-
const RouterContent: FunctionalComponent<{
|
|
786
|
-
children: ComponentChildren;
|
|
787
|
-
}> = ({ children }) => {
|
|
788
|
-
const { path } = useLocation();
|
|
789
|
-
|
|
790
|
-
if (!path) {
|
|
791
|
-
return null;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
const pathLocale = path.split("/")[1] as Locale;
|
|
795
|
-
|
|
796
|
-
const isLocaleRoute = locales
|
|
797
|
-
.filter(
|
|
798
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
799
|
-
)
|
|
800
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
801
|
-
|
|
802
|
-
if (isLocaleRoute) {
|
|
803
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
return (
|
|
807
|
-
<AppLocalized
|
|
808
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
809
|
-
>
|
|
810
|
-
{children}
|
|
811
|
-
</AppLocalized>
|
|
812
|
-
);
|
|
813
|
-
};
|
|
673
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
674
|
+
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
814
675
|
|
|
815
676
|
/**
|
|
816
|
-
*
|
|
817
|
-
*
|
|
677
|
+
* Một thành phần định tuyến thiết lập các tuyến đường cụ thể cho từng ngôn ngữ.
|
|
678
|
+
* Nó sử dụng preact-iso để quản lý điều hướng và hiển thị các thành phần cục bộ.
|
|
818
679
|
*/
|
|
819
680
|
export const LocaleRouter: FunctionalComponent<{
|
|
820
681
|
children: ComponentChildren;
|
|
821
682
|
}> = ({ children }) => (
|
|
822
683
|
<LocationProvider>
|
|
823
|
-
<
|
|
684
|
+
<Router>
|
|
685
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
686
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
687
|
+
.map(({ locale, urlPrefix }) => (
|
|
688
|
+
<Route
|
|
689
|
+
key={locale}
|
|
690
|
+
path={`${urlPrefix}/:rest*`}
|
|
691
|
+
component={() => (
|
|
692
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
693
|
+
)}
|
|
694
|
+
/>
|
|
695
|
+
))}
|
|
696
|
+
</Router>
|
|
824
697
|
</LocationProvider>
|
|
825
698
|
);
|
|
826
699
|
```
|
|
827
700
|
|
|
828
701
|
```jsx fileName="src/components/LocaleRouter.jsx" codeFormat="esm"
|
|
829
|
-
|
|
830
|
-
import { configuration, getPathWithoutLocale } from "intlayer";
|
|
702
|
+
import { localeMap } from "intlayer";
|
|
831
703
|
import { IntlayerProvider } from "preact-intlayer";
|
|
832
|
-
import { LocationProvider,
|
|
833
|
-
import { useEffect } from "preact/hooks";
|
|
834
|
-
import { h } from "preact"; // Diperlukan untuk JSX
|
|
835
|
-
|
|
836
|
-
// Mendestruktur konfigurasi dari Intlayer
|
|
837
|
-
const { internationalization, routing } = configuration;
|
|
838
|
-
const { locales, defaultLocale } = internationalization;
|
|
839
|
-
|
|
840
|
-
const Navigate = ({ to, replace }) => {
|
|
841
|
-
const { route } = useLocation();
|
|
842
|
-
useEffect(() => {
|
|
843
|
-
route(to, replace);
|
|
844
|
-
}, [to, replace, route]);
|
|
845
|
-
return null;
|
|
846
|
-
};
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
/**
|
|
850
|
-
* Komponen yang menangani lokalisasi dan membungkus children dengan konteks locale yang sesuai.
|
|
851
|
-
* Komponen ini mengelola deteksi dan validasi locale berdasarkan URL.
|
|
852
|
-
*/
|
|
853
|
-
const AppLocalized = ({ children, locale }) => {
|
|
854
|
-
const { path: pathname, url } = useLocation();
|
|
855
|
-
|
|
856
|
-
if (!url) {
|
|
857
|
-
return null;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
const search = url.substring(pathname.length);
|
|
861
|
-
|
|
862
|
-
// Menentukan locale saat ini, menggunakan default jika tidak disediakan
|
|
863
|
-
const currentLocale = locale ?? defaultLocale;
|
|
864
|
-
|
|
865
|
-
// Menghapus prefix locale dari path untuk membentuk path dasar
|
|
866
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
867
|
-
pathname // Path URL saat ini
|
|
868
|
-
);
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* Jika routing.mode adalah 'prefix-all', locale default harus selalu diprefix.
|
|
872
|
-
*/
|
|
873
|
-
if (routing.mode === "prefix-all") {
|
|
874
|
-
// Validasi locale
|
|
875
|
-
if (!locale || !locales.includes(locale)) {
|
|
876
|
-
// Alihkan ke locale default dengan path yang diperbarui
|
|
877
|
-
return (
|
|
878
|
-
<Navigate
|
|
879
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
880
|
-
replace // Gantikan entri riwayat saat ini dengan yang baru
|
|
881
|
-
/>
|
|
882
|
-
);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
886
|
-
return (
|
|
887
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
888
|
-
);
|
|
889
|
-
} else {
|
|
890
|
-
/**
|
|
891
|
-
* Ketika routing.mode bukan 'prefix-all', locale default tidak diberi prefix.
|
|
892
|
-
* Pastikan locale saat ini valid dan bukan locale default.
|
|
893
|
-
*/
|
|
894
|
-
if (
|
|
895
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
896
|
-
!locales
|
|
897
|
-
.filter(
|
|
898
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Kecualikan locale default
|
|
899
|
-
)
|
|
900
|
-
.includes(currentLocale) // Periksa apakah locale saat ini ada dalam daftar locale yang valid
|
|
901
|
-
) {
|
|
902
|
-
// Redirect ke path tanpa prefix locale
|
|
903
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
907
|
-
return (
|
|
908
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
909
|
-
);
|
|
910
|
-
}
|
|
911
|
-
};
|
|
912
|
-
|
|
913
|
-
const RouterContent = ({ children }) => {
|
|
914
|
-
const { path } = useLocation();
|
|
915
|
-
|
|
916
|
-
if (!path) {
|
|
917
|
-
return null;
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
const pathLocale = path.split("/")[1];
|
|
921
|
-
|
|
922
|
-
const isLocaleRoute = locales
|
|
923
|
-
.filter(
|
|
924
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
925
|
-
)
|
|
926
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
927
|
-
|
|
928
|
-
if (isLocaleRoute) {
|
|
929
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
return (
|
|
933
|
-
<AppLocalized
|
|
934
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
935
|
-
>
|
|
936
|
-
{children}
|
|
937
|
-
</AppLocalized>
|
|
938
|
-
);
|
|
939
|
-
};
|
|
704
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
940
705
|
|
|
941
706
|
/**
|
|
942
|
-
*
|
|
943
|
-
*
|
|
707
|
+
* Một thành phần định tuyến thiết lập các tuyến đường cụ thể cho từng ngôn ngữ.
|
|
708
|
+
* Nó sử dụng preact-iso để quản lý điều hướng và hiển thị các thành phần cục bộ.
|
|
944
709
|
*/
|
|
945
710
|
export const LocaleRouter = ({ children }) => (
|
|
946
711
|
<LocationProvider>
|
|
947
|
-
<
|
|
712
|
+
<Router>
|
|
713
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
714
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
715
|
+
.map(({ locale, urlPrefix }) => (
|
|
716
|
+
<Route
|
|
717
|
+
key={locale}
|
|
718
|
+
path={`${urlPrefix}/:rest*`}
|
|
719
|
+
component={() => (
|
|
720
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
721
|
+
)}
|
|
722
|
+
/>
|
|
723
|
+
))}
|
|
724
|
+
</Router>
|
|
948
725
|
</LocationProvider>
|
|
949
726
|
);
|
|
950
727
|
```
|
|
951
728
|
|
|
952
729
|
```jsx fileName="src/components/LocaleRouter.cjsx" codeFormat="commonjs"
|
|
953
|
-
|
|
954
|
-
const { configuration, getPathWithoutLocale } = require("intlayer");
|
|
730
|
+
const { localeMap } = require("intlayer");
|
|
955
731
|
const { IntlayerProvider } = require("preact-intlayer");
|
|
956
|
-
const { LocationProvider,
|
|
957
|
-
const { useEffect } = require("preact/hooks");
|
|
958
|
-
const { h } = require("preact"); // Diperlukan untuk JSX
|
|
959
|
-
|
|
960
|
-
// Mendestrukturisasi konfigurasi dari Intlayer
|
|
961
|
-
const { internationalization, routing } = configuration;
|
|
962
|
-
const { locales, defaultLocale } = internationalization;
|
|
963
|
-
|
|
964
|
-
const Navigate = ({ to, replace }) => {
|
|
965
|
-
const { route } = useLocation();
|
|
966
|
-
useEffect(() => {
|
|
967
|
-
route(to, replace);
|
|
968
|
-
}, [to, replace, route]);
|
|
969
|
-
return null;
|
|
970
|
-
};
|
|
732
|
+
const { LocationProvider, Router, Route } = require("preact-iso");
|
|
971
733
|
|
|
972
734
|
/**
|
|
973
|
-
*
|
|
974
|
-
*
|
|
735
|
+
* Một thành phần định tuyến thiết lập các tuyến đường cụ thể cho từng ngôn ngữ.
|
|
736
|
+
* Nó sử dụng preact-iso để quản lý điều hướng và hiển thị các thành phần cục bộ.
|
|
975
737
|
*/
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
);
|
|
992
|
-
|
|
993
|
-
/**
|
|
994
|
-
* Jika routing.mode adalah 'prefix-all', locale default harus selalu diprefix.
|
|
995
|
-
*/
|
|
996
|
-
if (routing.mode === "prefix-all") {
|
|
997
|
-
// Validasi locale
|
|
998
|
-
if (!locale || !locales.includes(locale)) {
|
|
999
|
-
// Redirect ke locale default dengan path yang diperbarui
|
|
1000
|
-
return (
|
|
1001
|
-
<Navigate
|
|
1002
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
1003
|
-
replace // Gantikan entri history saat ini dengan yang baru
|
|
1004
|
-
/>
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
1009
|
-
return (
|
|
1010
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1011
|
-
);
|
|
1012
|
-
} else {
|
|
1013
|
-
/**
|
|
1014
|
-
* Ketika routing.mode bukan 'prefix-all', locale default tidak diberi prefix.
|
|
1015
|
-
* Pastikan locale saat ini valid dan bukan locale default.
|
|
1016
|
-
*/
|
|
1017
|
-
if (
|
|
1018
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
1019
|
-
!locales
|
|
1020
|
-
.filter(
|
|
1021
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Kecualikan locale default
|
|
738
|
+
const LocaleRouter = ({ children }) =>
|
|
739
|
+
h(
|
|
740
|
+
LocationProvider,
|
|
741
|
+
{},
|
|
742
|
+
h(
|
|
743
|
+
Router,
|
|
744
|
+
{},
|
|
745
|
+
localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
746
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
747
|
+
.map(({ locale, urlPrefix }) =>
|
|
748
|
+
h(Route, {
|
|
749
|
+
key: locale,
|
|
750
|
+
path: `${urlPrefix}/:rest*`,
|
|
751
|
+
component: () => h(IntlayerProvider, { locale }, children),
|
|
752
|
+
})
|
|
1022
753
|
)
|
|
1023
|
-
.includes(currentLocale) // Periksa apakah locale saat ini ada dalam daftar locale yang valid
|
|
1024
|
-
) {
|
|
1025
|
-
// Redirect ke path tanpa prefix locale
|
|
1026
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
// Bungkus children dengan IntlayerProvider dan set locale saat ini
|
|
1030
|
-
return (
|
|
1031
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
const RouterContent = ({ children }) => {
|
|
1037
|
-
const { path } = useLocation();
|
|
1038
|
-
|
|
1039
|
-
if (!path) {
|
|
1040
|
-
return null;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
const pathLocale = path.split("/")[1];
|
|
1044
|
-
|
|
1045
|
-
const isLocaleRoute = locales
|
|
1046
|
-
.filter(
|
|
1047
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
1048
754
|
)
|
|
1049
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
1050
|
-
|
|
1051
|
-
if (isLocaleRoute) {
|
|
1052
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
return (
|
|
1056
|
-
<AppLocalized
|
|
1057
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
1058
|
-
>
|
|
1059
|
-
{children}
|
|
1060
|
-
</AppLocalized>
|
|
1061
755
|
);
|
|
1062
|
-
};
|
|
1063
|
-
|
|
1064
|
-
/**
|
|
1065
|
-
* Komponen router yang mengatur rute spesifik locale.
|
|
1066
|
-
* Menggunakan preact-iso untuk mengelola navigasi dan merender komponen yang dilokalkan.
|
|
1067
|
-
*/
|
|
1068
|
-
const LocaleRouter = ({ children }) => (
|
|
1069
|
-
<LocationProvider>
|
|
1070
|
-
<RouterContent>{children}</RouterContent>
|
|
1071
|
-
</LocationProvider>
|
|
1072
|
-
);
|
|
1073
756
|
|
|
1074
757
|
module.exports = { LocaleRouter };
|
|
1075
758
|
```
|
|
1076
759
|
|
|
1077
|
-
|
|
760
|
+
Sau đó, bạn có thể sử dụng thành phần `LocaleRouter` trong ứng dụng của mình:
|
|
1078
761
|
|
|
1079
762
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1080
763
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1081
764
|
import type { FunctionalComponent } from "preact";
|
|
1082
|
-
|
|
765
|
+
|
|
766
|
+
// ... Thành phần AppContent của bạn
|
|
1083
767
|
|
|
1084
768
|
const App: FunctionalComponent = () => (
|
|
1085
769
|
<LocaleRouter>
|
|
@@ -1092,7 +776,8 @@ export default App;
|
|
|
1092
776
|
|
|
1093
777
|
```jsx fileName="src/app.jsx" codeFormat="esm"
|
|
1094
778
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1095
|
-
|
|
779
|
+
|
|
780
|
+
// ... Thành phần AppContent của bạn
|
|
1096
781
|
|
|
1097
782
|
const App = () => (
|
|
1098
783
|
<LocaleRouter>
|
|
@@ -1105,7 +790,8 @@ export default App;
|
|
|
1105
790
|
|
|
1106
791
|
```jsx fileName="src/app.cjsx" codeFormat="commonjs"
|
|
1107
792
|
const { LocaleRouter } = require("./components/LocaleRouter");
|
|
1108
|
-
|
|
793
|
+
|
|
794
|
+
// ... Thành phần AppContent của bạn
|
|
1109
795
|
|
|
1110
796
|
const App = () => (
|
|
1111
797
|
<LocaleRouter>
|
|
@@ -1116,49 +802,12 @@ const App = () => (
|
|
|
1116
802
|
module.exports = App;
|
|
1117
803
|
```
|
|
1118
804
|
|
|
1119
|
-
Secara paralel, Anda juga dapat menggunakan `intlayerProxy` untuk menambahkan routing sisi server ke aplikasi Anda. Plugin ini akan secara otomatis mendeteksi locale saat ini berdasarkan URL dan mengatur cookie locale yang sesuai. Jika tidak ada locale yang ditentukan, plugin akan menentukan locale yang paling tepat berdasarkan preferensi bahasa browser pengguna. Jika tidak ada locale yang terdeteksi, maka akan mengarahkan ulang ke locale default.
|
|
1120
|
-
|
|
1121
|
-
> Perlu diperhatikan bahwa untuk menggunakan `intlayerProxy` dalam produksi, Anda perlu memindahkan paket `vite-intlayer` dari `devDependencies` ke `dependencies`.
|
|
1122
|
-
|
|
1123
|
-
```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
|
|
1124
|
-
import { defineConfig } from "vite";
|
|
1125
|
-
import preact from "@preact/preset-vite";
|
|
1126
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1127
|
-
|
|
1128
|
-
// https://vitejs.dev/config/
|
|
1129
|
-
export default defineConfig({
|
|
1130
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1131
|
-
});
|
|
1132
|
-
```
|
|
1133
|
-
|
|
1134
|
-
```javascript {3,7} fileName="vite.config.mjs" codeFormat="esm"
|
|
1135
|
-
import { defineConfig } from "vite";
|
|
1136
|
-
import preact from "@preact/preset-vite";
|
|
1137
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1138
|
-
|
|
1139
|
-
// https://vitejs.dev/config/
|
|
1140
|
-
export default defineConfig({
|
|
1141
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1142
|
-
});
|
|
1143
|
-
```
|
|
1144
|
-
|
|
1145
|
-
```javascript {3,7} fileName="vite.config.cjs" codeFormat="commonjs"
|
|
1146
|
-
const { defineConfig } = require("vite");
|
|
1147
|
-
const preact = require("@preact/preset-vite");
|
|
1148
|
-
const { intlayer, intlayerProxy } = require("vite-intlayer");
|
|
1149
|
-
|
|
1150
|
-
// https://vitejs.dev/config/
|
|
1151
|
-
module.exports = defineConfig({
|
|
1152
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1153
|
-
});
|
|
1154
|
-
```
|
|
1155
|
-
|
|
1156
805
|
### (Opsional) Langkah 8: Ubah URL saat locale berubah
|
|
1157
806
|
|
|
1158
|
-
|
|
807
|
+
Để thay đổi URL khi ngôn ngữ thay đổi, bạn có thể sử dụng thuộc tính `onLocaleChange` được cung cấp bởi hook `useLocale`. Đồng thời, bạn có thể sử dụng phương thức `route` từ `useLocation` của `preact-iso` để cập nhật đường dẫn URL.
|
|
1159
808
|
|
|
1160
809
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
1161
|
-
import { useLocation
|
|
810
|
+
import { useLocation } from "preact-iso";
|
|
1162
811
|
import {
|
|
1163
812
|
Locales,
|
|
1164
813
|
getHTMLTextDir,
|
|
@@ -1169,37 +818,15 @@ import { useLocale } from "preact-intlayer";
|
|
|
1169
818
|
import type { FunctionalComponent } from "preact";
|
|
1170
819
|
|
|
1171
820
|
const LocaleSwitcher: FunctionalComponent = () => {
|
|
1172
|
-
const
|
|
1173
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1174
|
-
});
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
### (Optional) Step 8: Change the URL when the locale changes
|
|
1178
|
-
|
|
1179
|
-
To change the URL when the locale changes, you can use the `onLocaleChange` prop provided by the `useLocale` hook. In parallel, you can use `useLocation` and `route` from `preact-iso` to update the URL path.
|
|
1180
|
-
|
|
1181
|
-
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
1182
|
-
import { useLocation, route } from "preact-iso";
|
|
1183
|
-
import {
|
|
1184
|
-
Locales,
|
|
1185
|
-
getHTMLTextDir,
|
|
1186
|
-
getLocaleName,
|
|
1187
|
-
getLocalizedUrl,
|
|
1188
|
-
} from "intlayer";
|
|
1189
|
-
import { useLocale } from "preact-intlayer";
|
|
1190
|
-
import type { FunctionalComponent } from "preact";
|
|
1191
|
-
|
|
1192
|
-
const LocaleSwitcher: FunctionalComponent = () => {
|
|
1193
|
-
const location = useLocation();
|
|
821
|
+
const { url, route } = useLocation();
|
|
1194
822
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1195
823
|
onLocaleChange: (newLocale) => {
|
|
1196
|
-
|
|
1197
|
-
//
|
|
1198
|
-
|
|
1199
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
824
|
+
// Xây dựng URL với ngôn ngữ đã cập nhật
|
|
825
|
+
// Ví dụ: /es/about?foo=bar
|
|
826
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1200
827
|
|
|
1201
|
-
//
|
|
1202
|
-
route(pathWithLocale, true); // true
|
|
828
|
+
// Cập nhật đường dẫn URL
|
|
829
|
+
route(pathWithLocale, true); // true để thay thế (replace)
|
|
1203
830
|
},
|
|
1204
831
|
});
|
|
1205
832
|
|
|
@@ -1209,30 +836,30 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
1209
836
|
<div id="localePopover" popover="auto">
|
|
1210
837
|
{availableLocales.map((localeItem) => (
|
|
1211
838
|
<a
|
|
1212
|
-
href={getLocalizedUrl(
|
|
839
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1213
840
|
hreflang={localeItem}
|
|
1214
841
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1215
842
|
onClick={(e) => {
|
|
1216
843
|
e.preventDefault();
|
|
1217
844
|
setLocale(localeItem);
|
|
1218
|
-
//
|
|
845
|
+
// Điều hướng theo lập trình sau khi thiết lập ngôn ngữ sẽ được xử lý bởi onLocaleChange
|
|
1219
846
|
}}
|
|
1220
847
|
key={localeItem}
|
|
1221
848
|
>
|
|
1222
849
|
<span>
|
|
1223
|
-
{/* Locale -
|
|
850
|
+
{/* Locale - ví dụ: FR */}
|
|
1224
851
|
{localeItem}
|
|
1225
852
|
</span>
|
|
1226
853
|
<span>
|
|
1227
|
-
{/*
|
|
854
|
+
{/* Ngôn ngữ trong chính Locale đó - ví dụ: Français */}
|
|
1228
855
|
{getLocaleName(localeItem, localeItem)}
|
|
1229
856
|
</span>
|
|
1230
857
|
<span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
|
|
1231
|
-
{/*
|
|
858
|
+
{/* Ngôn ngữ trong Locale hiện tại - ví dụ: Francés với ngôn ngữ hiện tại được đặt thành Locales.SPANISH */}
|
|
1232
859
|
{getLocaleName(localeItem, locale)}
|
|
1233
860
|
</span>
|
|
1234
861
|
<span dir="ltr" lang={Locales.ENGLISH}>
|
|
1235
|
-
{/*
|
|
862
|
+
{/* Ngôn ngữ bằng tiếng Anh - ví dụ: French */}
|
|
1236
863
|
{getLocaleName(localeItem, Locales.ENGLISH)}
|
|
1237
864
|
</span>
|
|
1238
865
|
</a>
|
|
@@ -1246,7 +873,7 @@ export default LocaleSwitcher;
|
|
|
1246
873
|
```
|
|
1247
874
|
|
|
1248
875
|
```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
|
|
1249
|
-
import { useLocation
|
|
876
|
+
import { useLocation } from "preact-iso";
|
|
1250
877
|
import {
|
|
1251
878
|
Locales,
|
|
1252
879
|
getHTMLTextDir,
|
|
@@ -1254,14 +881,12 @@ import {
|
|
|
1254
881
|
getLocalizedUrl,
|
|
1255
882
|
} from "intlayer";
|
|
1256
883
|
import { useLocale } from "preact-intlayer";
|
|
1257
|
-
import { h } from "preact"; // Untuk JSX
|
|
1258
884
|
|
|
1259
885
|
const LocaleSwitcher = () => {
|
|
1260
|
-
const
|
|
886
|
+
const { url, route } = useLocation();
|
|
1261
887
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1262
888
|
onLocaleChange: (newLocale) => {
|
|
1263
|
-
const
|
|
1264
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
889
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1265
890
|
route(pathWithLocale, true);
|
|
1266
891
|
},
|
|
1267
892
|
});
|
|
@@ -1272,7 +897,7 @@ const LocaleSwitcher = () => {
|
|
|
1272
897
|
<div id="localePopover" popover="auto">
|
|
1273
898
|
{availableLocales.map((localeItem) => (
|
|
1274
899
|
<a
|
|
1275
|
-
href={getLocalizedUrl(
|
|
900
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1276
901
|
hreflang={localeItem}
|
|
1277
902
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1278
903
|
onClick={(e) => {
|
|
@@ -1300,7 +925,7 @@ export default LocaleSwitcher;
|
|
|
1300
925
|
```
|
|
1301
926
|
|
|
1302
927
|
```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
|
|
1303
|
-
const { useLocation
|
|
928
|
+
const { useLocation } = require("preact-iso");
|
|
1304
929
|
const {
|
|
1305
930
|
Locales,
|
|
1306
931
|
getHTMLTextDir,
|
|
@@ -1308,81 +933,74 @@ const {
|
|
|
1308
933
|
getLocalizedUrl,
|
|
1309
934
|
} = require("intlayer");
|
|
1310
935
|
const { useLocale } = require("preact-intlayer");
|
|
1311
|
-
const { h } = require("preact"); // Untuk JSX
|
|
1312
936
|
|
|
1313
937
|
const LocaleSwitcher = () => {
|
|
1314
|
-
const
|
|
938
|
+
const { url, route } = useLocation();
|
|
1315
939
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1316
940
|
onLocaleChange: (newLocale) => {
|
|
1317
|
-
const
|
|
1318
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
941
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1319
942
|
route(pathWithLocale, true);
|
|
1320
943
|
},
|
|
1321
944
|
});
|
|
1322
945
|
|
|
1323
|
-
return (
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
946
|
+
return h(
|
|
947
|
+
"div",
|
|
948
|
+
{},
|
|
949
|
+
h("button", { popovertarget: "localePopover" }, getLocaleName(locale)),
|
|
950
|
+
h(
|
|
951
|
+
"div",
|
|
952
|
+
{ id: "localePopover", popover: "auto" },
|
|
953
|
+
availableLocales.map((localeItem) =>
|
|
954
|
+
h(
|
|
955
|
+
"a",
|
|
956
|
+
{
|
|
957
|
+
href: getLocalizedUrl(url, localeItem),
|
|
958
|
+
hreflang: localeItem,
|
|
959
|
+
"aria-current": locale === localeItem ? "page" : undefined,
|
|
960
|
+
onClick: (e) => {
|
|
1333
961
|
e.preventDefault();
|
|
1334
962
|
setLocale(localeItem);
|
|
1335
|
-
}
|
|
1336
|
-
key
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
963
|
+
},
|
|
964
|
+
key: localeItem,
|
|
965
|
+
},
|
|
966
|
+
h("span", {}, localeItem),
|
|
967
|
+
h("span", {}, getLocaleName(localeItem, localeItem)),
|
|
968
|
+
h(
|
|
969
|
+
"span",
|
|
970
|
+
{ dir: getHTMLTextDir(localeItem), lang: localeItem },
|
|
971
|
+
getLocaleName(localeItem, locale)
|
|
972
|
+
),
|
|
973
|
+
h(
|
|
974
|
+
"span",
|
|
975
|
+
{ dir: "ltr", lang: Locales.ENGLISH },
|
|
976
|
+
getLocaleName(localeItem, Locales.ENGLISH)
|
|
977
|
+
)
|
|
978
|
+
)
|
|
979
|
+
)
|
|
980
|
+
)
|
|
1350
981
|
);
|
|
1351
982
|
};
|
|
1352
983
|
|
|
1353
984
|
module.exports = LocaleSwitcher;
|
|
1354
985
|
```
|
|
1355
986
|
|
|
1356
|
-
>
|
|
987
|
+
> Tham khảo tài liệu:
|
|
1357
988
|
>
|
|
1358
|
-
> > - [`useLocale`
|
|
1359
|
-
>
|
|
1360
|
-
> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getLocaleName.md)
|
|
1361
|
-
> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getLocalizedUrl.md)
|
|
1362
|
-
> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getHTMLTextDir.md)
|
|
1363
|
-
> - atribut [`hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
|
|
1364
|
-
> - atribut [`lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)
|
|
1365
|
-
> - atribut [`dir`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)
|
|
1366
|
-
> - atribut [`aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)
|
|
1367
|
-
> - [API Popover](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) la.org/en-US/docs/Web/HTML/Global_attributes/dir)> - [`atribut aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)> - [API Popover](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API)
|
|
1368
|
-
|
|
1369
|
-
Berikut adalah **Langkah 9** yang diperbarui dengan penjelasan tambahan dan contoh kode yang disempurnakan:
|
|
989
|
+
> > - [Hook `useLocale`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/react-intlayer/useLocale.md) (API tương tự cho `preact-intlayer`)> - [Hook `getLocaleName`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getLocaleName.md)> - [Hook `getLocalizedUrl`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getLocalizedUrl.md)> - [Hook `getHTMLTextDir`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/packages/intlayer/getHTMLTextDir.md)> - [Thuộc tính `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)> - [Thuộc tính `lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)> - [Thuộc tính `dir`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)> - [Thuộc tính `aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)> - [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API)
|
|
1370
990
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
### (Opsional) Langkah 9: Mengubah Atribut Bahasa dan Arah pada HTML
|
|
991
|
+
### (Opsional) Langkah 9: Ganti atribut bahasa dan arah HTML
|
|
1374
992
|
|
|
1375
|
-
|
|
993
|
+
Khi ứng dụng của bạn hỗ trợ nhiều ngôn ngữ, việc cập nhật các thuộc tính `lang` và `dir` của thẻ `<html>` để khớp với locale hiện tại là rất quan trọng. Làm như vậy đảm bảo:
|
|
1376
994
|
|
|
1377
|
-
- **
|
|
1378
|
-
- **
|
|
995
|
+
- **Khả năng truy cập**: Trình đọc màn hình và các công nghệ hỗ trợ dựa trên thuộc tính `lang` chính xác để phát âm và diễn giải nội dung một cách chính xác.
|
|
996
|
+
- **Hiển thị văn bản**: Thuộc tính `dir` (hướng) đảm bảo văn bản được hiển thị theo thứ tự thích hợp (ví dụ: từ trái sang phải cho tiếng Anh, từ phải sang trái cho tiếng Ả Rập hoặc tiếng Do Thái), điều này rất cần thiết cho khả năng đọc.
|
|
1379
997
|
- **SEO**: Mesin pencari menggunakan atribut `lang` untuk menentukan bahasa halaman Anda, membantu menyajikan konten lokal yang tepat dalam hasil pencarian.
|
|
1380
998
|
|
|
1381
|
-
|
|
999
|
+
Bằng cách cập nhật các thuộc tính này một cách động khi locale thay đổi, bạn đảm bảo trải nghiệm nhất quán và dễ tiếp cận cho người dùng trên tất cả các ngôn ngữ được hỗ trợ.
|
|
1382
1000
|
|
|
1383
|
-
####
|
|
1001
|
+
#### Triển khai Hook
|
|
1384
1002
|
|
|
1385
|
-
|
|
1003
|
+
Tạo một hook tùy chỉnh để quản lý các thuộc tính HTML. Hook này lắng nghe các thay đổi về ngôn ngữ và cập nhật các thuộc tính cho phù hợp:
|
|
1386
1004
|
|
|
1387
1005
|
```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx" codeFormat="typescript"
|
|
1388
1006
|
import { useEffect } from "preact/hooks";
|
|
@@ -1390,20 +1008,20 @@ import { useLocale } from "preact-intlayer";
|
|
|
1390
1008
|
import { getHTMLTextDir } from "intlayer";
|
|
1391
1009
|
|
|
1392
1010
|
/**
|
|
1393
|
-
*
|
|
1394
|
-
* - `lang`:
|
|
1395
|
-
* - `dir`:
|
|
1011
|
+
* Cập nhật các thuộc tính `lang` và `dir` của phần tử HTML <html> dựa trên ngôn ngữ hiện tại.
|
|
1012
|
+
* - `lang`: Thông báo cho trình duyệt và công cụ tìm kiếm về ngôn ngữ của trang.
|
|
1013
|
+
* - `dir`: Đảm bảo thứ tự đọc chính xác (ví dụ: 'ltr' cho tiếng Anh, 'rtl' cho tiếng Ả Rập).
|
|
1396
1014
|
*
|
|
1397
|
-
*
|
|
1015
|
+
* Bản cập nhật động này rất cần thiết để hiển thị văn bản, khả năng truy cập và SEO thích hợp.
|
|
1398
1016
|
*/
|
|
1399
1017
|
export const useI18nHTMLAttributes = () => {
|
|
1400
1018
|
const { locale } = useLocale();
|
|
1401
1019
|
|
|
1402
1020
|
useEffect(() => {
|
|
1403
|
-
//
|
|
1021
|
+
// Cập nhật thuộc tính ngôn ngữ thành ngôn ngữ hiện tại.
|
|
1404
1022
|
document.documentElement.lang = locale;
|
|
1405
1023
|
|
|
1406
|
-
//
|
|
1024
|
+
// Đặt hướng văn bản dựa trên ngôn ngữ hiện tại.
|
|
1407
1025
|
document.documentElement.dir = getHTMLTextDir(locale);
|
|
1408
1026
|
}, [locale]);
|
|
1409
1027
|
};
|
|
@@ -1415,7 +1033,7 @@ import { useLocale } from "preact-intlayer";
|
|
|
1415
1033
|
import { getHTMLTextDir } from "intlayer";
|
|
1416
1034
|
|
|
1417
1035
|
/**
|
|
1418
|
-
*
|
|
1036
|
+
* Cập nhật các thuộc tính `lang` và `dir` của phần tử HTML <html> dựa trên ngôn ngữ hiện tại.
|
|
1419
1037
|
*/
|
|
1420
1038
|
export const useI18nHTMLAttributes = () => {
|
|
1421
1039
|
const { locale } = useLocale();
|
|
@@ -1433,7 +1051,7 @@ const { useLocale } = require("preact-intlayer");
|
|
|
1433
1051
|
const { getHTMLTextDir } = require("intlayer");
|
|
1434
1052
|
|
|
1435
1053
|
/**
|
|
1436
|
-
*
|
|
1054
|
+
* Cập nhật các thuộc tính `lang` và `dir` của phần tử HTML <html> dựa trên ngôn ngữ hiện tại.
|
|
1437
1055
|
*/
|
|
1438
1056
|
const useI18nHTMLAttributes = () => {
|
|
1439
1057
|
const { locale } = useLocale();
|
|
@@ -1447,22 +1065,22 @@ const useI18nHTMLAttributes = () => {
|
|
|
1447
1065
|
module.exports = { useI18nHTMLAttributes };
|
|
1448
1066
|
```
|
|
1449
1067
|
|
|
1450
|
-
####
|
|
1068
|
+
#### Sử dụng Hook trong ứng dụng của bạn
|
|
1451
1069
|
|
|
1452
|
-
|
|
1070
|
+
Tích hợp hook vào thành phần chính của bạn để các thuộc tính HTML cập nhật bất cứ khi nào ngôn ngữ thay đổi:
|
|
1453
1071
|
|
|
1454
1072
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1455
1073
|
import type { FunctionalComponent } from "preact";
|
|
1456
|
-
import { IntlayerProvider } from "preact-intlayer"; // useIntlayer
|
|
1074
|
+
import { IntlayerProvider } from "preact-intlayer"; // useIntlayer đã được nhập nếu AppContent cần nó
|
|
1457
1075
|
import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
|
|
1458
1076
|
import "./app.css";
|
|
1459
|
-
//
|
|
1077
|
+
// Định nghĩa AppContent từ Bước 5
|
|
1460
1078
|
|
|
1461
1079
|
const AppWithHooks: FunctionalComponent = () => {
|
|
1462
|
-
//
|
|
1080
|
+
// Áp dụng hook để cập nhật các thuộc tính lang và dir của thẻ <html> dựa trên ngôn ngữ.
|
|
1463
1081
|
useI18nHTMLAttributes();
|
|
1464
1082
|
|
|
1465
|
-
//
|
|
1083
|
+
// Giả sử AppContent là thành phần hiển thị nội dung chính của bạn từ Bước 5
|
|
1466
1084
|
return <AppContent />;
|
|
1467
1085
|
};
|
|
1468
1086
|
|
|
@@ -1479,7 +1097,7 @@ export default App;
|
|
|
1479
1097
|
import { IntlayerProvider } from "preact-intlayer";
|
|
1480
1098
|
import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
|
|
1481
1099
|
import "./app.css";
|
|
1482
|
-
//
|
|
1100
|
+
// Định nghĩa AppContent từ Bước 5
|
|
1483
1101
|
|
|
1484
1102
|
const AppWithHooks = () => {
|
|
1485
1103
|
useI18nHTMLAttributes();
|
|
@@ -1499,7 +1117,7 @@ export default App;
|
|
|
1499
1117
|
const { IntlayerProvider } = require("preact-intlayer");
|
|
1500
1118
|
const { useI18nHTMLAttributes } = require("./hooks/useI18nHTMLAttributes");
|
|
1501
1119
|
require("./app.css");
|
|
1502
|
-
//
|
|
1120
|
+
// Định nghĩa AppContent từ Bước 5
|
|
1503
1121
|
|
|
1504
1122
|
const AppWithHooks = () => {
|
|
1505
1123
|
useI18nHTMLAttributes();
|
|
@@ -1515,202 +1133,182 @@ const App = () => (
|
|
|
1515
1133
|
module.exports = App;
|
|
1516
1134
|
```
|
|
1517
1135
|
|
|
1518
|
-
Dengan menerapkan perubahan ini, aplikasi Anda akan:
|
|
1519
|
-
|
|
1520
|
-
- Memastikan atribut **bahasa** (`lang`) mencerminkan locale saat ini dengan benar, yang penting untuk SEO dan perilaku browser.
|
|
1521
|
-
- Menyesuaikan **arah teks** (`dir`) sesuai dengan locale, meningkatkan keterbacaan dan kegunaan untuk bahasa dengan urutan baca yang berbeda.
|
|
1522
|
-
- Memberikan pengalaman yang lebih **aksesibel**, karena teknologi bantu bergantung pada atribut ini agar berfungsi secara optimal.
|
|
1523
|
-
|
|
1524
1136
|
### (Opsional) Langkah 10: Membuat Komponen Link yang Dilokalkan
|
|
1525
1137
|
|
|
1526
|
-
|
|
1138
|
+
Để đảm bảo rằng điều hướng của ứng dụng của bạn tôn trọng ngôn ngữ hiện tại, bạn có thể tạo một thành phần `Link` tùy chỉnh. Thành phần này tự động thêm tiền tố ngôn ngữ hiện tại vào các URL nội bộ.
|
|
1527
1139
|
|
|
1528
|
-
|
|
1140
|
+
Hành vi này hữu ích vì một số lý do:
|
|
1529
1141
|
|
|
1530
|
-
- **SEO
|
|
1531
|
-
- **
|
|
1532
|
-
- **
|
|
1142
|
+
- **SEO và Trải nghiệm người dùng**: URL được bản địa hóa giúp công cụ tìm kiếm lập chỉ mục các trang dành riêng cho ngôn ngữ một cách chính xác và cung cấp cho người dùng nội dung bằng ngôn ngữ ưa thích của họ.
|
|
1143
|
+
- **Tính nhất quán**: Bằng cách sử dụng một liên kết được bản địa hóa trong toàn bộ ứng dụng của mình, bạn đảm bảo rằng điều hướng vẫn nằm trong ngôn ngữ hiện tại, ngăn chặn các thay đổi ngôn ngữ không mong muốn.
|
|
1144
|
+
- **Khả năng bảo trì**: Centralizing logic bản địa hóa trong một component duy nhất giúp đơn giản hóa việc quản lý các URL.
|
|
1533
1145
|
|
|
1534
|
-
|
|
1146
|
+
Dưới đây là cách triển khai thành phần `Link` được bản địa hóa trong Preact:
|
|
1535
1147
|
|
|
1536
|
-
```tsx fileName="src/components/
|
|
1148
|
+
```tsx fileName="src/components/Link.tsx" codeFormat="typescript"
|
|
1537
1149
|
import { getLocalizedUrl } from "intlayer";
|
|
1538
1150
|
import { useLocale } from "preact-intlayer";
|
|
1539
|
-
import { useLocation, route } from "preact-iso";
|
|
1540
|
-
import type { JSX } from "preact";
|
|
1541
1151
|
import { forwardRef } from "preact/compat";
|
|
1152
|
+
import type { JSX } from "preact";
|
|
1542
1153
|
|
|
1543
|
-
|
|
1544
|
-
* Props untuk LocalizedLink - mewarisi atribut anchor + beberapa properti ekstra.
|
|
1545
|
-
*/
|
|
1546
|
-
export interface LocalizedLinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
|
|
1154
|
+
export interface LinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
|
|
1547
1155
|
href: string;
|
|
1548
|
-
replace?: boolean; // Opsional: untuk mengganti state history
|
|
1549
1156
|
}
|
|
1550
1157
|
|
|
1551
1158
|
/**
|
|
1552
|
-
*
|
|
1159
|
+
* Hàm tiện ích để kiểm tra xem một URL nhất định có phải là bên ngoài hay không.
|
|
1160
|
+
* Nếu URL bắt đầu bằng http:// hoặc https://, nó được coi là bên ngoài.
|
|
1553
1161
|
*/
|
|
1554
|
-
export
|
|
1555
|
-
|
|
1556
|
-
}
|
|
1162
|
+
export const checkIsExternalLink = (href?: string): boolean =>
|
|
1163
|
+
/^https?:\/\//.test(href ?? "");
|
|
1557
1164
|
|
|
1558
1165
|
/**
|
|
1559
|
-
*
|
|
1560
|
-
*
|
|
1166
|
+
* Một thành phần Link tùy chỉnh thích ứng với thuộc tính href dựa trên ngôn ngữ hiện tại.
|
|
1167
|
+
* Đối với các liên kết nội bộ, nó sử dụng `getLocalizedUrl` để thêm tiền tố ngôn ngữ vào URL (ví dụ: /fr/about).
|
|
1168
|
+
* Điều này đảm bảo rằng điều hướng vẫn nằm trong cùng một bối cảnh ngôn ngữ.
|
|
1561
1169
|
*/
|
|
1562
|
-
export const
|
|
1563
|
-
({ href, children,
|
|
1170
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
1171
|
+
({ href, children, ...props }, ref) => {
|
|
1564
1172
|
const { locale } = useLocale();
|
|
1565
|
-
const location = useLocation();
|
|
1566
1173
|
const isExternalLink = checkIsExternalLink(href);
|
|
1567
1174
|
|
|
1175
|
+
// Nếu liên kết là nội bộ và một href hợp lệ được cung cấp, hãy lấy URL được bản địa hóa.
|
|
1568
1176
|
const hrefI18n =
|
|
1569
1177
|
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1570
1178
|
|
|
1571
|
-
const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
|
|
1572
|
-
if (typeof onClick === "function") onClick(event);
|
|
1573
|
-
|
|
1574
|
-
if (
|
|
1575
|
-
!isExternalLink &&
|
|
1576
|
-
href &&
|
|
1577
|
-
event.button === 0 &&
|
|
1578
|
-
!event.metaKey &&
|
|
1579
|
-
!event.ctrlKey &&
|
|
1580
|
-
!event.shiftKey &&
|
|
1581
|
-
!event.altKey &&
|
|
1582
|
-
!props.target
|
|
1583
|
-
) {
|
|
1584
|
-
event.preventDefault();
|
|
1585
|
-
if (location.url !== hrefI18n) {
|
|
1586
|
-
route(hrefI18n, replace);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
};
|
|
1590
|
-
|
|
1591
1179
|
return (
|
|
1592
|
-
<a href={hrefI18n} ref={ref}
|
|
1180
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1593
1181
|
{children}
|
|
1594
1182
|
</a>
|
|
1595
1183
|
);
|
|
1596
1184
|
}
|
|
1597
1185
|
);
|
|
1186
|
+
|
|
1187
|
+
Link.displayName = "Link";
|
|
1598
1188
|
```
|
|
1599
1189
|
|
|
1600
|
-
```jsx fileName="src/components/
|
|
1190
|
+
```jsx fileName="src/components/Link.jsx" codeFormat="esm"
|
|
1601
1191
|
import { getLocalizedUrl } from "intlayer";
|
|
1602
1192
|
import { useLocale } from "preact-intlayer";
|
|
1603
|
-
import { useLocation, route } from "preact-iso"; // Impor dari preact-iso
|
|
1604
1193
|
import { forwardRef } from "preact/compat";
|
|
1605
|
-
import { h } from "preact"; // Untuk JSX
|
|
1606
1194
|
|
|
1195
|
+
/**
|
|
1196
|
+
* Hàm tiện ích để kiểm tra xem một URL nhất định có phải là bên ngoài hay không.
|
|
1197
|
+
* Nếu URL bắt đầu bằng http:// hoặc https://, nó được coi là bên ngoài.
|
|
1198
|
+
*/
|
|
1607
1199
|
export const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1608
1200
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1201
|
+
/**
|
|
1202
|
+
* Một thành phần Link tùy chỉnh thích ứng với thuộc tính href dựa trên ngôn ngữ hiện tại.
|
|
1203
|
+
* Đối với các liên kết nội bộ, it sử dụng `getLocalizedUrl` để thêm tiền tố ngôn ngữ vào URL (ví dụ: /fr/about).
|
|
1204
|
+
* Điều này đảm bảo rằng điều hướng vẫn nằm trong cùng một bối cảnh ngôn ngữ.
|
|
1205
|
+
*/
|
|
1206
|
+
export const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1207
|
+
const { locale } = useLocale();
|
|
1208
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1614
1209
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1210
|
+
// Nếu liên kết là nội bộ và một href hợp lệ được cung cấp, hãy lấy URL được bản địa hóa.
|
|
1211
|
+
const hrefI18n =
|
|
1212
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1617
1213
|
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
href &&
|
|
1625
|
-
event.button === 0 &&
|
|
1626
|
-
!event.metaKey &&
|
|
1627
|
-
!event.ctrlKey &&
|
|
1628
|
-
!event.shiftKey &&
|
|
1629
|
-
!event.altKey &&
|
|
1630
|
-
!props.target
|
|
1631
|
-
) {
|
|
1632
|
-
event.preventDefault();
|
|
1633
|
-
if (location.url !== hrefI18n) {
|
|
1634
|
-
route(hrefI18n, replace);
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
};
|
|
1214
|
+
return (
|
|
1215
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1216
|
+
{children}
|
|
1217
|
+
</a>
|
|
1218
|
+
);
|
|
1219
|
+
});
|
|
1638
1220
|
|
|
1639
|
-
|
|
1640
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1641
|
-
{children}
|
|
1642
|
-
</a>
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
);
|
|
1221
|
+
Link.displayName = "Link";
|
|
1646
1222
|
```
|
|
1647
1223
|
|
|
1648
|
-
```jsx fileName="src/components/
|
|
1224
|
+
```jsx fileName="src/components/Link.cjsx" codeFormat="commonjs"
|
|
1649
1225
|
const { getLocalizedUrl } = require("intlayer");
|
|
1650
1226
|
const { useLocale } = require("preact-intlayer");
|
|
1651
|
-
const { useLocation, route } = require("preact-iso"); // Impor dari preact-iso
|
|
1652
1227
|
const { forwardRef } = require("preact/compat");
|
|
1653
|
-
const { h } = require("preact"); // Untuk JSX
|
|
1654
1228
|
|
|
1229
|
+
/**
|
|
1230
|
+
* Hàm tiện ích để kiểm tra xem một URL nhất định có phải là bên ngoài hay không.
|
|
1231
|
+
* Nếu URL bắt đầu bằng http:// hoặc https://, nó được coi là bên ngoài.
|
|
1232
|
+
*/
|
|
1655
1233
|
const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1656
1234
|
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1235
|
+
/**
|
|
1236
|
+
* Một thành phần Link tùy chỉnh thích ứng với thuộc tính href dựa trên ngôn ngữ hiện tại.
|
|
1237
|
+
* Đối với các liên kết nội bộ, nó sử dụng `getLocalizedUrl` để thêm tiền tố ngôn ngữ vào URL (ví dụ: /fr/about).
|
|
1238
|
+
* Điều này đảm bảo rằng điều hướng vẫn nằm trong cùng một bối cảnh ngôn ngữ.
|
|
1239
|
+
*/
|
|
1240
|
+
const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1241
|
+
const { locale } = useLocale();
|
|
1242
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1243
|
+
|
|
1244
|
+
// Nếu liên kết là nội bộ và một href hợp lệ được cung cấp, hãy lấy URL được bản địa hóa.
|
|
1245
|
+
const hrefI18n =
|
|
1246
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1247
|
+
|
|
1248
|
+
return h(
|
|
1249
|
+
"a",
|
|
1250
|
+
{
|
|
1251
|
+
href: hrefI18n,
|
|
1252
|
+
ref: ref,
|
|
1253
|
+
...props,
|
|
1254
|
+
},
|
|
1255
|
+
children
|
|
1256
|
+
);
|
|
1257
|
+
});
|
|
1665
1258
|
|
|
1666
|
-
|
|
1667
|
-
if (onClick) {
|
|
1668
|
-
onClick(event);
|
|
1669
|
-
}
|
|
1670
|
-
if (
|
|
1671
|
-
!isExternalLink &&
|
|
1672
|
-
href &&
|
|
1673
|
-
event.button === 0 &&
|
|
1674
|
-
!event.metaKey &&
|
|
1675
|
-
!event.ctrlKey &&
|
|
1676
|
-
!event.shiftKey &&
|
|
1677
|
-
!event.altKey &&
|
|
1678
|
-
!props.target
|
|
1679
|
-
) {
|
|
1680
|
-
event.preventDefault();
|
|
1681
|
-
if (location.url !== hrefI18n) {
|
|
1682
|
-
route(hrefI18n, replace);
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
};
|
|
1259
|
+
Link.displayName = "Link";
|
|
1686
1260
|
|
|
1687
|
-
|
|
1688
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1689
|
-
{children}
|
|
1690
|
-
</a>
|
|
1691
|
-
);
|
|
1692
|
-
}
|
|
1693
|
-
);
|
|
1694
|
-
|
|
1695
|
-
module.exports = { LocalizedLink, checkIsExternalLink };
|
|
1261
|
+
module.exports = { Link, checkIsExternalLink };
|
|
1696
1262
|
```
|
|
1697
1263
|
|
|
1698
1264
|
#### Cara Kerjanya
|
|
1699
1265
|
|
|
1700
1266
|
- **Mendeteksi Tautan Eksternal**:
|
|
1701
|
-
Fungsi pembantu `checkIsExternalLink` menentukan apakah sebuah URL adalah eksternal. Tautan eksternal dibiarkan tanpa perubahan.
|
|
1267
|
+
Fungsi pembantu `checkIsExternalLink` menentukan apakah sebuah URL adalah eksternal. Tautan eksternal dibiarkan tanpa perubahan karena tidak memerlukan lokalisasi.
|
|
1702
1268
|
- **Mengambil Locale Saat Ini**:
|
|
1703
|
-
Hook `useLocale` menyediakan locale saat ini.
|
|
1269
|
+
Hook `useLocale` menyediakan locale saat ini (misalnya, `fr` untuk bahasa Prancis).
|
|
1704
1270
|
- **Melokalkan URL**:
|
|
1705
|
-
Untuk tautan internal, `getLocalizedUrl` menambahkan prefix locale saat ini ke URL.
|
|
1706
|
-
- **Navigasi di Sisi Klien**:
|
|
1707
|
-
Fungsi `handleClick` memeriksa apakah itu tautan internal dan jika navigasi standar harus dicegah. Jika ya, fungsi `route` dari `preact-iso` (yang diperoleh melalui `useLocation` atau diimpor langsung) digunakan untuk melakukan navigasi sisi-klien. Ini memberikan perilaku seperti SPA tanpa memuat ulang halaman secara penuh.
|
|
1271
|
+
Untuk tautan internal (yaitu, non-eksternal), `getLocalizedUrl` digunakan untuk secara otomatis menambahkan prefix locale saat ini ke URL. Ini berarti jika pengguna Anda dalam bahasa Prancis, meneruskan `/about` sebagai `href` akan mengubahnya menjadi `/fr/about`.
|
|
1708
1272
|
- **Mengembalikan Tautan**:
|
|
1709
|
-
Komponen mengembalikan elemen `<a>` dengan URL yang sudah dilokalkan
|
|
1273
|
+
Komponen mengembalikan elemen `<a>` dengan URL yang sudah dilokalkan, memastikan navigasi konsisten dengan locale.
|
|
1274
|
+
|
|
1275
|
+
### (Opsional) Langkah 11: Render Markdown dan HTML
|
|
1276
|
+
|
|
1277
|
+
Intlayer mendukung rendering konten Markdown và HTML dalam Preact.
|
|
1278
|
+
|
|
1279
|
+
Bạn có thể tùy chỉnh việc hiển thị nội dung Markdown và HTML bằng cách sử dụng phương thức `.use()`. Phương thức này cho phép bạn ghi đè việc hiển thị mặc định của các thẻ cụ thể.
|
|
1280
|
+
|
|
1281
|
+
```tsx
|
|
1282
|
+
import { useIntlayer } from "preact-intlayer";
|
|
1283
|
+
|
|
1284
|
+
const { myMarkdownContent, myHtmlContent } = useIntlayer("my-component");
|
|
1285
|
+
|
|
1286
|
+
// ...
|
|
1287
|
+
|
|
1288
|
+
return (
|
|
1289
|
+
<div>
|
|
1290
|
+
{/* Rendering dasar */}
|
|
1291
|
+
{myMarkdownContent}
|
|
1292
|
+
|
|
1293
|
+
{/* Rendering kustom cho Markdown */}
|
|
1294
|
+
{myMarkdownContent.use({
|
|
1295
|
+
h1: (props) => <h1 style={{ color: "red" }} {...props} />,
|
|
1296
|
+
})}
|
|
1297
|
+
|
|
1298
|
+
{/* Rendering dasar cho HTML */}
|
|
1299
|
+
{myHtmlContent}
|
|
1300
|
+
|
|
1301
|
+
{/* Rendering kustom cho HTML */}
|
|
1302
|
+
{myHtmlContent.use({
|
|
1303
|
+
b: (props) => <strong style={{ color: "blue" }} {...props} />,
|
|
1304
|
+
})}
|
|
1305
|
+
</div>
|
|
1306
|
+
);
|
|
1307
|
+
```
|
|
1710
1308
|
|
|
1711
1309
|
### Konfigurasi TypeScript
|
|
1712
1310
|
|
|
1713
|
-
Intlayer menggunakan
|
|
1311
|
+
Intlayer menggunakan module augmentation để tận dụng lợi ích của TypeScript và làm cho codebase của bạn mạnh mẽ hơn.
|
|
1714
1312
|
|
|
1715
1313
|

|
|
1716
1314
|
|
|
@@ -1724,7 +1322,7 @@ Pastikan konfigurasi TypeScript Anda menyertakan tipe yang dihasilkan secara oto
|
|
|
1724
1322
|
"compilerOptions": {
|
|
1725
1323
|
// ...
|
|
1726
1324
|
"jsx": "react-jsx",
|
|
1727
|
-
"jsxImportSource": "preact", // Direkomendasikan
|
|
1325
|
+
"jsxImportSource": "preact", // Direkomendasikan cho Preact 10+
|
|
1728
1326
|
// ...
|
|
1729
1327
|
},
|
|
1730
1328
|
"include": [
|
|
@@ -1734,7 +1332,7 @@ Pastikan konfigurasi TypeScript Anda menyertakan tipe yang dihasilkan secara oto
|
|
|
1734
1332
|
}
|
|
1735
1333
|
```
|
|
1736
1334
|
|
|
1737
|
-
> Pastikan `tsconfig.json` Anda diatur
|
|
1335
|
+
> Pastikan `tsconfig.json` Anda diatur cho Preact, terutama `jsx` và `jsxImportSource` hoặc `jsxFactory`/`jsxFragmentFactory` cho các phiên bản Preact cũ hơn nếu không sử dụng mặc định của `preset-vite`.
|
|
1738
1336
|
|
|
1739
1337
|
### Konfigurasi Git
|
|
1740
1338
|
|
|
@@ -1755,15 +1353,17 @@ Untuk meningkatkan pengalaman pengembangan Anda dengan Intlayer, Anda dapat meng
|
|
|
1755
1353
|
|
|
1756
1354
|
Ekstensi ini menyediakan:
|
|
1757
1355
|
|
|
1758
|
-
- **Autocompletion**
|
|
1759
|
-
- **Deteksi kesalahan waktu nyata**
|
|
1356
|
+
- **Autocompletion** cho các khóa dịch.
|
|
1357
|
+
- **Deteksi kesalahan waktu nyata** cho các bản dịch còn thiếu.
|
|
1760
1358
|
- **Pratinjau inline** dari konten yang diterjemahkan.
|
|
1761
|
-
- **Tindakan cepat**
|
|
1359
|
+
- **Tindakan cepat** để dễ dàng tạo và cập nhật bản dịch.
|
|
1762
1360
|
|
|
1763
|
-
|
|
1361
|
+
Để biết thêm chi tiết về cách sử dụng tiện ích mở rộng, hãy tham khảo [tài liệu Tiện ích mở rộng Intlayer cho VS Code](https://intlayer.org/doc/vs-code-extension).
|
|
1764
1362
|
|
|
1765
1363
|
---
|
|
1766
1364
|
|
|
1767
1365
|
### Melangkah Lebih Jauh
|
|
1768
1366
|
|
|
1769
|
-
|
|
1367
|
+
Để đi xa hơn, bạn có thể triển khai [trình soạn thảo trực quan](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/intlayer_visual_editor.md) hoặc mengeksternalisasi konten Anda menggunakan [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/id/intlayer_CMS.md).
|
|
1368
|
+
|
|
1369
|
+
---
|