@intlayer/docs 8.0.0 → 8.0.1-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/generated/docs.entry.cjs +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
|
-
> Цей пакет знаходиться в розробці. Див. [issue](https://github.com/aymericzip/intlayer/issues/118) для детальнішої інформації. Підтримайте Intlayer для Preact, поставивши лайк цьому issue
|
|
52
|
-
|
|
53
51
|
## Зміст
|
|
54
52
|
|
|
55
53
|
<TOC/>
|
|
@@ -61,22 +59,14 @@ history:
|
|
|
61
59
|
За допомогою Intlayer ви можете:
|
|
62
60
|
|
|
63
61
|
- **Легко керувати перекладами** за допомогою декларативних словників на рівні компонентів.
|
|
64
|
-
- **Динамічно локалізувати
|
|
62
|
+
- **Динамічно локалізувати метадані, маршрути та вміст**.
|
|
65
63
|
- **Забезпечити підтримку TypeScript** через автогенеровані типи, що покращують автодоповнення та виявлення помилок.
|
|
66
|
-
-
|
|
64
|
+
- **Отримати переваги розширених можливостей**, таких як динамічне визначення локалі та її перемикання.
|
|
67
65
|
|
|
68
66
|
---
|
|
69
67
|
|
|
70
68
|
## Покроковий посібник із налаштування Intlayer у застосунку на Vite і 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="Демо CodeSandbox — Як інтернаціоналізувати ваш застосунок за допомогою Intlayer"
|
|
76
|
-
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
|
77
|
-
loading="lazy"
|
|
78
|
-
/>
|
|
79
|
-
|
|
80
70
|
Перегляньте [шаблон застосунку](https://github.com/aymericzip/intlayer-vite-preact-template) на GitHub.
|
|
81
71
|
|
|
82
72
|
### Крок 1: Встановіть залежності
|
|
@@ -109,12 +99,14 @@ bunx intlayer init
|
|
|
109
99
|
|
|
110
100
|
- **intlayer**
|
|
111
101
|
|
|
112
|
-
Основний пакет, що надає інструменти інтернаціоналізації для керування конфігурацією, перекладу, [декларації контенту](https://github.com/aymericzip/intlayer/blob/main/docs/docs/
|
|
102
|
+
Основний пакет, що надає інструменти інтернаціоналізації для керування конфігурацією, перекладу, [декларації контенту](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/dictionary/content_file.md), компіляції та [CLI-команд](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/cli/index.md).
|
|
113
103
|
|
|
114
104
|
- **preact-intlayer**
|
|
105
|
+
|
|
115
106
|
Пакет, який інтегрує Intlayer у Preact-застосунок. Надає провайдери контексту та хуки для інтернаціоналізації в Preact.
|
|
116
107
|
|
|
117
108
|
- **vite-intlayer**
|
|
109
|
+
|
|
118
110
|
Містить плагін для Vite для інтеграції Intlayer з [Vite bundler](https://vite.dev/guide/why.html#why-bundle-for-production), а також middleware для визначення пріоритетної локалі користувача, керування cookie та обробки перенаправлень URL.
|
|
119
111
|
|
|
120
112
|
### Крок 2: Налаштування вашого проєкту
|
|
@@ -242,13 +234,11 @@ const appContent = {
|
|
|
242
234
|
key: "app",
|
|
243
235
|
content: {
|
|
244
236
|
viteLogo: t({
|
|
245
|
-
uk: "Логотип Vite",
|
|
246
237
|
en: "Vite logo",
|
|
247
238
|
fr: "Logo Vite",
|
|
248
239
|
es: "Logo Vite",
|
|
249
240
|
}),
|
|
250
241
|
preactLogo: t({
|
|
251
|
-
uk: "Логотип Preact",
|
|
252
242
|
en: "Preact logo",
|
|
253
243
|
fr: "Logo Preact",
|
|
254
244
|
es: "Logo Preact",
|
|
@@ -257,18 +247,12 @@ const appContent = {
|
|
|
257
247
|
title: "Vite + Preact",
|
|
258
248
|
|
|
259
249
|
count: t({
|
|
260
|
-
uk: "лічильник: ",
|
|
261
250
|
en: "count is ",
|
|
262
251
|
fr: "le compte est ",
|
|
263
252
|
es: "el recuento es ",
|
|
264
253
|
}),
|
|
265
254
|
|
|
266
255
|
edit: t<ComponentChildren>({
|
|
267
|
-
uk: (
|
|
268
|
-
<>
|
|
269
|
-
Редагуйте <code>src/app.tsx</code> і збережіть, щоб перевірити HMR
|
|
270
|
-
</>
|
|
271
|
-
),
|
|
272
256
|
en: (
|
|
273
257
|
<>
|
|
274
258
|
Edit <code>src/app.tsx</code> and save to test HMR
|
|
@@ -287,10 +271,8 @@ const appContent = {
|
|
|
287
271
|
}),
|
|
288
272
|
|
|
289
273
|
readTheDocs: t({
|
|
290
|
-
uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
|
|
291
274
|
en: "Click on the Vite and Preact logos to learn more",
|
|
292
275
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
293
|
-
uk: "Клацніть на логотипи Vite та Preact, щоб дізнатися більше",
|
|
294
276
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
295
277
|
}),
|
|
296
278
|
},
|
|
@@ -308,13 +290,11 @@ const appContent = {
|
|
|
308
290
|
key: "app",
|
|
309
291
|
content: {
|
|
310
292
|
viteLogo: t({
|
|
311
|
-
uk: "Логотип Vite",
|
|
312
293
|
en: "Vite logo",
|
|
313
294
|
fr: "Logo Vite",
|
|
314
295
|
es: "Logo Vite",
|
|
315
296
|
}),
|
|
316
297
|
preactLogo: t({
|
|
317
|
-
uk: "Логотип Preact",
|
|
318
298
|
en: "Preact logo",
|
|
319
299
|
fr: "Logo Preact",
|
|
320
300
|
es: "Logo Preact",
|
|
@@ -323,27 +303,18 @@ const appContent = {
|
|
|
323
303
|
title: "Vite + Preact",
|
|
324
304
|
|
|
325
305
|
count: t({
|
|
326
|
-
uk: "лічильник ",
|
|
327
306
|
en: "count is ",
|
|
328
307
|
fr: "le compte est ",
|
|
329
308
|
es: "el recuento es ",
|
|
330
309
|
}),
|
|
331
310
|
|
|
332
311
|
edit: t({
|
|
333
|
-
uk: (
|
|
334
|
-
<>
|
|
335
|
-
Редагуйте <code>src/app.mjs</code> і збережіть, щоб перевірити HMR
|
|
336
|
-
</>
|
|
337
|
-
),
|
|
338
|
-
edit: t({
|
|
339
|
-
uk: "Редагуйте src/app.jsx і збережіть, щоб протестувати HMR",
|
|
340
312
|
en: "Edit src/app.jsx and save to test HMR",
|
|
341
313
|
fr: "Éditez src/app.jsx et enregistrez pour tester HMR",
|
|
342
314
|
es: "Edita src/app.jsx y guarda para probar HMR",
|
|
343
315
|
}),
|
|
344
316
|
|
|
345
317
|
readTheDocs: t({
|
|
346
|
-
uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
|
|
347
318
|
en: "Click on the Vite and Preact logos to learn more",
|
|
348
319
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
349
320
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
@@ -364,12 +335,10 @@ const appContent = {
|
|
|
364
335
|
content: {
|
|
365
336
|
viteLogo: t({
|
|
366
337
|
en: "Vite logo",
|
|
367
|
-
uk: "Логотип Vite",
|
|
368
338
|
fr: "Logo Vite",
|
|
369
339
|
es: "Logo Vite",
|
|
370
340
|
}),
|
|
371
341
|
preactLogo: t({
|
|
372
|
-
uk: "Логотип Preact",
|
|
373
342
|
en: "Preact logo",
|
|
374
343
|
fr: "Logo Preact",
|
|
375
344
|
es: "Logo Preact",
|
|
@@ -378,24 +347,21 @@ const appContent = {
|
|
|
378
347
|
title: "Vite + Preact",
|
|
379
348
|
|
|
380
349
|
count: t({
|
|
381
|
-
uk: "Кількість: ",
|
|
382
350
|
en: "count is ",
|
|
383
351
|
fr: "le compte est ",
|
|
384
352
|
es: "el recuento es ",
|
|
385
353
|
}),
|
|
386
354
|
|
|
387
355
|
edit: t({
|
|
388
|
-
uk: "Редагуйте src/app.tsx і збережіть, щоб протестувати HMR",
|
|
389
356
|
en: "Edit src/app.tsx and save to test HMR",
|
|
390
357
|
fr: "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
391
358
|
es: "Edita src/app.tsx y guarda para probar HMR",
|
|
392
359
|
}),
|
|
393
360
|
|
|
394
361
|
readTheDocs: t({
|
|
395
|
-
uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
|
|
396
362
|
en: "Click on the Vite and Preact logos to learn more",
|
|
397
363
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
398
|
-
es: "Haga clic en los logotipos de Vite
|
|
364
|
+
es: "Haga clic en los logotipos de Vite et Preact pour en savoir plus",
|
|
399
365
|
}),
|
|
400
366
|
},
|
|
401
367
|
};
|
|
@@ -411,7 +377,6 @@ module.exports = appContent;
|
|
|
411
377
|
"viteLogo": {
|
|
412
378
|
"nodeType": "translation",
|
|
413
379
|
"translation": {
|
|
414
|
-
"uk": "Логотип Vite",
|
|
415
380
|
"en": "Vite logo",
|
|
416
381
|
"fr": "Logo Vite",
|
|
417
382
|
"es": "Logo Vite"
|
|
@@ -420,7 +385,6 @@ module.exports = appContent;
|
|
|
420
385
|
"preactLogo": {
|
|
421
386
|
"nodeType": "translation",
|
|
422
387
|
"translation": {
|
|
423
|
-
"uk": "Логотип Preact",
|
|
424
388
|
"en": "Preact logo",
|
|
425
389
|
"fr": "Logo Preact",
|
|
426
390
|
"es": "Logo Preact"
|
|
@@ -429,7 +393,6 @@ module.exports = appContent;
|
|
|
429
393
|
"title": {
|
|
430
394
|
"nodeType": "translation",
|
|
431
395
|
"translation": {
|
|
432
|
-
"uk": "Vite + Preact",
|
|
433
396
|
"en": "Vite + Preact",
|
|
434
397
|
"fr": "Vite + Preact",
|
|
435
398
|
"es": "Vite + Preact"
|
|
@@ -438,9 +401,7 @@ module.exports = appContent;
|
|
|
438
401
|
"count": {
|
|
439
402
|
"nodeType": "translation",
|
|
440
403
|
"translation": {
|
|
441
|
-
"uk": "кількість ",
|
|
442
404
|
"en": "count is ",
|
|
443
|
-
"uk": "лічильник: ",
|
|
444
405
|
"fr": "le compte est ",
|
|
445
406
|
"es": "el recuento es "
|
|
446
407
|
}
|
|
@@ -448,7 +409,6 @@ module.exports = appContent;
|
|
|
448
409
|
"edit": {
|
|
449
410
|
"nodeType": "translation",
|
|
450
411
|
"translation": {
|
|
451
|
-
"uk": "Редагуйте src/app.tsx і збережіть, щоб перевірити HMR",
|
|
452
412
|
"en": "Edit src/app.tsx and save to test HMR",
|
|
453
413
|
"fr": "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
454
414
|
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
@@ -457,7 +417,6 @@ module.exports = appContent;
|
|
|
457
417
|
"readTheDocs": {
|
|
458
418
|
"nodeType": "translation",
|
|
459
419
|
"translation": {
|
|
460
|
-
"uk": "Натисніть на логотипи Vite та Preact, щоб дізнатися більше",
|
|
461
420
|
"en": "Click on the Vite and Preact logos to learn more",
|
|
462
421
|
"fr": "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
463
422
|
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
@@ -511,6 +470,12 @@ const AppContent: FunctionalComponent = () => {
|
|
|
511
470
|
</button>
|
|
512
471
|
<p>{content.edit}</p>
|
|
513
472
|
</div>
|
|
473
|
+
{/* Markdown контент */}
|
|
474
|
+
<div>{content.myMarkdownContent}</div>
|
|
475
|
+
|
|
476
|
+
{/* HTML контент */}
|
|
477
|
+
<div>{content.myHtmlContent}</div>
|
|
478
|
+
|
|
514
479
|
<p class="read-the-docs">{content.readTheDocs}</p>
|
|
515
480
|
</>
|
|
516
481
|
);
|
|
@@ -643,7 +608,7 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
643
608
|
|
|
644
609
|
return (
|
|
645
610
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
646
|
-
|
|
611
|
+
Change Language to English
|
|
647
612
|
</button>
|
|
648
613
|
);
|
|
649
614
|
};
|
|
@@ -660,7 +625,7 @@ const LocaleSwitcher = () => {
|
|
|
660
625
|
|
|
661
626
|
return (
|
|
662
627
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
663
|
-
|
|
628
|
+
Change Language to English
|
|
664
629
|
</button>
|
|
665
630
|
);
|
|
666
631
|
};
|
|
@@ -687,7 +652,7 @@ module.exports = LocaleSwitcher;
|
|
|
687
652
|
|
|
688
653
|
> Щоб дізнатися більше про хук `useLocale`, зверніться до [документації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/react-intlayer/useLocale.md) (API схоже для `preact-intlayer`).
|
|
689
654
|
|
|
690
|
-
### (Необов'язково) Крок 7: Додайте локалізовану маршрутизацію до вашого
|
|
655
|
+
### (Необов'язково) Крок 7: Додайте локалізовану маршрутизацію до вашого додатка
|
|
691
656
|
|
|
692
657
|
Мета цього кроку — створити унікальні маршрути для кожної мови. Це корисно для SEO та SEO-дружніх URL-адрес.
|
|
693
658
|
Приклад:
|
|
@@ -698,269 +663,45 @@ module.exports = LocaleSwitcher;
|
|
|
698
663
|
- https://example.com/fr/about
|
|
699
664
|
```
|
|
700
665
|
|
|
701
|
-
> За замовчуванням маршрути не мають префікса для мови за
|
|
702
|
-
|
|
703
|
-
Щоб додати локалізовану маршрутизацію до вашого застосунку, ви можете створити компонент `LocaleRouter`, який обгортає маршрути вашого застосунку та обробляє маршрутизацію на основі локалі. Ось приклад із використанням [preact-iso](https://github.com/preactjs/preact-iso):
|
|
704
|
-
|
|
705
|
-
Спочатку встановіть `preact-iso`:
|
|
706
|
-
|
|
707
|
-
```bash packageManager="npm"
|
|
708
|
-
npm install preact-iso
|
|
709
|
-
npx intlayer init
|
|
710
|
-
```
|
|
711
|
-
|
|
712
|
-
```bash packageManager="pnpm"
|
|
713
|
-
pnpm add preact-iso
|
|
714
|
-
pnpm intlayer init
|
|
715
|
-
```
|
|
666
|
+
> За замовчуванням маршрути не мають префікса для мови за замовчуванням. Якщо ви хочете додати префікс і для мови за замовчуванням, ви можете встановити опцію `routing.mode` в `"prefix-all"` у вашій конфігурації. Див. [документацію з конфігурації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/configuration.md) для додаткової інформації.
|
|
716
667
|
|
|
717
|
-
|
|
718
|
-
yarn add preact-iso
|
|
719
|
-
```
|
|
668
|
+
Щоб додати локалізовану маршрутизацію до вашого додатка, ви можете створити компонент `LocaleRouter`, який обгортає маршрути вашого додатка та обробляє маршрутизацію на основі локалі. Ось приклад із використанням [preact-iso](https://github.com/preactjs/preact-iso):
|
|
720
669
|
|
|
721
670
|
```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
|
|
722
|
-
import {
|
|
723
|
-
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
724
|
-
import { useEffect } from "preact/hooks";
|
|
671
|
+
import { localeMap } from "intlayer";
|
|
725
672
|
import { IntlayerProvider } from "preact-intlayer";
|
|
726
|
-
import { LocationProvider,
|
|
727
|
-
|
|
728
|
-
const { internationalization, routing } = configuration;
|
|
729
|
-
const { locales, defaultLocale } = internationalization;
|
|
730
|
-
|
|
731
|
-
const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({
|
|
732
|
-
to,
|
|
733
|
-
replace,
|
|
734
|
-
}) => {
|
|
735
|
-
const { route } = useLocation();
|
|
736
|
-
useEffect(() => {
|
|
737
|
-
route(to, replace);
|
|
738
|
-
}, [to, replace, route]);
|
|
739
|
-
return null;
|
|
740
|
-
};
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Компонент, який обробляє локалізацію і обгортає дочірні елементи у відповідний контекст локалі.
|
|
744
|
-
* Він керує визначенням локалі на основі URL та її валідацією.
|
|
745
|
-
*/
|
|
746
|
-
const AppLocalized: FunctionalComponent<{
|
|
747
|
-
children: ComponentChildren;
|
|
748
|
-
locale?: Locale;
|
|
749
|
-
}> = ({ children, locale }) => {
|
|
750
|
-
const { path: pathname, url } = useLocation();
|
|
751
|
-
|
|
752
|
-
if (!url) {
|
|
753
|
-
return null;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
const search = url.substring(pathname.length);
|
|
757
|
-
|
|
758
|
-
// Визначає поточну локаль — використовується передана locale або локаль за замовчуванням
|
|
759
|
-
const currentLocale = locale ?? defaultLocale;
|
|
760
|
-
|
|
761
|
-
// Видаляє префікс локалі з шляху для побудови базового шляху
|
|
762
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
763
|
-
pathname // Поточний шлях URL
|
|
764
|
-
);
|
|
765
|
-
|
|
766
|
-
/**
|
|
767
|
-
* Якщо routing.mode === 'prefix-all', локаль за замовчуванням повинна завжди мати префікс.
|
|
768
|
-
*/
|
|
769
|
-
if (routing.mode === "prefix-all") {
|
|
770
|
-
// Перевірити локаль
|
|
771
|
-
if (!locale || !locales.includes(locale)) {
|
|
772
|
-
// Перенаправити на локаль за замовчуванням з оновленим шляхом
|
|
773
|
-
return (
|
|
774
|
-
<Navigate
|
|
775
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
776
|
-
replace // Замінити поточний запис історії новим
|
|
777
|
-
/>
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
// Огорнути children через IntlayerProvider і встановити поточну локаль
|
|
782
|
-
return (
|
|
783
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
784
|
-
);
|
|
785
|
-
} else {
|
|
786
|
-
/**
|
|
787
|
-
* Коли routing.mode не дорівнює 'prefix-all', локаль за замовчуванням не має префікса.
|
|
788
|
-
* Переконатися, що поточна локаль дійсна і не є локаллю за замовчуванням.
|
|
789
|
-
*/
|
|
790
|
-
if (
|
|
791
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
792
|
-
!locales
|
|
793
|
-
.filter(
|
|
794
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Виключити локаль за замовчуванням
|
|
795
|
-
)
|
|
796
|
-
.includes(currentLocale) // Перевірити, чи поточна локаль є в списку дійсних локалей
|
|
797
|
-
) {
|
|
798
|
-
// Перенаправити на шлях без префікса локалі
|
|
799
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// Обгорнути children у IntlayerProvider і встановити поточну локаль
|
|
803
|
-
return (
|
|
804
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
805
|
-
);
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
|
|
809
|
-
const RouterContent: FunctionalComponent<{
|
|
810
|
-
children: ComponentChildren;
|
|
811
|
-
}> = ({ children }) => {
|
|
812
|
-
const { path } = useLocation();
|
|
813
|
-
|
|
814
|
-
if (!path) {
|
|
815
|
-
return null;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
const pathLocale = path.split("/")[1] as Locale;
|
|
819
|
-
|
|
820
|
-
const isLocaleRoute = locales
|
|
821
|
-
.filter(
|
|
822
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
823
|
-
)
|
|
824
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
825
|
-
|
|
826
|
-
if (isLocaleRoute) {
|
|
827
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
return (
|
|
831
|
-
<AppLocalized
|
|
832
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
833
|
-
>
|
|
834
|
-
{children}
|
|
835
|
-
</AppLocalized>
|
|
836
|
-
);
|
|
837
|
-
};
|
|
673
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
674
|
+
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
838
675
|
|
|
839
676
|
/**
|
|
840
|
-
* Компонент роутера,
|
|
677
|
+
* Компонент роутера, що налаштовує маршрути з урахуванням локалі.
|
|
841
678
|
* Використовує preact-iso для керування навігацією та рендерингу локалізованих компонентів.
|
|
842
679
|
*/
|
|
843
680
|
export const LocaleRouter: FunctionalComponent<{
|
|
844
681
|
children: ComponentChildren;
|
|
845
682
|
}> = ({ children }) => (
|
|
846
683
|
<LocationProvider>
|
|
847
|
-
<
|
|
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>
|
|
848
697
|
</LocationProvider>
|
|
849
698
|
);
|
|
850
699
|
```
|
|
851
700
|
|
|
852
701
|
```jsx fileName="src/components/LocaleRouter.jsx" codeFormat="esm"
|
|
853
|
-
|
|
854
|
-
import { configuration, getPathWithoutLocale } from "intlayer";
|
|
702
|
+
import { localeMap } from "intlayer";
|
|
855
703
|
import { IntlayerProvider } from "preact-intlayer";
|
|
856
|
-
import { LocationProvider,
|
|
857
|
-
import { useEffect } from "preact/hooks";
|
|
858
|
-
import { h } from "preact"; // Потрібно для JSX
|
|
859
|
-
|
|
860
|
-
// Деструктуризація конфігурації з Intlayer
|
|
861
|
-
const { internationalization, routing } = configuration;
|
|
862
|
-
const { locales, defaultLocale } = internationalization;
|
|
863
|
-
|
|
864
|
-
const Navigate = ({ to, replace }) => {
|
|
865
|
-
const { route } = useLocation();
|
|
866
|
-
useEffect(() => {
|
|
867
|
-
route(to, replace);
|
|
868
|
-
}, [to, replace, route]);
|
|
869
|
-
return null;
|
|
870
|
-
};
|
|
871
|
-
|
|
872
|
-
/**
|
|
873
|
-
/**
|
|
874
|
-
* Компонент, що обробляє локалізацію та обгортає children відповідним контекстом локалі.
|
|
875
|
-
* Він керує визначенням локалі на основі URL та перевіркою коректності локалі.
|
|
876
|
-
*/
|
|
877
|
-
const AppLocalized = ({ children, locale }) => {
|
|
878
|
-
const { path: pathname, url } = useLocation();
|
|
879
|
-
|
|
880
|
-
if (!url) {
|
|
881
|
-
return null;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
const search = url.substring(pathname.length);
|
|
885
|
-
|
|
886
|
-
// Визначає поточну локаль, за замовчуванням використовується defaultLocale, якщо не передано
|
|
887
|
-
const currentLocale = locale ?? defaultLocale;
|
|
888
|
-
|
|
889
|
-
// Видаляє префікс локалі з шляху для побудови базового шляху
|
|
890
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
891
|
-
pathname // Поточний шлях URL
|
|
892
|
-
);
|
|
893
|
-
|
|
894
|
-
/**
|
|
895
|
-
* Якщо routing.mode === "prefix-all", локаль за замовчуванням завжди має бути з префіксом.
|
|
896
|
-
*/
|
|
897
|
-
if (routing.mode === "prefix-all") {
|
|
898
|
-
// Перевіряє локаль
|
|
899
|
-
if (!locale || !locales.includes(locale)) {
|
|
900
|
-
// Перенаправлення до мови за замовчуванням з оновленим шляхом
|
|
901
|
-
return (
|
|
902
|
-
<Navigate
|
|
903
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
904
|
-
replace // Замінити поточний запис історії на новий
|
|
905
|
-
/>
|
|
906
|
-
);
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
// Обгорнути дочірні елементи IntlayerProvider та встановити поточну локаль
|
|
910
|
-
return (
|
|
911
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
912
|
-
);
|
|
913
|
-
} else {
|
|
914
|
-
/**
|
|
915
|
-
* Коли routing.mode не 'prefix-all', префікс мови за замовчуванням не додається.
|
|
916
|
-
* Переконайтесь, що поточна локаль дійсна і не є локаллю за замовчуванням.
|
|
917
|
-
*/
|
|
918
|
-
if (
|
|
919
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
920
|
-
!locales
|
|
921
|
-
.filter(
|
|
922
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Не включати мову за замовчуванням
|
|
923
|
-
)
|
|
924
|
-
.includes(currentLocale) // Перевіряє, чи поточна локаль є в списку дійсних локалей
|
|
925
|
-
) {
|
|
926
|
-
// Перенаправити на шлях без префікса локалі
|
|
927
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// Обгорнути children у IntlayerProvider та встановити поточну локаль
|
|
931
|
-
return (
|
|
932
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
};
|
|
936
|
-
|
|
937
|
-
const RouterContent = ({ children }) => {
|
|
938
|
-
const { path } = useLocation();
|
|
939
|
-
|
|
940
|
-
if (!path) {
|
|
941
|
-
return null;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
const pathLocale = path.split("/")[1];
|
|
945
|
-
|
|
946
|
-
const isLocaleRoute = locales
|
|
947
|
-
.filter(
|
|
948
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
949
|
-
)
|
|
950
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
951
|
-
|
|
952
|
-
if (isLocaleRoute) {
|
|
953
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
return (
|
|
957
|
-
<AppLocalized
|
|
958
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
959
|
-
>
|
|
960
|
-
{children}
|
|
961
|
-
</AppLocalized>
|
|
962
|
-
);
|
|
963
|
-
};
|
|
704
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
964
705
|
|
|
965
706
|
/**
|
|
966
707
|
* Компонент роутера, що налаштовує маршрути з урахуванням локалі.
|
|
@@ -968,142 +709,61 @@ const RouterContent = ({ children }) => {
|
|
|
968
709
|
*/
|
|
969
710
|
export const LocaleRouter = ({ children }) => (
|
|
970
711
|
<LocationProvider>
|
|
971
|
-
<
|
|
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>
|
|
972
725
|
</LocationProvider>
|
|
973
726
|
);
|
|
974
727
|
```
|
|
975
728
|
|
|
976
729
|
```jsx fileName="src/components/LocaleRouter.cjsx" codeFormat="commonjs"
|
|
977
|
-
|
|
978
|
-
const { configuration, getPathWithoutLocale } = require("intlayer");
|
|
730
|
+
const { localeMap } = require("intlayer");
|
|
979
731
|
const { IntlayerProvider } = require("preact-intlayer");
|
|
980
|
-
const { LocationProvider,
|
|
981
|
-
const { useEffect } = require("preact/hooks");
|
|
982
|
-
const { h } = require("preact"); // Потрібно для JSX
|
|
983
|
-
|
|
984
|
-
// Деструктуризація конфігурації з Intlayer
|
|
985
|
-
const { internationalization, routing } = configuration;
|
|
986
|
-
const { locales, defaultLocale } = internationalization;
|
|
987
|
-
|
|
988
|
-
const Navigate = ({ to, replace }) => {
|
|
989
|
-
const { route } = useLocation();
|
|
990
|
-
useEffect(() => {
|
|
991
|
-
route(to, replace);
|
|
992
|
-
}, [to, replace, route]);
|
|
993
|
-
return null;
|
|
994
|
-
};
|
|
732
|
+
const { LocationProvider, Router, Route } = require("preact-iso");
|
|
995
733
|
|
|
996
734
|
/**
|
|
997
|
-
*
|
|
998
|
-
*
|
|
735
|
+
* Компонент роутера, що налаштовує маршрути з урахуванням локалі.
|
|
736
|
+
* Використовує preact-iso для керування навігацією та рендерингу локалізованих компонентів.
|
|
999
737
|
*/
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
);
|
|
1016
|
-
|
|
1017
|
-
/**
|
|
1018
|
-
* Якщо routing.mode === 'prefix-all', локаль за замовчуванням завжди повинна мати префікс.
|
|
1019
|
-
*/
|
|
1020
|
-
if (routing.mode === "prefix-all") {
|
|
1021
|
-
// Перевіряємо локаль
|
|
1022
|
-
if (!locale || !locales.includes(locale)) {
|
|
1023
|
-
// Перенаправляємо на локаль за замовчуванням з оновленим шляхом
|
|
1024
|
-
return (
|
|
1025
|
-
<Navigate
|
|
1026
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
1027
|
-
replace // Замінити поточний запис у історії на новий
|
|
1028
|
-
/>
|
|
1029
|
-
);
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
// Обгорнути children у IntlayerProvider і встановити поточну локаль
|
|
1033
|
-
return (
|
|
1034
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1035
|
-
);
|
|
1036
|
-
} else {
|
|
1037
|
-
/**
|
|
1038
|
-
* Коли routing.mode не 'prefix-all', префікс для локалі за замовчуванням не додається.
|
|
1039
|
-
* Переконайтесь, що поточна локаль дійсна і не є локаллю за замовчуванням.
|
|
1040
|
-
*/
|
|
1041
|
-
if (
|
|
1042
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
1043
|
-
!locales
|
|
1044
|
-
.filter(
|
|
1045
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Виключити локаль за замовчуванням
|
|
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
|
+
})
|
|
1046
753
|
)
|
|
1047
|
-
.includes(currentLocale) // Перевірити, чи поточна локаль є в списку дійсних локалей
|
|
1048
|
-
) {
|
|
1049
|
-
// Перенаправлення на шлях без префіксу локалі
|
|
1050
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
// Обгорнути дочірні елементи в IntlayerProvider і встановити поточну локаль
|
|
1054
|
-
return (
|
|
1055
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1056
|
-
);
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
|
-
|
|
1060
|
-
const RouterContent = ({ children }) => {
|
|
1061
|
-
const { path } = useLocation();
|
|
1062
|
-
|
|
1063
|
-
if (!path) {
|
|
1064
|
-
return null;
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
const pathLocale = path.split("/")[1];
|
|
1068
|
-
|
|
1069
|
-
const isLocaleRoute = locales
|
|
1070
|
-
.filter(
|
|
1071
|
-
(locale) => routing.mode === "prefix-all" || locale !== defaultLocale
|
|
1072
754
|
)
|
|
1073
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
1074
|
-
|
|
1075
|
-
if (isLocaleRoute) {
|
|
1076
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
return (
|
|
1080
|
-
<AppLocalized
|
|
1081
|
-
locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
|
|
1082
|
-
>
|
|
1083
|
-
{children}
|
|
1084
|
-
</AppLocalized>
|
|
1085
755
|
);
|
|
1086
|
-
};
|
|
1087
|
-
|
|
1088
|
-
/**
|
|
1089
|
-
* Компонент роутера, який налаштовує маршрути для конкретних локалей.
|
|
1090
|
-
* Він використовує preact-iso для керування навігацією та відображення локалізованих компонентів.
|
|
1091
|
-
*/
|
|
1092
|
-
const LocaleRouter = ({ children }) => (
|
|
1093
|
-
<LocationProvider>
|
|
1094
|
-
<RouterContent>{children}</RouterContent>
|
|
1095
|
-
</LocationProvider>
|
|
1096
|
-
);
|
|
1097
756
|
|
|
1098
757
|
module.exports = { LocaleRouter };
|
|
1099
758
|
```
|
|
1100
759
|
|
|
1101
|
-
Потім ви можете використовувати компонент `LocaleRouter` у вашому
|
|
760
|
+
Потім ви можете використовувати компонент `LocaleRouter` у вашому додатку:
|
|
1102
761
|
|
|
1103
762
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1104
763
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1105
764
|
import type { FunctionalComponent } from "preact";
|
|
1106
|
-
|
|
765
|
+
|
|
766
|
+
// ... Ваш компонент AppContent
|
|
1107
767
|
|
|
1108
768
|
const App: FunctionalComponent = () => (
|
|
1109
769
|
<LocaleRouter>
|
|
@@ -1116,7 +776,8 @@ export default App;
|
|
|
1116
776
|
|
|
1117
777
|
```jsx fileName="src/app.jsx" codeFormat="esm"
|
|
1118
778
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1119
|
-
|
|
779
|
+
|
|
780
|
+
// ... Ваш компонент AppContent
|
|
1120
781
|
|
|
1121
782
|
const App = () => (
|
|
1122
783
|
<LocaleRouter>
|
|
@@ -1129,7 +790,8 @@ export default App;
|
|
|
1129
790
|
|
|
1130
791
|
```jsx fileName="src/app.cjsx" codeFormat="commonjs"
|
|
1131
792
|
const { LocaleRouter } = require("./components/LocaleRouter");
|
|
1132
|
-
|
|
793
|
+
|
|
794
|
+
// ... Ваш компонент AppContent
|
|
1133
795
|
|
|
1134
796
|
const App = () => (
|
|
1135
797
|
<LocaleRouter>
|
|
@@ -1140,49 +802,12 @@ const App = () => (
|
|
|
1140
802
|
module.exports = App;
|
|
1141
803
|
```
|
|
1142
804
|
|
|
1143
|
-
|
|
805
|
+
### (Необов'язково) Крок 8: Змінюйте URL при зміні локалі
|
|
1144
806
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
|
|
1148
|
-
import { defineConfig } from "vite";
|
|
1149
|
-
import preact from "@preact/preset-vite";
|
|
1150
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1151
|
-
|
|
1152
|
-
// https://vitejs.dev/config/ (див. документацію Vite)
|
|
1153
|
-
export default defineConfig({
|
|
1154
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1155
|
-
});
|
|
1156
|
-
```
|
|
1157
|
-
|
|
1158
|
-
```javascript {3,7} fileName="vite.config.mjs" codeFormat="esm"
|
|
1159
|
-
import { defineConfig } from "vite";
|
|
1160
|
-
import preact from "@preact/preset-vite";
|
|
1161
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1162
|
-
|
|
1163
|
-
// Документація: https://vitejs.dev/config/
|
|
1164
|
-
export default defineConfig({
|
|
1165
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1166
|
-
});
|
|
1167
|
-
```
|
|
1168
|
-
|
|
1169
|
-
```javascript {3,7} fileName="vite.config.cjs" codeFormat="commonjs"
|
|
1170
|
-
const { defineConfig } = require("vite");
|
|
1171
|
-
const preact = require("@preact/preset-vite");
|
|
1172
|
-
const { intlayer, intlayerProxy } = require("vite-intlayer");
|
|
1173
|
-
|
|
1174
|
-
// Документація: https://vitejs.dev/config/
|
|
1175
|
-
module.exports = defineConfig({
|
|
1176
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1177
|
-
});
|
|
1178
|
-
```
|
|
1179
|
-
|
|
1180
|
-
### (Необов'язково) Крок 8: Змінити URL при зміні локалі
|
|
1181
|
-
|
|
1182
|
-
Щоб змінювати URL при зміні локалі, ви можете використовувати пропс `onLocaleChange`, який надає хук `useLocale`. Паралельно можна використовувати `useLocation` та `route` з `preact-iso` для оновлення шляху URL.
|
|
807
|
+
Щоб змінювати URL при зміні локалі, ви можете використовувати пропс `onLocaleChange`, який надає хук `useLocale`. Паралельно можна використовувати метод `route` з `useLocation` бібліотеки `preact-iso` для оновлення шляху URL.
|
|
1183
808
|
|
|
1184
809
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
1185
|
-
import { useLocation
|
|
810
|
+
import { useLocation } from "preact-iso";
|
|
1186
811
|
import {
|
|
1187
812
|
Locales,
|
|
1188
813
|
getHTMLTextDir,
|
|
@@ -1193,16 +818,15 @@ import { useLocale } from "preact-intlayer";
|
|
|
1193
818
|
import type { FunctionalComponent } from "preact";
|
|
1194
819
|
|
|
1195
820
|
const LocaleSwitcher: FunctionalComponent = () => {
|
|
1196
|
-
const
|
|
821
|
+
const { url, route } = useLocation();
|
|
1197
822
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1198
823
|
onLocaleChange: (newLocale) => {
|
|
1199
|
-
const currentFullPath = location.url; // preact-iso надає повний URL
|
|
1200
824
|
// Сформувати URL з оновленою локаллю
|
|
1201
825
|
// Приклад: /es/about?foo=bar
|
|
1202
|
-
const pathWithLocale = getLocalizedUrl(
|
|
826
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1203
827
|
|
|
1204
828
|
// Оновити шлях URL
|
|
1205
|
-
route(pathWithLocale, true); // true для заміни
|
|
829
|
+
route(pathWithLocale, true); // true для заміни (replace)
|
|
1206
830
|
},
|
|
1207
831
|
});
|
|
1208
832
|
|
|
@@ -1212,7 +836,7 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
1212
836
|
<div id="localePopover" popover="auto">
|
|
1213
837
|
{availableLocales.map((localeItem) => (
|
|
1214
838
|
<a
|
|
1215
|
-
href={getLocalizedUrl(
|
|
839
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1216
840
|
hreflang={localeItem}
|
|
1217
841
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1218
842
|
onClick={(e) => {
|
|
@@ -1249,7 +873,7 @@ export default LocaleSwitcher;
|
|
|
1249
873
|
```
|
|
1250
874
|
|
|
1251
875
|
```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
|
|
1252
|
-
import { useLocation
|
|
876
|
+
import { useLocation } from "preact-iso";
|
|
1253
877
|
import {
|
|
1254
878
|
Locales,
|
|
1255
879
|
getHTMLTextDir,
|
|
@@ -1257,14 +881,12 @@ import {
|
|
|
1257
881
|
getLocalizedUrl,
|
|
1258
882
|
} from "intlayer";
|
|
1259
883
|
import { useLocale } from "preact-intlayer";
|
|
1260
|
-
import { h } from "preact"; // Для JSX
|
|
1261
884
|
|
|
1262
885
|
const LocaleSwitcher = () => {
|
|
1263
|
-
const
|
|
886
|
+
const { url, route } = useLocation();
|
|
1264
887
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1265
888
|
onLocaleChange: (newLocale) => {
|
|
1266
|
-
const
|
|
1267
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
889
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1268
890
|
route(pathWithLocale, true);
|
|
1269
891
|
},
|
|
1270
892
|
});
|
|
@@ -1275,7 +897,7 @@ const LocaleSwitcher = () => {
|
|
|
1275
897
|
<div id="localePopover" popover="auto">
|
|
1276
898
|
{availableLocales.map((localeItem) => (
|
|
1277
899
|
<a
|
|
1278
|
-
href={getLocalizedUrl(
|
|
900
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1279
901
|
hreflang={localeItem}
|
|
1280
902
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1281
903
|
onClick={(e) => {
|
|
@@ -1303,7 +925,7 @@ export default LocaleSwitcher;
|
|
|
1303
925
|
```
|
|
1304
926
|
|
|
1305
927
|
```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
|
|
1306
|
-
const { useLocation
|
|
928
|
+
const { useLocation } = require("preact-iso");
|
|
1307
929
|
const {
|
|
1308
930
|
Locales,
|
|
1309
931
|
getHTMLTextDir,
|
|
@@ -1311,45 +933,51 @@ const {
|
|
|
1311
933
|
getLocalizedUrl,
|
|
1312
934
|
} = require("intlayer");
|
|
1313
935
|
const { useLocale } = require("preact-intlayer");
|
|
1314
|
-
const { h } = require("preact"); // Для JSX
|
|
1315
936
|
|
|
1316
937
|
const LocaleSwitcher = () => {
|
|
1317
|
-
const
|
|
938
|
+
const { url, route } = useLocation();
|
|
1318
939
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1319
940
|
onLocaleChange: (newLocale) => {
|
|
1320
|
-
const
|
|
1321
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
941
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1322
942
|
route(pathWithLocale, true);
|
|
1323
943
|
},
|
|
1324
944
|
});
|
|
1325
945
|
|
|
1326
|
-
return (
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
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) => {
|
|
1336
961
|
e.preventDefault();
|
|
1337
962
|
setLocale(localeItem);
|
|
1338
|
-
}
|
|
1339
|
-
key
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
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
|
+
)
|
|
1353
981
|
);
|
|
1354
982
|
};
|
|
1355
983
|
|
|
@@ -1358,13 +986,9 @@ module.exports = LocaleSwitcher;
|
|
|
1358
986
|
|
|
1359
987
|
> Посилання на документацію:
|
|
1360
988
|
>
|
|
1361
|
-
> > - [`useLocale`
|
|
989
|
+
> > - [Хук `useLocale`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/react-intlayer/useLocale.md) (API схоже для `preact-intlayer`)> - [Хук `getLocaleName`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getLocaleName.md)> - [Хук `getLocalizedUrl`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getLocalizedUrl.md)> - [Хук `getHTMLTextDir`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getHTMLTextDir.md)> - [Атрибут `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=uk)> - [Атрибут `lang`](https://developer.mozilla.org/uk/docs/Web/HTML/Global_attributes/lang)> - [Атрибут `dir`](https://developer.mozilla.org/uk/docs/Web/HTML/Global_attributes/dir)> - [Атрибут `aria-current`](https://developer.mozilla.org/uk/docs/Web/Accessibility/ARIA/Attributes/aria-current)> - [Popover API](https://developer.mozilla.org/uk/docs/Web/API/Popover_API)
|
|
1362
990
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
---
|
|
1366
|
-
|
|
1367
|
-
### (Необов'язково) Крок 9: Переключення атрибутів мови та напрямку в HTML
|
|
991
|
+
### (Необов'язково) Крок 9: Перемикайте атрибути мови та напрямку в HTML
|
|
1368
992
|
|
|
1369
993
|
Коли ваш додаток підтримує кілька мов, важливо оновлювати атрибути `lang` та `dir` тегу `<html>`, щоб вони відповідали поточній локалі. Це гарантує:
|
|
1370
994
|
|
|
@@ -1509,12 +1133,6 @@ const App = () => (
|
|
|
1509
1133
|
module.exports = App;
|
|
1510
1134
|
```
|
|
1511
1135
|
|
|
1512
|
-
Застосувавши ці зміни, ваш додаток буде:
|
|
1513
|
-
|
|
1514
|
-
- Забезпечувати, що атрибут **language** (`lang`) правильно відображає поточну локаль, що важливо для SEO та поведінки браузера.
|
|
1515
|
-
- Підлаштовувати **напрямок тексту** (`dir`) відповідно до локалі, покращуючи читабельність та зручність використання для мов із різними напрямками читання.
|
|
1516
|
-
- Забезпечити більш **доступний** досвід, оскільки засоби допомоги (assistive technologies) залежать від цих атрибутів для оптимальної роботи.
|
|
1517
|
-
|
|
1518
1136
|
### (Необов'язково) Крок 10: Створення локалізованого компонента `Link`
|
|
1519
1137
|
|
|
1520
1138
|
Щоб переконатися, що навігація вашого додатка дотримується поточної локалі, ви можете створити власний компонент `Link`. Цей компонент автоматично додає префікс мови до внутрішніх URL.
|
|
@@ -1525,18 +1143,16 @@ module.exports = App;
|
|
|
1525
1143
|
- **Consistency**: використовуючи локалізоване посилання по всьому додатку, ви гарантуєте, що навігація залишатиметься в поточній локалі, запобігаючи несподіваним перемиканням мови.
|
|
1526
1144
|
- **Підтримуваність**: Централізація логіки локалізації в одному компоненті спрощує керування URL-адресами.
|
|
1527
1145
|
|
|
1528
|
-
|
|
1146
|
+
Нижче наведено реалізацію локалізованого компонента `Link` у Preact:
|
|
1529
1147
|
|
|
1530
|
-
```tsx fileName="src/components/
|
|
1148
|
+
```tsx fileName="src/components/Link.tsx" codeFormat="typescript"
|
|
1531
1149
|
import { getLocalizedUrl } from "intlayer";
|
|
1532
|
-
import { useLocale
|
|
1533
|
-
|
|
1534
|
-
import type { JSX } from "preact";
|
|
1535
|
-
import { forwardRef } from "preact/compat"; // Для передачі ref
|
|
1150
|
+
import { useLocale } from "preact-intlayer";
|
|
1151
|
+
import { forwardRef } from "preact/compat";
|
|
1152
|
+
import type { JSX } from "preact";
|
|
1536
1153
|
|
|
1537
|
-
export interface
|
|
1154
|
+
export interface LinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
|
|
1538
1155
|
href: string;
|
|
1539
|
-
replace?: boolean; // Необов'язково: замінює стан історії
|
|
1540
1156
|
}
|
|
1541
1157
|
|
|
1542
1158
|
/**
|
|
@@ -1548,165 +1164,151 @@ export const checkIsExternalLink = (href?: string): boolean =>
|
|
|
1548
1164
|
|
|
1549
1165
|
/**
|
|
1550
1166
|
* Кастомний компонент Link, який адаптує атрибут href відповідно до поточної локалі.
|
|
1551
|
-
*/
|
|
1552
1167
|
* Для внутрішніх посилань використовується `getLocalizedUrl` для додавання префіксу локалі до URL (наприклад, /fr/about).
|
|
1553
1168
|
* Це гарантує, що навігація залишатиметься в межах контексту тієї самої локалі.
|
|
1554
|
-
* Використовується стандартний тег <a>, але може ініціювати навігацію на клієнті за допомогою `route` з preact-iso.
|
|
1555
1169
|
*/
|
|
1556
|
-
export const
|
|
1557
|
-
({ href, children,
|
|
1170
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
1171
|
+
({ href, children, ...props }, ref) => {
|
|
1558
1172
|
const { locale } = useLocale();
|
|
1559
|
-
const location = useLocation(); // з preact-iso
|
|
1560
1173
|
const isExternalLink = checkIsExternalLink(href);
|
|
1561
1174
|
|
|
1175
|
+
// Якщо посилання внутрішнє та надано валідний href, отримуємо локалізований URL.
|
|
1562
1176
|
const hrefI18n =
|
|
1563
1177
|
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1564
1178
|
|
|
1565
|
-
const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
|
|
1566
|
-
if (onClick) {
|
|
1567
|
-
onClick(event);
|
|
1568
|
-
}
|
|
1569
|
-
if (
|
|
1570
|
-
!isExternalLink &&
|
|
1571
|
-
href && // Переконайтесь, що href визначено
|
|
1572
|
-
event.button === 0 && // Лівий клік
|
|
1573
|
-
!event.metaKey &&
|
|
1574
|
-
!event.ctrlKey &&
|
|
1575
|
-
!event.shiftKey &&
|
|
1576
|
-
!event.altKey && // Перевірка стандартних модифікаторів
|
|
1577
|
-
!props.target // Не відкривати в новій вкладці/вікні
|
|
1578
|
-
) {
|
|
1579
|
-
event.preventDefault();
|
|
1580
|
-
if (location.url !== hrefI18n) {
|
|
1581
|
-
// Перехід лише якщо URL відрізняється
|
|
1582
|
-
route(hrefI18n, replace); // Використовуємо route з preact-iso
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
};
|
|
1586
|
-
|
|
1587
1179
|
return (
|
|
1588
|
-
<a href={hrefI18n} ref={ref}
|
|
1180
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1589
1181
|
{children}
|
|
1590
1182
|
</a>
|
|
1591
1183
|
);
|
|
1592
1184
|
}
|
|
1593
1185
|
);
|
|
1186
|
+
|
|
1187
|
+
Link.displayName = "Link";
|
|
1594
1188
|
```
|
|
1595
1189
|
|
|
1596
|
-
```jsx fileName="src/components/
|
|
1190
|
+
```jsx fileName="src/components/Link.jsx" codeFormat="esm"
|
|
1597
1191
|
import { getLocalizedUrl } from "intlayer";
|
|
1598
1192
|
import { useLocale } from "preact-intlayer";
|
|
1599
|
-
import { useLocation, route } from "preact-iso"; // Імпортуємо з preact-iso
|
|
1600
1193
|
import { forwardRef } from "preact/compat";
|
|
1601
|
-
import { h } from "preact"; // Для JSX
|
|
1602
1194
|
|
|
1195
|
+
/**
|
|
1196
|
+
* Утиліта для перевірки, чи є вказаний URL зовнішнім.
|
|
1197
|
+
* Якщо URL починається з http:// або https://, він вважається зовнішнім.
|
|
1198
|
+
*/
|
|
1603
1199
|
export const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1604
1200
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1201
|
+
/**
|
|
1202
|
+
* Кастомний компонент Link, який адаптує атрибут href відповідно до поточної локалі.
|
|
1203
|
+
* Для внутрішніх посилань використовується `getLocalizedUrl` для додавання префіксу локалі до URL (наприклад, /fr/about).
|
|
1204
|
+
* Це гарантує, що навігація залишатиметься в межах контексту тієї самої локалі.
|
|
1205
|
+
*/
|
|
1206
|
+
export const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1207
|
+
const { locale } = useLocale();
|
|
1208
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1610
1209
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1210
|
+
// Якщо посилання внутрішнє та надано валідний href, отримуємо локалізований URL.
|
|
1211
|
+
const hrefI18n =
|
|
1212
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1613
1213
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
href &&
|
|
1621
|
-
event.button === 0 &&
|
|
1622
|
-
!event.metaKey &&
|
|
1623
|
-
!event.ctrlKey &&
|
|
1624
|
-
!event.shiftKey &&
|
|
1625
|
-
!event.altKey &&
|
|
1626
|
-
!props.target
|
|
1627
|
-
) {
|
|
1628
|
-
event.preventDefault();
|
|
1629
|
-
if (location.url !== hrefI18n) {
|
|
1630
|
-
route(hrefI18n, replace);
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
};
|
|
1214
|
+
return (
|
|
1215
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1216
|
+
{children}
|
|
1217
|
+
</a>
|
|
1218
|
+
);
|
|
1219
|
+
});
|
|
1634
1220
|
|
|
1635
|
-
|
|
1636
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1637
|
-
{children}
|
|
1638
|
-
</a>
|
|
1639
|
-
);
|
|
1640
|
-
}
|
|
1641
|
-
);
|
|
1221
|
+
Link.displayName = "Link";
|
|
1642
1222
|
```
|
|
1643
1223
|
|
|
1644
|
-
```jsx fileName="src/components/
|
|
1224
|
+
```jsx fileName="src/components/Link.cjsx" codeFormat="commonjs"
|
|
1645
1225
|
const { getLocalizedUrl } = require("intlayer");
|
|
1646
1226
|
const { useLocale } = require("preact-intlayer");
|
|
1647
|
-
const { useLocation, route } = require("preact-iso"); // Імпорт з preact-iso
|
|
1648
1227
|
const { forwardRef } = require("preact/compat");
|
|
1649
|
-
const { h } = require("preact"); // Для JSX
|
|
1650
1228
|
|
|
1229
|
+
/**
|
|
1230
|
+
* Утиліта для перевірки, чи є вказаний URL зовнішнім.
|
|
1231
|
+
* Якщо URL починається з http:// або https://, він вважається зовнішнім.
|
|
1232
|
+
*/
|
|
1651
1233
|
const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1652
1234
|
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
event.preventDefault();
|
|
1677
|
-
if (location.url !== hrefI18n) {
|
|
1678
|
-
route(hrefI18n, replace);
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
};
|
|
1235
|
+
/**
|
|
1236
|
+
* Кастомний компонент Link, який адаптує атрибут href відповідно до поточної локалі.
|
|
1237
|
+
* Для внутрішніх посилань використовується `getLocalizedUrl` для додавання префіксу локалі до URL (наприклад, /fr/about).
|
|
1238
|
+
* Це гарантує, що навігація залишатиметься в межах контексту тієї самої локалі.
|
|
1239
|
+
*/
|
|
1240
|
+
const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1241
|
+
const { locale } = useLocale();
|
|
1242
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1243
|
+
|
|
1244
|
+
// Якщо посилання внутрішнє та надано валідний href, отримуємо локалізований URL.
|
|
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
|
+
});
|
|
1682
1258
|
|
|
1683
|
-
|
|
1684
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1685
|
-
{children}
|
|
1686
|
-
</a>
|
|
1687
|
-
);
|
|
1688
|
-
}
|
|
1689
|
-
);
|
|
1259
|
+
Link.displayName = "Link";
|
|
1690
1260
|
|
|
1691
|
-
module.exports = {
|
|
1261
|
+
module.exports = { Link, checkIsExternalLink };
|
|
1692
1262
|
```
|
|
1693
1263
|
|
|
1694
1264
|
#### Як це працює
|
|
1695
1265
|
|
|
1696
1266
|
- **Виявлення зовнішніх посилань**:
|
|
1697
|
-
Допоміжна функція `checkIsExternalLink` визначає, чи є URL зовнішнім. Зовнішні посилання залишаються без
|
|
1267
|
+
Допоміжна функція `checkIsExternalLink` визначає, чи є URL зовнішнім. Зовнішні посилання залишаються без змін, оскільки вони не потребують локалізації.
|
|
1698
1268
|
- **Отримання поточної локалі**:
|
|
1699
|
-
Хук `useLocale` повертає поточну
|
|
1269
|
+
Хук `useLocale` повертає поточну локаль (наприклад, `fr` для французької).
|
|
1700
1270
|
- **Локалізація URL**:
|
|
1701
|
-
Для внутрішніх посилань `getLocalizedUrl`
|
|
1702
|
-
- **Клієнтська навігація**:
|
|
1703
|
-
Функція `handleClick` перевіряє, чи посилання є внутрішнім і чи слід запобігти стандартній навігації. У такому випадку вона використовує функцію `route` з `preact-iso` (отриману через `useLocation` або імпортовану напряму) для виконання навігації на клієнтській стороні. Це забезпечує поведінку, подібну до SPA, без повного перезавантаження сторінки.
|
|
1271
|
+
Для внутрішніх посилань (тобто не зовнішніх) використовується `getLocalizedUrl` для автоматичного додавання префіксу поточної локалі до URL. Це означає, що якщо ваш користувач перебуває у французькій локалі, передача `/about` як `href` перетворить його на `/fr/about`.
|
|
1704
1272
|
- **Повернення посилання**:
|
|
1705
|
-
Компонент повертає елемент `<a>` з локалізованою URL
|
|
1273
|
+
Компонент повертає елемент `<a>` з локалізованою URL-адресою, гарантуючи, що навігація відповідає локалі.
|
|
1274
|
+
|
|
1275
|
+
### (Необов'язково) Крок 11: Відображення Markdown та HTML
|
|
1276
|
+
|
|
1277
|
+
Intlayer підтримує відображення вмісту Markdown та HTML у Preact.
|
|
1278
|
+
|
|
1279
|
+
Ви можете налаштувати відображення вмісту Markdown та HTML за допомогою методу `.use()`. Цей метод дозволяє вам перевизначати стандартне відображення певних тегів.
|
|
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
|
+
{/* Базове відображення */}
|
|
1291
|
+
{myMarkdownContent}
|
|
1292
|
+
|
|
1293
|
+
{/* Спеціальне відображення для Markdown */}
|
|
1294
|
+
{myMarkdownContent.use({
|
|
1295
|
+
h1: (props) => <h1 style={{ color: "red" }} {...props} />,
|
|
1296
|
+
})}
|
|
1297
|
+
|
|
1298
|
+
{/* Базове відображення для HTML */}
|
|
1299
|
+
{myHtmlContent}
|
|
1300
|
+
|
|
1301
|
+
{/* Спеціальне відображення для HTML */}
|
|
1302
|
+
{myHtmlContent.use({
|
|
1303
|
+
b: (props) => <strong style={{ color: "blue" }} {...props} />,
|
|
1304
|
+
})}
|
|
1305
|
+
</div>
|
|
1306
|
+
);
|
|
1307
|
+
```
|
|
1706
1308
|
|
|
1707
1309
|
### Налаштування TypeScript
|
|
1708
1310
|
|
|
1709
|
-
Intlayer використовує module augmentation, щоб
|
|
1311
|
+
Intlayer використовує розширення модулів (module augmentation), щоб отримати переваги від TypeScript та зробити вашу кодову базу надійнішою.
|
|
1710
1312
|
|
|
1711
1313
|

|
|
1712
1314
|
|