@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
|
@@ -24,7 +24,7 @@ history:
|
|
|
24
24
|
changes: Инициализация истории
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
# Переведите ваш Vite
|
|
27
|
+
# Переведите ваш сайт на Vite и Preact с помощью Intlayer | Интернационализация (i18n)
|
|
28
28
|
|
|
29
29
|
<Tabs defaultTab="video">
|
|
30
30
|
<Tab label="Video" value="video">
|
|
@@ -45,25 +45,27 @@ history:
|
|
|
45
45
|
</Tab>
|
|
46
46
|
</Tabs>
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
## Содержание
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
<TOC/>
|
|
51
51
|
|
|
52
52
|
## Что такое Intlayer?
|
|
53
53
|
|
|
54
|
-
**Intlayer**
|
|
54
|
+
**Intlayer** — это инновационная библиотека интернационализации (i18n) с открытым исходным кодом, разработанная для упрощения поддержки многоязычности в современных веб-приложениях.
|
|
55
55
|
|
|
56
|
-
С
|
|
56
|
+
С Intlayer вы можете:
|
|
57
57
|
|
|
58
|
-
- **Легко управлять переводами** с
|
|
58
|
+
- **Легко управлять переводами** с помощью декларативных словарей на уровне компонентов.
|
|
59
59
|
- **Динамически локализовать метаданные**, маршруты и контент.
|
|
60
|
-
- **Обеспечить поддержку TypeScript** с помощью
|
|
61
|
-
-
|
|
60
|
+
- **Обеспечить поддержку TypeScript** с помощью автоматически генерируемых типов, улучшающих автодополнение и обнаружение ошибок.
|
|
61
|
+
- **Пользоваться расширенными функциями**, такими как динамическое определение локали и переключение языков.
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
65
|
## Пошаговое руководство по настройке Intlayer в приложении на Vite и Preact
|
|
66
66
|
|
|
67
|
+
См. [Шаблон приложения](https://github.com/aymericzip/intlayer-vite-preact-template) на GitHub.
|
|
68
|
+
|
|
67
69
|
### Шаг 1: Установка зависимостей
|
|
68
70
|
|
|
69
71
|
Установите необходимые пакеты с помощью npm:
|
|
@@ -94,15 +96,15 @@ bunx intlayer init
|
|
|
94
96
|
|
|
95
97
|
- **intlayer**
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
Основной пакет, предоставляющий инструменты интернационализации для управления конфигурацией, перевода, [объявления контента](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/dictionary/get_started.md), транспиляции и [CLI-команд](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_cli.md).
|
|
99
|
+
Основной пакет, предоставляющий инструменты интернационализации для управления конфигурацией, перевода, [объявления контента](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/dictionary/content_file.md), компиляции и [CLI-команд](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/cli/index.md).
|
|
100
100
|
|
|
101
101
|
- **preact-intlayer**
|
|
102
|
+
|
|
102
103
|
Пакет, который интегрирует Intlayer с приложением на Preact. Он предоставляет провайдеры контекста и хуки для интернационализации Preact.
|
|
103
104
|
|
|
104
105
|
- **vite-intlayer**
|
|
105
|
-
|
|
106
|
+
|
|
107
|
+
Включает плагин Vite для интеграции Intlayer с [сборщиком Vite](https://vite.dev/guide/why.html#why-bundle-for-production), а также промежуточное ПО для определения предпочтительной локали пользователя, управления куки и обработки перенаправления URL.
|
|
106
108
|
|
|
107
109
|
### Шаг 2: Конфигурация вашего проекта
|
|
108
110
|
|
|
@@ -121,6 +123,10 @@ const config: IntlayerConfig = {
|
|
|
121
123
|
],
|
|
122
124
|
defaultLocale: Locales.ENGLISH,
|
|
123
125
|
},
|
|
126
|
+
routing: {
|
|
127
|
+
mode: "prefix-no-default", // По умолчанию: префикс для всех локалей, кроме основной
|
|
128
|
+
storage: ["cookie", "header"], // По умолчанию: хранение локали в куки и определение из заголовка
|
|
129
|
+
},
|
|
124
130
|
};
|
|
125
131
|
|
|
126
132
|
export default config;
|
|
@@ -140,6 +146,10 @@ const config = {
|
|
|
140
146
|
],
|
|
141
147
|
defaultLocale: Locales.ENGLISH,
|
|
142
148
|
},
|
|
149
|
+
routing: {
|
|
150
|
+
mode: "prefix-no-default", // По умолчанию: префикс для всех локалей, кроме основной
|
|
151
|
+
storage: ["cookie", "header"], // По умолчанию: хранение локали в куки и определение из заголовка
|
|
152
|
+
},
|
|
143
153
|
};
|
|
144
154
|
|
|
145
155
|
export default config;
|
|
@@ -149,7 +159,6 @@ export default config;
|
|
|
149
159
|
const { Locales } = require("intlayer");
|
|
150
160
|
|
|
151
161
|
/** @type {import('intlayer').IntlayerConfig} */
|
|
152
|
-
// Конфигурация интернационализации
|
|
153
162
|
const config = {
|
|
154
163
|
internationalization: {
|
|
155
164
|
locales: [
|
|
@@ -160,14 +169,18 @@ const config = {
|
|
|
160
169
|
],
|
|
161
170
|
defaultLocale: Locales.ENGLISH,
|
|
162
171
|
},
|
|
172
|
+
routing: {
|
|
173
|
+
mode: "prefix-no-default", // По умолчанию: префикс для всех локалей, кроме основной
|
|
174
|
+
storage: ["cookie", "header"], // По умолчанию: хранение локали в куки и определение из заголовка
|
|
175
|
+
},
|
|
163
176
|
};
|
|
164
177
|
|
|
165
178
|
module.exports = config;
|
|
166
179
|
```
|
|
167
180
|
|
|
168
|
-
> Через этот конфигурационный файл вы можете настроить локализованные URL,
|
|
181
|
+
> Через этот конфигурационный файл вы можете настроить локализованные URL, режимы маршрутизации, параметры хранения, имена куки, расположение и расширение ваших объявлений контента, отключить логи Intlayer в консоли и многое другое. Полный список доступных параметров см. в [документации по конфигурации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/configuration.md).
|
|
169
182
|
|
|
170
|
-
### Шаг 3: Интеграция Intlayer в
|
|
183
|
+
### Шаг 3: Интеграция Intlayer в конфигурацию Vite
|
|
171
184
|
|
|
172
185
|
Добавьте плагин intlayer в вашу конфигурацию.
|
|
173
186
|
|
|
@@ -204,11 +217,11 @@ module.exports = defineConfig({
|
|
|
204
217
|
});
|
|
205
218
|
```
|
|
206
219
|
|
|
207
|
-
> Плагин Vite `intlayer()` используется для интеграции Intlayer с Vite. Он обеспечивает сборку файлов
|
|
220
|
+
> Плагин Vite `intlayer()` используется для интеграции Intlayer с Vite. Он обеспечивает сборку файлов объявлений контента и отслеживает их в режиме разработки. Он определяет переменные окружения Intlayer внутри приложения Vite. Кроме того, он предоставляет алиасы для оптимизации производительности.
|
|
208
221
|
|
|
209
|
-
### Шаг 4:
|
|
222
|
+
### Шаг 4: Объявление контента
|
|
210
223
|
|
|
211
|
-
Создайте и управляйте
|
|
224
|
+
Создайте и управляйте своими объявлениями контента для хранения переводов:
|
|
212
225
|
|
|
213
226
|
```tsx fileName="src/app.content.tsx" contentDeclarationFormat="typescript"
|
|
214
227
|
import { t, type Dictionary } from "intlayer";
|
|
@@ -225,7 +238,7 @@ const appContent = {
|
|
|
225
238
|
preactLogo: t({
|
|
226
239
|
en: "Preact logo",
|
|
227
240
|
fr: "Logo Preact",
|
|
228
|
-
es: "
|
|
241
|
+
es: "Logo Preact",
|
|
229
242
|
}),
|
|
230
243
|
|
|
231
244
|
title: "Vite + Preact",
|
|
@@ -239,7 +252,7 @@ const appContent = {
|
|
|
239
252
|
edit: t<ComponentChildren>({
|
|
240
253
|
en: (
|
|
241
254
|
<>
|
|
242
|
-
|
|
255
|
+
Edit <code>src/app.tsx</code> and save to test HMR
|
|
243
256
|
</>
|
|
244
257
|
),
|
|
245
258
|
fr: (
|
|
@@ -267,7 +280,7 @@ export default appContent;
|
|
|
267
280
|
|
|
268
281
|
```javascript fileName="src/app.content.mjs" contentDeclarationFormat="esm"
|
|
269
282
|
import { t } from "intlayer";
|
|
270
|
-
// import { h } from 'preact'; //
|
|
283
|
+
// import { h } from 'preact'; // Требуется, если вы используете JSX напрямую в .mjs
|
|
271
284
|
|
|
272
285
|
/** @type {import('intlayer').Dictionary} */
|
|
273
286
|
const appContent = {
|
|
@@ -275,13 +288,13 @@ const appContent = {
|
|
|
275
288
|
content: {
|
|
276
289
|
viteLogo: t({
|
|
277
290
|
en: "Vite logo",
|
|
278
|
-
fr: "
|
|
279
|
-
es: "
|
|
291
|
+
fr: "Logo Vite",
|
|
292
|
+
es: "Logo Vite",
|
|
280
293
|
}),
|
|
281
294
|
preactLogo: t({
|
|
282
295
|
en: "Preact logo",
|
|
283
|
-
fr: "
|
|
284
|
-
es: "
|
|
296
|
+
fr: "Logo Preact",
|
|
297
|
+
es: "Logo Preact",
|
|
285
298
|
}),
|
|
286
299
|
|
|
287
300
|
title: "Vite + Preact",
|
|
@@ -299,8 +312,8 @@ const appContent = {
|
|
|
299
312
|
}),
|
|
300
313
|
|
|
301
314
|
readTheDocs: t({
|
|
302
|
-
en: "
|
|
303
|
-
fr: "
|
|
315
|
+
en: "Click on the Vite and Preact logos to learn more",
|
|
316
|
+
fr: "Cliqueз sur les logos Vite et Preact pour en savoir plus",
|
|
304
317
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
305
318
|
}),
|
|
306
319
|
},
|
|
@@ -311,19 +324,19 @@ export default appContent;
|
|
|
311
324
|
|
|
312
325
|
```javascript fileName="src/app.content.cjs" contentDeclarationFormat="commonjs"
|
|
313
326
|
const { t } = require("intlayer");
|
|
314
|
-
// const { h } = require('preact'); //
|
|
327
|
+
// const { h } = require('preact'); // Требуется, если вы используете JSX напрямую в .cjs
|
|
315
328
|
|
|
316
329
|
/** @type {import('intlayer').Dictionary} */
|
|
317
330
|
const appContent = {
|
|
318
331
|
key: "app",
|
|
319
332
|
content: {
|
|
320
333
|
viteLogo: t({
|
|
321
|
-
en: "
|
|
334
|
+
en: "Vite logo",
|
|
322
335
|
fr: "Logo Vite",
|
|
323
336
|
es: "Logo Vite",
|
|
324
337
|
}),
|
|
325
338
|
preactLogo: t({
|
|
326
|
-
en: "
|
|
339
|
+
en: "Preact logo",
|
|
327
340
|
fr: "Logo Preact",
|
|
328
341
|
es: "Logo Preact",
|
|
329
342
|
}),
|
|
@@ -334,21 +347,18 @@ const appContent = {
|
|
|
334
347
|
en: "count is ",
|
|
335
348
|
fr: "le compte est ",
|
|
336
349
|
es: "el recuento es ",
|
|
337
|
-
ru: "счётчик равен ",
|
|
338
350
|
}),
|
|
339
351
|
|
|
340
352
|
edit: t({
|
|
341
353
|
en: "Edit src/app.tsx and save to test HMR",
|
|
342
354
|
fr: "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
343
355
|
es: "Edita src/app.tsx y guarda para probar HMR",
|
|
344
|
-
ru: "Отредактируйте src/app.tsx и сохраните, чтобы проверить HMR",
|
|
345
356
|
}),
|
|
346
357
|
|
|
347
358
|
readTheDocs: t({
|
|
348
359
|
en: "Click on the Vite and Preact logos to learn more",
|
|
349
360
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
350
361
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
351
|
-
ru: "Нажмите на логотипы Vite и Preact, чтобы узнать больше",
|
|
352
362
|
}),
|
|
353
363
|
},
|
|
354
364
|
};
|
|
@@ -366,8 +376,7 @@ module.exports = appContent;
|
|
|
366
376
|
"translation": {
|
|
367
377
|
"en": "Vite logo",
|
|
368
378
|
"fr": "Logo Vite",
|
|
369
|
-
"es": "Logo Vite"
|
|
370
|
-
"ru": "Логотип Vite" // комментарий: перевод для русского языка
|
|
379
|
+
"es": "Logo Vite"
|
|
371
380
|
}
|
|
372
381
|
},
|
|
373
382
|
"preactLogo": {
|
|
@@ -375,8 +384,7 @@ module.exports = appContent;
|
|
|
375
384
|
"translation": {
|
|
376
385
|
"en": "Preact logo",
|
|
377
386
|
"fr": "Logo Preact",
|
|
378
|
-
"es": "Logo Preact"
|
|
379
|
-
"ru": "Логотип Preact" // комментарий: перевод для русского языка
|
|
387
|
+
"es": "Logo Preact"
|
|
380
388
|
}
|
|
381
389
|
},
|
|
382
390
|
"title": {
|
|
@@ -384,8 +392,7 @@ module.exports = appContent;
|
|
|
384
392
|
"translation": {
|
|
385
393
|
"en": "Vite + Preact",
|
|
386
394
|
"fr": "Vite + Preact",
|
|
387
|
-
"es": "Vite + Preact"
|
|
388
|
-
"ru": "Vite + Preact" // комментарий: название технологии не переводится
|
|
395
|
+
"es": "Vite + Preact"
|
|
389
396
|
}
|
|
390
397
|
},
|
|
391
398
|
"count": {
|
|
@@ -393,8 +400,7 @@ module.exports = appContent;
|
|
|
393
400
|
"translation": {
|
|
394
401
|
"en": "count is ",
|
|
395
402
|
"fr": "le compte est ",
|
|
396
|
-
"es": "el recuento es "
|
|
397
|
-
"ru": "счётчик равен " // комментарий: перевод для русского языка
|
|
403
|
+
"es": "el recuento es "
|
|
398
404
|
}
|
|
399
405
|
},
|
|
400
406
|
"edit": {
|
|
@@ -402,8 +408,7 @@ module.exports = appContent;
|
|
|
402
408
|
"translation": {
|
|
403
409
|
"en": "Edit src/app.tsx and save to test HMR",
|
|
404
410
|
"fr": "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
405
|
-
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
406
|
-
"ru": "Отредактируйте src/app.tsx и сохраните, чтобы проверить HMR"
|
|
411
|
+
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
407
412
|
}
|
|
408
413
|
},
|
|
409
414
|
"readTheDocs": {
|
|
@@ -411,21 +416,20 @@ module.exports = appContent;
|
|
|
411
416
|
"translation": {
|
|
412
417
|
"en": "Click on the Vite and Preact logos to learn more",
|
|
413
418
|
"fr": "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
414
|
-
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
415
|
-
"ru": "Нажмите на логотипы Vite и Preact, чтобы узнать больше"
|
|
419
|
+
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
416
420
|
}
|
|
417
421
|
}
|
|
418
422
|
}
|
|
419
423
|
}
|
|
420
424
|
```
|
|
421
425
|
|
|
422
|
-
> Ваши объявления контента могут быть определены в любом месте вашего приложения,
|
|
426
|
+
> Ваши объявления контента могут быть определены в любом месте вашего приложения, при условии, что они включены в каталог `contentDir` (по умолчанию `./src`). И соответствуют расширению файла объявлений контента (по умолчанию `.content.{json,ts,tsx,js,jsx,mjs,cjs}`).
|
|
423
427
|
|
|
424
|
-
>
|
|
428
|
+
> Подробнее см. в [документации по объявлению контента](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/dictionary/content_file.md).
|
|
425
429
|
|
|
426
|
-
> Если ваш файл контента содержит код TSX,
|
|
430
|
+
> Если ваш файл контента содержит код TSX, вам может потребоваться импортировать `import { h } from "preact";` или убедиться, что ваша JSX прагма правильно настроена для Preact.
|
|
427
431
|
|
|
428
|
-
### Шаг 5:
|
|
432
|
+
### Шаг 5: Использование Intlayer в коде
|
|
429
433
|
|
|
430
434
|
Получайте доступ к вашим словарям контента по всему приложению:
|
|
431
435
|
|
|
@@ -463,6 +467,12 @@ const AppContent: FunctionalComponent = () => {
|
|
|
463
467
|
</button>
|
|
464
468
|
<p>{content.edit}</p>
|
|
465
469
|
</div>
|
|
470
|
+
{/* Markdown контент */}
|
|
471
|
+
<div>{content.myMarkdownContent}</div>
|
|
472
|
+
|
|
473
|
+
{/* HTML контент */}
|
|
474
|
+
<div>{content.myHtmlContent}</div>
|
|
475
|
+
|
|
466
476
|
<p class="read-the-docs">{content.readTheDocs}</p>
|
|
467
477
|
</>
|
|
468
478
|
);
|
|
@@ -571,7 +581,7 @@ const App = () => (
|
|
|
571
581
|
module.exports = App;
|
|
572
582
|
```
|
|
573
583
|
|
|
574
|
-
> Если вы хотите использовать
|
|
584
|
+
> Если вы хотите использовать свой контент в строковом атрибуте, таком как `alt`, `title`, `href`, `aria-label` и т. д., вы должны вызвать значение функции, например:
|
|
575
585
|
|
|
576
586
|
> ```jsx
|
|
577
587
|
> <img src={content.image.src.value} alt={content.image.value} />
|
|
@@ -579,11 +589,11 @@ module.exports = App;
|
|
|
579
589
|
|
|
580
590
|
> Примечание: В Preact `className` обычно пишется как `class`.
|
|
581
591
|
|
|
582
|
-
> Чтобы узнать больше о хуке `useIntlayer`, обратитесь к [документации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useIntlayer.md) (API
|
|
592
|
+
> Чтобы узнать больше о хуке `useIntlayer`, обратитесь к [документации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useIntlayer.md) (API для `preact-intlayer` аналогично).
|
|
583
593
|
|
|
584
|
-
### (Необязательно) Шаг 6: Изменение языка
|
|
594
|
+
### (Необязательно) Шаг 6: Изменение языка контента
|
|
585
595
|
|
|
586
|
-
Для изменения языка
|
|
596
|
+
Для изменения языка контента вы можете использовать функцию `setLocale`, предоставляемую хуком `useLocale`. Эта функция позволяет установить локаль приложения и обновить контент соответствующим образом.
|
|
587
597
|
|
|
588
598
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
589
599
|
import type { FunctionalComponent } from "preact";
|
|
@@ -595,7 +605,7 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
595
605
|
|
|
596
606
|
return (
|
|
597
607
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
598
|
-
|
|
608
|
+
Change Language to English
|
|
599
609
|
</button>
|
|
600
610
|
);
|
|
601
611
|
};
|
|
@@ -612,7 +622,7 @@ const LocaleSwitcher = () => {
|
|
|
612
622
|
|
|
613
623
|
return (
|
|
614
624
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
615
|
-
|
|
625
|
+
Change Language to English
|
|
616
626
|
</button>
|
|
617
627
|
);
|
|
618
628
|
};
|
|
@@ -629,7 +639,7 @@ const LocaleSwitcher = () => {
|
|
|
629
639
|
|
|
630
640
|
return (
|
|
631
641
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
632
|
-
|
|
642
|
+
Change Language to English
|
|
633
643
|
</button>
|
|
634
644
|
);
|
|
635
645
|
};
|
|
@@ -637,11 +647,11 @@ const LocaleSwitcher = () => {
|
|
|
637
647
|
module.exports = LocaleSwitcher;
|
|
638
648
|
```
|
|
639
649
|
|
|
640
|
-
> Чтобы узнать больше о хуке `useLocale`, обратитесь к [документации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useLocale.md) (API
|
|
650
|
+
> Чтобы узнать больше о хуке `useLocale`, обратитесь к [документации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useLocale.md) (API для `preact-intlayer` аналогично).
|
|
641
651
|
|
|
642
652
|
### (Необязательно) Шаг 7: Добавьте локализованную маршрутизацию в ваше приложение
|
|
643
653
|
|
|
644
|
-
Цель этого шага
|
|
654
|
+
Цель этого шага — создать уникальные маршруты для каждого языка. Это полезно для SEO и создания дружественных к поисковым системам URL.
|
|
645
655
|
Пример:
|
|
646
656
|
|
|
647
657
|
```plaintext
|
|
@@ -650,142 +660,15 @@ module.exports = LocaleSwitcher;
|
|
|
650
660
|
- https://example.com/fr/about
|
|
651
661
|
```
|
|
652
662
|
|
|
653
|
-
> По умолчанию маршруты не имеют префикса для
|
|
654
|
-
|
|
655
|
-
Чтобы добавить локализованную маршрутизацию в ваше приложение, вы можете создать компонент `LocaleRouter`, который обернет маршруты вашего приложения и будет обрабатывать маршрутизацию на основе локали. Вот пример с использованием [preact-iso](https://github.com/preactjs/preact-iso):
|
|
663
|
+
> По умолчанию маршруты не имеют префикса для основной локали. Если вы хотите добавить префикс для основной локали, вы можете установить опцию `routing.mode` в значение `"prefix-all"` в вашей конфигурации. См. [документацию по конфигурации](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/configuration.md) для получения дополнительной информации.
|
|
656
664
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
```bash packageManager="npm"
|
|
660
|
-
npm install preact-iso
|
|
661
|
-
npx intlayer init
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
```bash packageManager="pnpm"
|
|
665
|
-
pnpm add preact-iso
|
|
666
|
-
pnpm intlayer init
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
```bash packageManager="yarn"
|
|
670
|
-
yarn add preact-iso
|
|
671
|
-
```
|
|
665
|
+
Чтобы добавить локализованную маршрутизацию в ваше приложение, вы можете создать компонент `LocaleRouter`, который оборачивает маршруты вашего приложения и обрабатывает маршрутизацию на основе локали. Вот пример использования [preact-iso](https://github.com/preactjs/preact-iso):
|
|
672
666
|
|
|
673
667
|
```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
|
|
674
|
-
import {
|
|
675
|
-
import { ComponentChildren, FunctionalComponent } from "preact";
|
|
668
|
+
import { localeMap } from "intlayer";
|
|
676
669
|
import { IntlayerProvider } from "preact-intlayer";
|
|
677
|
-
import { LocationProvider,
|
|
678
|
-
import {
|
|
679
|
-
|
|
680
|
-
const { internationalization, middleware } = configuration;
|
|
681
|
-
const { locales, defaultLocale } = internationalization;
|
|
682
|
-
|
|
683
|
-
const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({
|
|
684
|
-
to,
|
|
685
|
-
replace,
|
|
686
|
-
}) => {
|
|
687
|
-
const { route } = useLocation();
|
|
688
|
-
useEffect(() => {
|
|
689
|
-
route(to, replace);
|
|
690
|
-
}, [to, replace, route]);
|
|
691
|
-
return null;
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
/**
|
|
696
|
-
* Компонент, который обрабатывает локализацию и оборачивает дочерние элементы в соответствующий контекст локали.
|
|
697
|
-
* Он управляет определением и проверкой локали на основе URL.
|
|
698
|
-
*/
|
|
699
|
-
const AppLocalized: FunctionalComponent<{
|
|
700
|
-
children: ComponentChildren;
|
|
701
|
-
locale?: Locales;
|
|
702
|
-
}> = ({ children, locale }) => {
|
|
703
|
-
const { path: pathname, url } = useLocation();
|
|
704
|
-
|
|
705
|
-
if (!url) {
|
|
706
|
-
return null;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
const search = url.substring(pathname.length);
|
|
710
|
-
|
|
711
|
-
// Определяем текущую локаль, используя локаль по умолчанию, если не указана
|
|
712
|
-
const currentLocale = locale ?? defaultLocale;
|
|
713
|
-
|
|
714
|
-
// Удаляем префикс локали из пути для построения базового пути
|
|
715
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
716
|
-
pathname // Текущий путь URL
|
|
717
|
-
);
|
|
718
|
-
|
|
719
|
-
/**
|
|
720
|
-
* Если middleware.prefixDefault установлено в true, префикс с локалью по умолчанию должен всегда использоваться.
|
|
721
|
-
*/
|
|
722
|
-
if (middleware.prefixDefault) {
|
|
723
|
-
// Проверка локали
|
|
724
|
-
if (!locale || !locales.includes(locale)) {
|
|
725
|
-
// Перенаправление на локаль по умолчанию с обновлённым путём
|
|
726
|
-
return (
|
|
727
|
-
<Navigate
|
|
728
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
729
|
-
replace // Заменить текущую запись в истории на новую
|
|
730
|
-
/>
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
// Обернуть дочерние элементы в IntlayerProvider и установить текущую локаль
|
|
735
|
-
return (
|
|
736
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
737
|
-
);
|
|
738
|
-
} else {
|
|
739
|
-
/**
|
|
740
|
-
* Когда middleware.prefixDefault равно false, префикс локали по умолчанию не используется.
|
|
741
|
-
* Убедитесь, что текущая локаль действительна и не является локалью по умолчанию.
|
|
742
|
-
*/
|
|
743
|
-
if (
|
|
744
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
745
|
-
!locales
|
|
746
|
-
.filter(
|
|
747
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Исключить локаль по умолчанию
|
|
748
|
-
)
|
|
749
|
-
.includes(currentLocale) // Проверить, входит ли текущая локаль в список допустимых локалей
|
|
750
|
-
) {
|
|
751
|
-
// Перенаправить на путь без префикса локали
|
|
752
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// Обернуть дочерние элементы в IntlayerProvider и установить текущую локаль
|
|
756
|
-
return (
|
|
757
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
758
|
-
);
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
const RouterContent: FunctionalComponent<{
|
|
763
|
-
children: ComponentChildren;
|
|
764
|
-
}> = ({ children }) => {
|
|
765
|
-
const { path } = useLocation();
|
|
766
|
-
|
|
767
|
-
if (!path) {
|
|
768
|
-
return null;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
const pathLocale = path.split("/")[1] as Locales;
|
|
772
|
-
|
|
773
|
-
const isLocaleRoute = locales
|
|
774
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
775
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
776
|
-
|
|
777
|
-
if (isLocaleRoute) {
|
|
778
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
return (
|
|
782
|
-
<AppLocalized
|
|
783
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
784
|
-
>
|
|
785
|
-
{children}
|
|
786
|
-
</AppLocalized>
|
|
787
|
-
);
|
|
788
|
-
};
|
|
670
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
671
|
+
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
789
672
|
|
|
790
673
|
/**
|
|
791
674
|
* Компонент маршрутизатора, который настраивает маршруты с учетом локали.
|
|
@@ -795,120 +678,27 @@ export const LocaleRouter: FunctionalComponent<{
|
|
|
795
678
|
children: ComponentChildren;
|
|
796
679
|
}> = ({ children }) => (
|
|
797
680
|
<LocationProvider>
|
|
798
|
-
<
|
|
681
|
+
<Router>
|
|
682
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
683
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
684
|
+
.map(({ locale, urlPrefix }) => (
|
|
685
|
+
<Route
|
|
686
|
+
key={locale}
|
|
687
|
+
path={`${urlPrefix}/:rest*`}
|
|
688
|
+
component={() => (
|
|
689
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
690
|
+
)}
|
|
691
|
+
/>
|
|
692
|
+
))}
|
|
693
|
+
</Router>
|
|
799
694
|
</LocationProvider>
|
|
800
695
|
);
|
|
801
696
|
```
|
|
802
697
|
|
|
803
698
|
```jsx fileName="src/components/LocaleRouter.jsx" codeFormat="esm"
|
|
804
|
-
|
|
805
|
-
import { configuration, getPathWithoutLocale } from "intlayer";
|
|
699
|
+
import { localeMap } from "intlayer";
|
|
806
700
|
import { IntlayerProvider } from "preact-intlayer";
|
|
807
|
-
import { LocationProvider,
|
|
808
|
-
import { useEffect } from "preact/hooks";
|
|
809
|
-
import { h } from "preact"; // Необходимо для JSX
|
|
810
|
-
|
|
811
|
-
// Деструктуризация конфигурации из Intlayer
|
|
812
|
-
const { internationalization, middleware } = configuration;
|
|
813
|
-
const { locales, defaultLocale } = internationalization;
|
|
814
|
-
|
|
815
|
-
const Navigate = ({ to, replace }) => {
|
|
816
|
-
const { route } = useLocation();
|
|
817
|
-
useEffect(() => {
|
|
818
|
-
route(to, replace);
|
|
819
|
-
}, [to, replace, route]);
|
|
820
|
-
return null;
|
|
821
|
-
};
|
|
822
|
-
|
|
823
|
-
/**
|
|
824
|
-
* Компонент, который обрабатывает локализацию и оборачивает дочерние элементы в соответствующий контекст локали.
|
|
825
|
-
* Он управляет определением и проверкой локали на основе URL.
|
|
826
|
-
*/
|
|
827
|
-
const AppLocalized = ({ children, locale }) => {
|
|
828
|
-
const { path: pathname, url } = useLocation();
|
|
829
|
-
|
|
830
|
-
if (!url) {
|
|
831
|
-
return null;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const search = url.substring(pathname.length);
|
|
835
|
-
|
|
836
|
-
// Определяем текущую локаль, используя локаль по умолчанию, если не указана
|
|
837
|
-
const currentLocale = locale ?? defaultLocale;
|
|
838
|
-
|
|
839
|
-
// Удаляем префикс локали из пути для построения базового пути
|
|
840
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
841
|
-
pathname // Текущий путь URL
|
|
842
|
-
);
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* Если middleware.prefixDefault равно true, префикс локали по умолчанию всегда должен присутствовать.
|
|
846
|
-
*/
|
|
847
|
-
if (middleware.prefixDefault) {
|
|
848
|
-
// Проверяем корректность локали
|
|
849
|
-
if (!locale || !locales.includes(locale)) {
|
|
850
|
-
// Перенаправляем на локаль по умолчанию с обновлённым путём
|
|
851
|
-
return (
|
|
852
|
-
<Navigate
|
|
853
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
854
|
-
replace // Заменяем текущую запись в истории на новую
|
|
855
|
-
/>
|
|
856
|
-
);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// Оборачиваем дочерние элементы в IntlayerProvider и устанавливаем текущую локаль
|
|
860
|
-
return (
|
|
861
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
862
|
-
);
|
|
863
|
-
} else {
|
|
864
|
-
/**
|
|
865
|
-
* Если middleware.prefixDefault равно false, локаль по умолчанию не префиксируется.
|
|
866
|
-
* Убедитесь, что текущая локаль валидна и не является локалью по умолчанию.
|
|
867
|
-
*/
|
|
868
|
-
if (
|
|
869
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
870
|
-
!locales
|
|
871
|
-
.filter(
|
|
872
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Исключить локаль по умолчанию
|
|
873
|
-
)
|
|
874
|
-
.includes(currentLocale) // Проверить, входит ли текущая локаль в список допустимых локалей
|
|
875
|
-
) {
|
|
876
|
-
// Перенаправить на путь без префикса локали
|
|
877
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
// Обернуть дочерние элементы в IntlayerProvider и установить текущую локаль
|
|
881
|
-
return (
|
|
882
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
};
|
|
886
|
-
|
|
887
|
-
const RouterContent = ({ children }) => {
|
|
888
|
-
const { path } = useLocation();
|
|
889
|
-
|
|
890
|
-
if (!path) {
|
|
891
|
-
return null;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
const pathLocale = path.split("/")[1];
|
|
895
|
-
|
|
896
|
-
const isLocaleRoute = locales
|
|
897
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
898
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
899
|
-
|
|
900
|
-
if (isLocaleRoute) {
|
|
901
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
return (
|
|
905
|
-
<AppLocalized
|
|
906
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
907
|
-
>
|
|
908
|
-
{children}
|
|
909
|
-
</AppLocalized>
|
|
910
|
-
);
|
|
911
|
-
};
|
|
701
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
912
702
|
|
|
913
703
|
/**
|
|
914
704
|
* Компонент маршрутизатора, который настраивает маршруты с учетом локали.
|
|
@@ -916,143 +706,61 @@ const RouterContent = ({ children }) => {
|
|
|
916
706
|
*/
|
|
917
707
|
export const LocaleRouter = ({ children }) => (
|
|
918
708
|
<LocationProvider>
|
|
919
|
-
<
|
|
709
|
+
<Router>
|
|
710
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
711
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
712
|
+
.map(({ locale, urlPrefix }) => (
|
|
713
|
+
<Route
|
|
714
|
+
key={locale}
|
|
715
|
+
path={`${urlPrefix}/:rest*`}
|
|
716
|
+
component={() => (
|
|
717
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
718
|
+
)}
|
|
719
|
+
/>
|
|
720
|
+
))}
|
|
721
|
+
</Router>
|
|
920
722
|
</LocationProvider>
|
|
921
723
|
);
|
|
922
724
|
```
|
|
923
725
|
|
|
924
726
|
```jsx fileName="src/components/LocaleRouter.cjsx" codeFormat="commonjs"
|
|
925
|
-
|
|
926
|
-
const { configuration, getPathWithoutLocale } = require("intlayer");
|
|
727
|
+
const { localeMap } = require("intlayer");
|
|
927
728
|
const { IntlayerProvider } = require("preact-intlayer");
|
|
928
|
-
const { LocationProvider,
|
|
929
|
-
const { useEffect } = require("preact/hooks");
|
|
930
|
-
const { h } = require("preact"); // Необходимо для JSX
|
|
931
|
-
|
|
932
|
-
// Деструктуризация конфигурации из Intlayer
|
|
933
|
-
const { internationalization, middleware } = configuration;
|
|
934
|
-
const { locales, defaultLocale } = internationalization;
|
|
935
|
-
|
|
936
|
-
const Navigate = ({ to, replace }) => {
|
|
937
|
-
const { route } = useLocation();
|
|
938
|
-
useEffect(() => {
|
|
939
|
-
route(to, replace);
|
|
940
|
-
}, [to, replace, route]);
|
|
941
|
-
return null;
|
|
942
|
-
};
|
|
943
|
-
|
|
944
|
-
/**
|
|
945
|
-
* Компонент, который обрабатывает локализацию и оборачивает дочерние элементы в соответствующий контекст локали.
|
|
946
|
-
* Управляет определением и проверкой локали на основе URL.
|
|
947
|
-
*/
|
|
948
|
-
const AppLocalized = ({ children, locale }) => {
|
|
949
|
-
const { path: pathname, url } = useLocation();
|
|
950
|
-
|
|
951
|
-
if (!url) {
|
|
952
|
-
return null;
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
const search = url.substring(pathname.length);
|
|
956
|
-
|
|
957
|
-
// Определяем текущую локаль, по умолчанию используем локаль по умолчанию, если не указана
|
|
958
|
-
const currentLocale = locale ?? defaultLocale;
|
|
959
|
-
|
|
960
|
-
// Удаляем префикс локали из пути для построения базового пути
|
|
961
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
962
|
-
pathname // Текущий путь URL
|
|
963
|
-
);
|
|
964
|
-
|
|
965
|
-
/**
|
|
966
|
-
* Если middleware.prefixDefault равно true, префикс локали по умолчанию всегда должен присутствовать.
|
|
967
|
-
*/
|
|
968
|
-
if (middleware.prefixDefault) {
|
|
969
|
-
// Проверяем валидность локали
|
|
970
|
-
if (!locale || !locales.includes(locale)) {
|
|
971
|
-
// Перенаправляем на локаль по умолчанию с обновлённым путём
|
|
972
|
-
return (
|
|
973
|
-
<Navigate
|
|
974
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
975
|
-
replace // Заменить текущую запись истории на новую
|
|
976
|
-
/>
|
|
977
|
-
);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
// Обернуть дочерние элементы в IntlayerProvider и установить текущую локаль
|
|
981
|
-
return (
|
|
982
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
983
|
-
);
|
|
984
|
-
} else {
|
|
985
|
-
/**
|
|
986
|
-
* Когда middleware.prefixDefault равно false, префикс для локали по умолчанию не используется.
|
|
987
|
-
* Убедиться, что текущая локаль действительна и не является локалью по умолчанию.
|
|
988
|
-
*/
|
|
989
|
-
if (
|
|
990
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
991
|
-
!locales
|
|
992
|
-
.filter(
|
|
993
|
-
(loc) => loc.toString() !== defaultLocale.toString() // Исключить локаль по умолчанию
|
|
994
|
-
)
|
|
995
|
-
.includes(currentLocale) // Проверяем, находится ли текущая локаль в списке допустимых локалей
|
|
996
|
-
) {
|
|
997
|
-
// Перенаправляем на путь без префикса локали
|
|
998
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
// Оборачиваем дочерние элементы в IntlayerProvider и устанавливаем текущую локаль
|
|
1002
|
-
return (
|
|
1003
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
};
|
|
1007
|
-
|
|
1008
|
-
const RouterContent = ({ children }) => {
|
|
1009
|
-
const { path } = useLocation();
|
|
1010
|
-
|
|
1011
|
-
if (!path) {
|
|
1012
|
-
return null;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
const pathLocale = path.split("/")[1];
|
|
1016
|
-
|
|
1017
|
-
const isLocaleRoute = locales
|
|
1018
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
1019
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
1020
|
-
|
|
1021
|
-
if (isLocaleRoute) {
|
|
1022
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
return (
|
|
1026
|
-
<AppLocalized
|
|
1027
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
1028
|
-
>
|
|
1029
|
-
{children}
|
|
1030
|
-
</AppLocalized>
|
|
1031
|
-
);
|
|
1032
|
-
};
|
|
729
|
+
const { LocationProvider, Router, Route } = require("preact-iso");
|
|
1033
730
|
|
|
1034
731
|
/**
|
|
1035
732
|
* Компонент маршрутизатора, который настраивает маршруты с учетом локали.
|
|
1036
733
|
* Использует preact-iso для управления навигацией и рендеринга локализованных компонентов.
|
|
1037
734
|
*/
|
|
1038
|
-
const LocaleRouter = ({ children }) =>
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
735
|
+
const LocaleRouter = ({ children }) =>
|
|
736
|
+
h(
|
|
737
|
+
LocationProvider,
|
|
738
|
+
{},
|
|
739
|
+
h(
|
|
740
|
+
Router,
|
|
741
|
+
{},
|
|
742
|
+
localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
743
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
744
|
+
.map(({ locale, urlPrefix }) =>
|
|
745
|
+
h(Route, {
|
|
746
|
+
key: locale,
|
|
747
|
+
path: `${urlPrefix}/:rest*`,
|
|
748
|
+
component: () => h(IntlayerProvider, { locale }, children),
|
|
749
|
+
})
|
|
750
|
+
)
|
|
751
|
+
)
|
|
752
|
+
);
|
|
1043
753
|
|
|
1044
754
|
module.exports = { LocaleRouter };
|
|
1045
755
|
```
|
|
1046
756
|
|
|
1047
|
-
Затем вы можете использовать компонент `LocaleRouter` в
|
|
757
|
+
Затем вы можете использовать компонент `LocaleRouter` в своем приложении:
|
|
1048
758
|
|
|
1049
759
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1050
760
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1051
761
|
import type { FunctionalComponent } from "preact";
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
import type { FunctionalComponent } from "preact";
|
|
1055
|
-
// ... Ваш компонент AppContent (определённый на Шаге 5)
|
|
762
|
+
|
|
763
|
+
// ... Ваш компонент AppContent
|
|
1056
764
|
|
|
1057
765
|
const App: FunctionalComponent = () => (
|
|
1058
766
|
<LocaleRouter>
|
|
@@ -1065,7 +773,8 @@ export default App;
|
|
|
1065
773
|
|
|
1066
774
|
```jsx fileName="src/app.jsx" codeFormat="esm"
|
|
1067
775
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1068
|
-
|
|
776
|
+
|
|
777
|
+
// ... Ваш компонент AppContent
|
|
1069
778
|
|
|
1070
779
|
const App = () => (
|
|
1071
780
|
<LocaleRouter>
|
|
@@ -1078,7 +787,8 @@ export default App;
|
|
|
1078
787
|
|
|
1079
788
|
```jsx fileName="src/app.cjsx" codeFormat="commonjs"
|
|
1080
789
|
const { LocaleRouter } = require("./components/LocaleRouter");
|
|
1081
|
-
|
|
790
|
+
|
|
791
|
+
// ... Ваш компонент AppContent
|
|
1082
792
|
|
|
1083
793
|
const App = () => (
|
|
1084
794
|
<LocaleRouter>
|
|
@@ -1089,47 +799,12 @@ const App = () => (
|
|
|
1089
799
|
module.exports = App;
|
|
1090
800
|
```
|
|
1091
801
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
|
|
1095
|
-
import { defineConfig } from "vite";
|
|
1096
|
-
import preact from "@preact/preset-vite";
|
|
1097
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1098
|
-
|
|
1099
|
-
// https://vitejs.dev/config/
|
|
1100
|
-
export default defineConfig({
|
|
1101
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1102
|
-
});
|
|
1103
|
-
```
|
|
1104
|
-
|
|
1105
|
-
```javascript {3,7} fileName="vite.config.mjs" codeFormat="esm"
|
|
1106
|
-
import { defineConfig } from "vite";
|
|
1107
|
-
import preact from "@preact/preset-vite";
|
|
1108
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1109
|
-
|
|
1110
|
-
// https://vitejs.dev/config/
|
|
1111
|
-
export default defineConfig({
|
|
1112
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1113
|
-
});
|
|
1114
|
-
```
|
|
1115
|
-
|
|
1116
|
-
```javascript {3,7} fileName="vite.config.cjs" codeFormat="commonjs"
|
|
1117
|
-
const { defineConfig } = require("vite");
|
|
1118
|
-
const preact = require("@preact/preset-vite");
|
|
1119
|
-
const { intlayer, intlayerProxy } = require("vite-intlayer");
|
|
1120
|
-
|
|
1121
|
-
// https://vitejs.dev/config/
|
|
1122
|
-
module.exports = defineConfig({
|
|
1123
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1124
|
-
});
|
|
1125
|
-
```
|
|
1126
|
-
|
|
1127
|
-
### (Необязательно) Шаг 8: Изменение URL при смене локали
|
|
802
|
+
### (Необязательно) Шаг 8: Изменяйте URL при смене локали
|
|
1128
803
|
|
|
1129
|
-
Чтобы изменить URL при смене локали, вы можете использовать проп `onLocaleChange`, предоставляемый хуком `useLocale`. Параллельно вы можете использовать `
|
|
804
|
+
Чтобы изменить URL при смене локали, вы можете использовать проп `onLocaleChange`, предоставляемый хуком `useLocale`. Параллельно вы можете использовать метод `route` из `useLocation` библиотеки `preact-iso` для обновления пути URL.
|
|
1130
805
|
|
|
1131
806
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
1132
|
-
import { useLocation
|
|
807
|
+
import { useLocation } from "preact-iso";
|
|
1133
808
|
import {
|
|
1134
809
|
Locales,
|
|
1135
810
|
getHTMLTextDir,
|
|
@@ -1140,16 +815,15 @@ import { useLocale } from "preact-intlayer";
|
|
|
1140
815
|
import type { FunctionalComponent } from "preact";
|
|
1141
816
|
|
|
1142
817
|
const LocaleSwitcher: FunctionalComponent = () => {
|
|
1143
|
-
const
|
|
818
|
+
const { url, route } = useLocation();
|
|
1144
819
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1145
820
|
onLocaleChange: (newLocale) => {
|
|
1146
|
-
|
|
1147
|
-
// Формируем URL с обновлённой локалью
|
|
821
|
+
// Создаем URL с обновленной локалью
|
|
1148
822
|
// Пример: /es/about?foo=bar
|
|
1149
|
-
const pathWithLocale = getLocalizedUrl(
|
|
823
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1150
824
|
|
|
1151
825
|
// Обновляем путь URL
|
|
1152
|
-
route(pathWithLocale, true); // true для замены
|
|
826
|
+
route(pathWithLocale, true); // true для замены (replace)
|
|
1153
827
|
},
|
|
1154
828
|
});
|
|
1155
829
|
|
|
@@ -1159,30 +833,30 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
1159
833
|
<div id="localePopover" popover="auto">
|
|
1160
834
|
{availableLocales.map((localeItem) => (
|
|
1161
835
|
<a
|
|
1162
|
-
href={getLocalizedUrl(
|
|
836
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1163
837
|
hreflang={localeItem}
|
|
1164
838
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1165
839
|
onClick={(e) => {
|
|
1166
840
|
e.preventDefault();
|
|
1167
841
|
setLocale(localeItem);
|
|
1168
|
-
// Программная навигация после
|
|
842
|
+
// Программная навигация после смены локали будет обработана в onLocaleChange
|
|
1169
843
|
}}
|
|
1170
844
|
key={localeItem}
|
|
1171
845
|
>
|
|
1172
846
|
<span>
|
|
1173
|
-
{/* Локаль
|
|
847
|
+
{/* Локаль — например, FR */}
|
|
1174
848
|
{localeItem}
|
|
1175
849
|
</span>
|
|
1176
850
|
<span>
|
|
1177
|
-
{/* Язык на
|
|
851
|
+
{/* Язык на самой локали — например, Français */}
|
|
1178
852
|
{getLocaleName(localeItem, localeItem)}
|
|
1179
853
|
</span>
|
|
1180
854
|
<span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
|
|
1181
|
-
{/* Язык на текущей локали
|
|
855
|
+
{/* Язык на текущей локали — например, Francés, если текущая локаль Locales.SPANISH */}
|
|
1182
856
|
{getLocaleName(localeItem, locale)}
|
|
1183
857
|
</span>
|
|
1184
858
|
<span dir="ltr" lang={Locales.ENGLISH}>
|
|
1185
|
-
{/* Язык на английском
|
|
859
|
+
{/* Язык на английском — например, French */}
|
|
1186
860
|
{getLocaleName(localeItem, Locales.ENGLISH)}
|
|
1187
861
|
</span>
|
|
1188
862
|
</a>
|
|
@@ -1196,7 +870,7 @@ export default LocaleSwitcher;
|
|
|
1196
870
|
```
|
|
1197
871
|
|
|
1198
872
|
```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
|
|
1199
|
-
import { useLocation
|
|
873
|
+
import { useLocation } from "preact-iso";
|
|
1200
874
|
import {
|
|
1201
875
|
Locales,
|
|
1202
876
|
getHTMLTextDir,
|
|
@@ -1204,14 +878,12 @@ import {
|
|
|
1204
878
|
getLocalizedUrl,
|
|
1205
879
|
} from "intlayer";
|
|
1206
880
|
import { useLocale } from "preact-intlayer";
|
|
1207
|
-
import { h } from "preact"; // Для JSX
|
|
1208
881
|
|
|
1209
882
|
const LocaleSwitcher = () => {
|
|
1210
|
-
const
|
|
883
|
+
const { url, route } = useLocation();
|
|
1211
884
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1212
885
|
onLocaleChange: (newLocale) => {
|
|
1213
|
-
const
|
|
1214
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
886
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1215
887
|
route(pathWithLocale, true);
|
|
1216
888
|
},
|
|
1217
889
|
});
|
|
@@ -1222,7 +894,7 @@ const LocaleSwitcher = () => {
|
|
|
1222
894
|
<div id="localePopover" popover="auto">
|
|
1223
895
|
{availableLocales.map((localeItem) => (
|
|
1224
896
|
<a
|
|
1225
|
-
href={getLocalizedUrl(
|
|
897
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1226
898
|
hreflang={localeItem}
|
|
1227
899
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1228
900
|
onClick={(e) => {
|
|
@@ -1250,7 +922,7 @@ export default LocaleSwitcher;
|
|
|
1250
922
|
```
|
|
1251
923
|
|
|
1252
924
|
```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
|
|
1253
|
-
const { useLocation
|
|
925
|
+
const { useLocation } = require("preact-iso");
|
|
1254
926
|
const {
|
|
1255
927
|
Locales,
|
|
1256
928
|
getHTMLTextDir,
|
|
@@ -1258,45 +930,51 @@ const {
|
|
|
1258
930
|
getLocalizedUrl,
|
|
1259
931
|
} = require("intlayer");
|
|
1260
932
|
const { useLocale } = require("preact-intlayer");
|
|
1261
|
-
const { h } = require("preact"); // Для JSX
|
|
1262
933
|
|
|
1263
934
|
const LocaleSwitcher = () => {
|
|
1264
|
-
const
|
|
935
|
+
const { url, route } = useLocation();
|
|
1265
936
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1266
937
|
onLocaleChange: (newLocale) => {
|
|
1267
|
-
const
|
|
1268
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
938
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1269
939
|
route(pathWithLocale, true);
|
|
1270
940
|
},
|
|
1271
941
|
});
|
|
1272
942
|
|
|
1273
|
-
return (
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
943
|
+
return h(
|
|
944
|
+
"div",
|
|
945
|
+
{},
|
|
946
|
+
h("button", { popovertarget: "localePopover" }, getLocaleName(locale)),
|
|
947
|
+
h(
|
|
948
|
+
"div",
|
|
949
|
+
{ id: "localePopover", popover: "auto" },
|
|
950
|
+
availableLocales.map((localeItem) =>
|
|
951
|
+
h(
|
|
952
|
+
"a",
|
|
953
|
+
{
|
|
954
|
+
href: getLocalizedUrl(url, localeItem),
|
|
955
|
+
hreflang: localeItem,
|
|
956
|
+
"aria-current": locale === localeItem ? "page" : undefined,
|
|
957
|
+
onClick: (e) => {
|
|
1283
958
|
e.preventDefault();
|
|
1284
959
|
setLocale(localeItem);
|
|
1285
|
-
}
|
|
1286
|
-
key
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
960
|
+
},
|
|
961
|
+
key: localeItem,
|
|
962
|
+
},
|
|
963
|
+
h("span", {}, localeItem),
|
|
964
|
+
h("span", {}, getLocaleName(localeItem, localeItem)),
|
|
965
|
+
h(
|
|
966
|
+
"span",
|
|
967
|
+
{ dir: getHTMLTextDir(localeItem), lang: localeItem },
|
|
968
|
+
getLocaleName(localeItem, locale)
|
|
969
|
+
),
|
|
970
|
+
h(
|
|
971
|
+
"span",
|
|
972
|
+
{ dir: "ltr", lang: Locales.ENGLISH },
|
|
973
|
+
getLocaleName(localeItem, Locales.ENGLISH)
|
|
974
|
+
)
|
|
975
|
+
)
|
|
976
|
+
)
|
|
977
|
+
)
|
|
1300
978
|
);
|
|
1301
979
|
};
|
|
1302
980
|
|
|
@@ -1305,40 +983,21 @@ module.exports = LocaleSwitcher;
|
|
|
1305
983
|
|
|
1306
984
|
> Ссылки на документацию:
|
|
1307
985
|
>
|
|
1308
|
-
> > - [`useLocale`
|
|
1309
|
-
> > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocaleName.md)
|
|
1310
|
-
> > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocalizedUrl.md)
|
|
1311
|
-
> > - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getHTMLTextDir.md)
|
|
1312
|
-
> > - Атрибут [`hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=ru)
|
|
1313
|
-
> > - Атрибут [`lang`](https://developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/lang)
|
|
1314
|
-
> > - Атрибут [`dir`](https://developer.mozil
|
|
1315
|
-
> > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useLocale.md) (API аналогично для `preact-intlayer`)
|
|
1316
|
-
> > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocaleName.md)
|
|
1317
|
-
> > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocalizedUrl.md)
|
|
1318
|
-
> > - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getHTMLTextDir.md)
|
|
1319
|
-
> > - Атрибут [`hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=ru)
|
|
1320
|
-
> > - Атрибут [`lang`](https://developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/lang)
|
|
1321
|
-
> > - Атрибут [`dir`](https://developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/dir)
|
|
1322
|
-
> > - Атрибут [`aria-current`](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA/Attributes/aria-current)
|
|
1323
|
-
> > - [API Popover](https://developer.mozilla.org/ru/docs/Web/API/Popover_API) la.org/en-US/docs/Web/HTML/Global_attributes/dir)> - [`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)
|
|
1324
|
-
|
|
1325
|
-
Ниже приведён обновлённый **Шаг 9** с дополнительными пояснениями и уточнёнными примерами кода:
|
|
986
|
+
> > - [Хук `useLocale`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/react-intlayer/useLocale.md) (API для `preact-intlayer` аналогично)> - [Хук `getLocaleName`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocaleName.md)> - [Хук `getLocalizedUrl`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getLocalizedUrl.md)> - [Хук `getHTMLTextDir`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/packages/intlayer/getHTMLTextDir.md)> - [Атрибут `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=ru)> - [Атрибут `lang`](https://developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/lang)> - [Атрибут `dir`](https://developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/dir)> - [Атрибут `aria-current`](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA/Attributes/aria-current)> - [Popover API](https://developer.mozilla.org/ru/docs/Web/API/Popover_API)
|
|
1326
987
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
### (Необязательно) Шаг 9: Переключение атрибутов языка и направления в HTML
|
|
988
|
+
### (Необязательно) Шаг 9: Переключайте атрибуты языка и направления HTML
|
|
1330
989
|
|
|
1331
990
|
Когда ваше приложение поддерживает несколько языков, крайне важно обновлять атрибуты `lang` и `dir` тега `<html>`, чтобы они соответствовали текущей локали. Это обеспечивает:
|
|
1332
991
|
|
|
1333
|
-
- **Доступность**: Экранные
|
|
1334
|
-
- **Отображение текста**: Атрибут `dir` (
|
|
1335
|
-
- **SEO**: Поисковые системы используют атрибут `lang` для определения языка вашей страницы,
|
|
992
|
+
- **Доступность**: Экранные дикторы и вспомогательные технологии полагаются на правильный атрибут `lang` для точного произношения и интерпретации контента.
|
|
993
|
+
- **Отображение текста**: Атрибут `dir` (direction) гарантирует, что текст отображается в правильном порядке (например, слева направо для английского, справа налево для арабского или иврита), что важно для удобочитаемости.
|
|
994
|
+
- **SEO**: Поисковые системы используют атрибут `lang` для определения языка вашей страницы, помогая показывать правильный локализованный контент в результатах поиска.
|
|
1336
995
|
|
|
1337
|
-
Обновляя эти атрибуты динамически при
|
|
996
|
+
Обновляя эти атрибуты динамически при изменении локали, вы гарантируете согласованный и доступный опыт для пользователей на всех поддерживаемых языках.
|
|
1338
997
|
|
|
1339
998
|
#### Реализация хука
|
|
1340
999
|
|
|
1341
|
-
Создайте пользовательский хук для управления атрибутами HTML. Хук
|
|
1000
|
+
Создайте пользовательский хук для управления атрибутами HTML. Хук прослушивает изменения локали и соответствующим образом обновляет атрибуты:
|
|
1342
1001
|
|
|
1343
1002
|
```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx" codeFormat="typescript"
|
|
1344
1003
|
import { useEffect } from "preact/hooks";
|
|
@@ -1346,11 +1005,11 @@ import { useLocale } from "preact-intlayer";
|
|
|
1346
1005
|
import { getHTMLTextDir } from "intlayer";
|
|
1347
1006
|
|
|
1348
1007
|
/**
|
|
1349
|
-
* Обновляет атрибуты `lang` и `dir`
|
|
1008
|
+
* Обновляет атрибуты `lang` и `dir` HTML-элемента <html> на основе текущей локали.
|
|
1350
1009
|
* - `lang`: Информирует браузеры и поисковые системы о языке страницы.
|
|
1351
1010
|
* - `dir`: Обеспечивает правильный порядок чтения (например, 'ltr' для английского, 'rtl' для арабского).
|
|
1352
1011
|
*
|
|
1353
|
-
*
|
|
1012
|
+
* Это динамическое обновление необходимо для правильного отображения текста, доступности и SEO.
|
|
1354
1013
|
*/
|
|
1355
1014
|
export const useI18nHTMLAttributes = () => {
|
|
1356
1015
|
const { locale } = useLocale();
|
|
@@ -1359,7 +1018,7 @@ export const useI18nHTMLAttributes = () => {
|
|
|
1359
1018
|
// Обновляет атрибут языка на текущую локаль.
|
|
1360
1019
|
document.documentElement.lang = locale;
|
|
1361
1020
|
|
|
1362
|
-
// Устанавливает направление текста
|
|
1021
|
+
// Устанавливает направление текста на основе текущей локали.
|
|
1363
1022
|
document.documentElement.dir = getHTMLTextDir(locale);
|
|
1364
1023
|
}, [locale]);
|
|
1365
1024
|
};
|
|
@@ -1371,7 +1030,7 @@ import { useLocale } from "preact-intlayer";
|
|
|
1371
1030
|
import { getHTMLTextDir } from "intlayer";
|
|
1372
1031
|
|
|
1373
1032
|
/**
|
|
1374
|
-
* Обновляет атрибуты `lang` и `dir`
|
|
1033
|
+
* Обновляет атрибуты `lang` и `dir` HTML-элемента <html> на основе текущей локали.
|
|
1375
1034
|
*/
|
|
1376
1035
|
export const useI18nHTMLAttributes = () => {
|
|
1377
1036
|
const { locale } = useLocale();
|
|
@@ -1389,7 +1048,7 @@ const { useLocale } = require("preact-intlayer");
|
|
|
1389
1048
|
const { getHTMLTextDir } = require("intlayer");
|
|
1390
1049
|
|
|
1391
1050
|
/**
|
|
1392
|
-
* Обновляет атрибуты `lang` и `dir`
|
|
1051
|
+
* Обновляет атрибуты `lang` и `dir` HTML-элемента <html> на основе текущей локали.
|
|
1393
1052
|
*/
|
|
1394
1053
|
const useI18nHTMLAttributes = () => {
|
|
1395
1054
|
const { locale } = useLocale();
|
|
@@ -1405,7 +1064,7 @@ module.exports = { useI18nHTMLAttributes };
|
|
|
1405
1064
|
|
|
1406
1065
|
#### Использование хука в вашем приложении
|
|
1407
1066
|
|
|
1408
|
-
Интегрируйте хук в
|
|
1067
|
+
Интегрируйте хук в свой основной компонент, чтобы атрибуты HTML обновлялись при каждом изменении локали:
|
|
1409
1068
|
|
|
1410
1069
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1411
1070
|
import type { FunctionalComponent } from "preact";
|
|
@@ -1418,7 +1077,7 @@ const AppWithHooks: FunctionalComponent = () => {
|
|
|
1418
1077
|
// Применяем хук для обновления атрибутов lang и dir тега <html> в зависимости от локали.
|
|
1419
1078
|
useI18nHTMLAttributes();
|
|
1420
1079
|
|
|
1421
|
-
// Предполагается, что AppContent
|
|
1080
|
+
// Предполагается, что AppContent — это ваш основной компонент отображения контента из Шага 5
|
|
1422
1081
|
return <AppContent />;
|
|
1423
1082
|
};
|
|
1424
1083
|
|
|
@@ -1471,34 +1130,26 @@ const App = () => (
|
|
|
1471
1130
|
module.exports = App;
|
|
1472
1131
|
```
|
|
1473
1132
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
- Обеспечивать корректное отражение текущей локали в атрибуте **языка** (`lang`), что важно для SEO и поведения браузера.
|
|
1477
|
-
- Настраивать **направление текста** (`dir`) в соответствии с локалью, улучшая читаемость и удобство использования для языков с разным порядком чтения.
|
|
1478
|
-
- Обеспечить более **доступный** опыт, так как вспомогательные технологии зависят от этих атрибутов для оптимальной работы.
|
|
1133
|
+
### (Необязательно) Шаг 10: Создание компонента локализованной ссылки
|
|
1479
1134
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
Чтобы гарантировать, что навигация вашего приложения учитывает текущую локаль, вы можете создать пользовательский компонент `Link`. Этот компонент автоматически добавляет префикс текущего языка к внутренним URL.
|
|
1135
|
+
Чтобы навигация в вашем приложении учитывала текущую локаль, вы можете создать пользовательский компонент `Link`. Этот компонент автоматически добавляет префикс текущего языка к внутренним URL.
|
|
1483
1136
|
|
|
1484
1137
|
Это поведение полезно по нескольким причинам:
|
|
1485
1138
|
|
|
1486
|
-
- **SEO и пользовательский опыт**: Локализованные URL помогают поисковым системам правильно индексировать страницы на разных языках и
|
|
1487
|
-
- **Последовательность**: Используя локализованную ссылку во всем приложении, вы гарантируете, что навигация
|
|
1139
|
+
- **SEO и пользовательский опыт**: Локализованные URL помогают поисковым системам правильно индексировать страницы на разных языках и предоставляют пользователям контент на их предпочтительном языке.
|
|
1140
|
+
- **Последовательность**: Используя локализованную ссылку во всем приложении, вы гарантируете, что навигация остается в пределах текущей локали, предотвращая неожиданные переключения языка.
|
|
1488
1141
|
- **Поддерживаемость**: Централизация логики локализации в одном компоненте упрощает управление URL.
|
|
1489
1142
|
|
|
1490
|
-
|
|
1143
|
+
Ниже приведена реализация компонента локализованной ссылки `Link` в Preact:
|
|
1491
1144
|
|
|
1492
|
-
```tsx fileName="src/components/
|
|
1145
|
+
```tsx fileName="src/components/Link.tsx" codeFormat="typescript"
|
|
1493
1146
|
import { getLocalizedUrl } from "intlayer";
|
|
1494
|
-
import { useLocale
|
|
1495
|
-
|
|
1496
|
-
import type { JSX } from "preact";
|
|
1497
|
-
import { forwardRef } from "preact/compat"; // Для передачи ref
|
|
1147
|
+
import { useLocale } from "preact-intlayer";
|
|
1148
|
+
import { forwardRef } from "preact/compat";
|
|
1149
|
+
import type { JSX } from "preact";
|
|
1498
1150
|
|
|
1499
|
-
export interface
|
|
1151
|
+
export interface LinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
|
|
1500
1152
|
href: string;
|
|
1501
|
-
replace?: boolean; // Необязательно: для замены состояния истории
|
|
1502
1153
|
}
|
|
1503
1154
|
|
|
1504
1155
|
/**
|
|
@@ -1509,173 +1160,158 @@ export const checkIsExternalLink = (href?: string): boolean =>
|
|
|
1509
1160
|
/^https?:\/\//.test(href ?? "");
|
|
1510
1161
|
|
|
1511
1162
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
* Для внутренних ссылок
|
|
1514
|
-
* Это гарантирует, что навигация
|
|
1515
|
-
* Используется стандартный тег <a>, но может инициировать навигацию на стороне клиента с помощью `route` из preact-iso.
|
|
1163
|
+
* Пользовательский компонент Link, который адаптирует атрибут href в зависимости от текущей локали.
|
|
1164
|
+
* Для внутренних ссылок он использует `getLocalizedUrl`, чтобы добавить префикс локали к URL (например, /fr/about).
|
|
1165
|
+
* Это гарантирует, что навигация остается в контексте той же локали.
|
|
1516
1166
|
*/
|
|
1517
|
-
export const
|
|
1518
|
-
({ href, children,
|
|
1167
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
1168
|
+
({ href, children, ...props }, ref) => {
|
|
1519
1169
|
const { locale } = useLocale();
|
|
1520
|
-
const location = useLocation(); // из preact-iso
|
|
1521
1170
|
const isExternalLink = checkIsExternalLink(href);
|
|
1522
1171
|
|
|
1172
|
+
// Если ссылка внутренняя и предоставлен валидный href, получаем локализованный URL.
|
|
1523
1173
|
const hrefI18n =
|
|
1524
1174
|
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1525
1175
|
|
|
1526
|
-
const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
|
|
1527
|
-
if (onClick) {
|
|
1528
|
-
onClick(event);
|
|
1529
|
-
}
|
|
1530
|
-
if (
|
|
1531
|
-
!isExternalLink &&
|
|
1532
|
-
href && // Убедиться, что href определён
|
|
1533
|
-
event.button === 0 && // Левая кнопка мыши
|
|
1534
|
-
!event.metaKey &&
|
|
1535
|
-
!event.ctrlKey &&
|
|
1536
|
-
!event.shiftKey &&
|
|
1537
|
-
!event.altKey && // Проверка стандартных модификаторов
|
|
1538
|
-
!props.target // Не открывать в новой вкладке/окне
|
|
1539
|
-
) {
|
|
1540
|
-
event.preventDefault();
|
|
1541
|
-
if (location.url !== hrefI18n) {
|
|
1542
|
-
// Переходить только если URL отличается
|
|
1543
|
-
route(hrefI18n, replace); // Использовать route из preact-iso
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
};
|
|
1547
|
-
|
|
1548
1176
|
return (
|
|
1549
|
-
<a href={hrefI18n} ref={ref}
|
|
1177
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1550
1178
|
{children}
|
|
1551
1179
|
</a>
|
|
1552
1180
|
);
|
|
1553
1181
|
}
|
|
1554
1182
|
);
|
|
1183
|
+
|
|
1184
|
+
Link.displayName = "Link";
|
|
1555
1185
|
```
|
|
1556
1186
|
|
|
1557
|
-
```jsx fileName="src/components/
|
|
1187
|
+
```jsx fileName="src/components/Link.jsx" codeFormat="esm"
|
|
1558
1188
|
import { getLocalizedUrl } from "intlayer";
|
|
1559
1189
|
import { useLocale } from "preact-intlayer";
|
|
1560
|
-
import { useLocation, route } from "preact-iso"; // Импорт из preact-iso
|
|
1561
1190
|
import { forwardRef } from "preact/compat";
|
|
1562
|
-
import { h } from "preact"; // Для JSX
|
|
1563
1191
|
|
|
1192
|
+
/**
|
|
1193
|
+
* Вспомогательная функция для проверки, является ли данный URL внешним.
|
|
1194
|
+
* Если URL начинается с http:// или https://, он считается внешним.
|
|
1195
|
+
*/
|
|
1564
1196
|
export const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1565
1197
|
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1198
|
+
/**
|
|
1199
|
+
* Пользовательский компонент Link, который адаптирует атрибут href в зависимости от текущей локали.
|
|
1200
|
+
* Для внутренних ссылок он использует `getLocalizedUrl`, чтобы добавить префикс локали к URL (например, /fr/about).
|
|
1201
|
+
* Это гарантирует, что навигация остается в контексте той же локали.
|
|
1202
|
+
*/
|
|
1203
|
+
export const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1204
|
+
const { locale } = useLocale();
|
|
1205
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1571
1206
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1207
|
+
// Если ссылка внутренняя и предоставлен валидный href, получаем локализованный URL.
|
|
1208
|
+
const hrefI18n =
|
|
1209
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1574
1210
|
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
href &&
|
|
1582
|
-
event.button === 0 &&
|
|
1583
|
-
!event.metaKey &&
|
|
1584
|
-
!event.ctrlKey &&
|
|
1585
|
-
!event.shiftKey &&
|
|
1586
|
-
!event.altKey &&
|
|
1587
|
-
!props.target
|
|
1588
|
-
) {
|
|
1589
|
-
event.preventDefault();
|
|
1590
|
-
if (location.url !== hrefI18n) {
|
|
1591
|
-
route(hrefI18n, replace);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
};
|
|
1211
|
+
return (
|
|
1212
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1213
|
+
{children}
|
|
1214
|
+
</a>
|
|
1215
|
+
);
|
|
1216
|
+
});
|
|
1595
1217
|
|
|
1596
|
-
|
|
1597
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1598
|
-
{children}
|
|
1599
|
-
</a>
|
|
1600
|
-
);
|
|
1601
|
-
}
|
|
1602
|
-
);
|
|
1218
|
+
Link.displayName = "Link";
|
|
1603
1219
|
```
|
|
1604
1220
|
|
|
1605
|
-
```jsx fileName="src/components/
|
|
1221
|
+
```jsx fileName="src/components/Link.cjsx" codeFormat="commonjs"
|
|
1606
1222
|
const { getLocalizedUrl } = require("intlayer");
|
|
1607
1223
|
const { useLocale } = require("preact-intlayer");
|
|
1608
|
-
const { useLocation, route } = require("preact-iso"); // Импорт из preact-iso
|
|
1609
1224
|
const { forwardRef } = require("preact/compat");
|
|
1610
|
-
const { h } = require("preact"); // Для JSX
|
|
1611
1225
|
|
|
1226
|
+
/**
|
|
1227
|
+
* Вспомогательная функция для проверки, является ли данный URL внешним.
|
|
1228
|
+
* Если URL начинается с http:// или https://, он считается внешним.
|
|
1229
|
+
*/
|
|
1612
1230
|
const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1613
1231
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
!props.target
|
|
1638
|
-
) {
|
|
1639
|
-
event.preventDefault();
|
|
1640
|
-
if (location.url !== hrefI18n) {
|
|
1641
|
-
route(hrefI18n, replace);
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
};
|
|
1232
|
+
/**
|
|
1233
|
+
* Пользовательский компонент Link, который адаптирует атрибут href в зависимости от текущей локали.
|
|
1234
|
+
* Для внутренних ссылок он использует `getLocalizedUrl`, чтобы добавить префикс локали к URL (например, /fr/about).
|
|
1235
|
+
* Это гарантирует, что навигация остается в контексте той же локали.
|
|
1236
|
+
*/
|
|
1237
|
+
const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1238
|
+
const { locale } = useLocale();
|
|
1239
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1240
|
+
|
|
1241
|
+
// Если ссылка внутренняя и предоставлен валидный href, получаем локализованный URL.
|
|
1242
|
+
const hrefI18n =
|
|
1243
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1244
|
+
|
|
1245
|
+
return h(
|
|
1246
|
+
"a",
|
|
1247
|
+
{
|
|
1248
|
+
href: hrefI18n,
|
|
1249
|
+
ref: ref,
|
|
1250
|
+
...props,
|
|
1251
|
+
},
|
|
1252
|
+
children
|
|
1253
|
+
);
|
|
1254
|
+
});
|
|
1645
1255
|
|
|
1646
|
-
|
|
1647
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1648
|
-
{children}
|
|
1649
|
-
</a>
|
|
1650
|
-
);
|
|
1651
|
-
}
|
|
1652
|
-
);
|
|
1256
|
+
Link.displayName = "Link";
|
|
1653
1257
|
|
|
1654
|
-
module.exports = {
|
|
1258
|
+
module.exports = { Link, checkIsExternalLink };
|
|
1655
1259
|
```
|
|
1656
1260
|
|
|
1657
1261
|
#### Как это работает
|
|
1658
1262
|
|
|
1659
1263
|
- **Определение внешних ссылок**:
|
|
1660
|
-
Вспомогательная функция `checkIsExternalLink` определяет, является ли URL внешним. Внешние ссылки остаются без
|
|
1264
|
+
Вспомогательная функция `checkIsExternalLink` определяет, является ли URL внешним. Внешние ссылки остаются без изменений, так как они не нуждаются в локализации.
|
|
1661
1265
|
- **Получение текущей локали**:
|
|
1662
|
-
Хук `useLocale` предоставляет текущую
|
|
1266
|
+
Хук `useLocale` предоставляет текущую локаль (например, `fr` для французского).
|
|
1663
1267
|
- **Локализация URL**:
|
|
1664
|
-
Для внутренних ссылок
|
|
1665
|
-
- **Навигация на стороне клиента**:
|
|
1666
|
-
Функция `handleClick` проверяет, является ли ссылка внутренней и нужно ли предотвратить стандартную навигацию. Если да, она использует функцию `route` из `preact-iso` (полученную через `useLocation` или импортированную напрямую) для выполнения навигации на стороне клиента. Это обеспечивает поведение, похожее на SPA, без полной перезагрузки страницы.
|
|
1268
|
+
Для внутренних ссылок (т. е. не внешних) используется `getLocalizedUrl` для автоматического добавления префикса текущей локали к URL. Это означает, что если ваш пользователь использует французский язык, передача `/about` в качестве `href` преобразует его в `/fr/about`.
|
|
1667
1269
|
- **Возврат ссылки**:
|
|
1668
|
-
Компонент возвращает элемент `<a>` с локализованным URL
|
|
1270
|
+
Компонент возвращает элемент `<a>` с локализованным URL, гарантируя, что навигация соответствует локали.
|
|
1271
|
+
|
|
1272
|
+
### (Необязательно) Шаг 11: Рендеринг Markdown и HTML
|
|
1273
|
+
|
|
1274
|
+
Intlayer поддерживает рендеринг контента в форматах Markdown и HTML в Preact.
|
|
1275
|
+
|
|
1276
|
+
Вы можете настроить рендеринг контента Markdown и HTML с помощью метода `.use()`. Этот метод позволяет переопределить стандартный рендеринг определенных тегов.
|
|
1277
|
+
|
|
1278
|
+
```tsx
|
|
1279
|
+
import { useIntlayer } from "preact-intlayer";
|
|
1280
|
+
|
|
1281
|
+
const { myMarkdownContent, myHtmlContent } = useIntlayer("my-component");
|
|
1282
|
+
|
|
1283
|
+
// ...
|
|
1284
|
+
|
|
1285
|
+
return (
|
|
1286
|
+
<div>
|
|
1287
|
+
{/* Базовый рендеринг */}
|
|
1288
|
+
{myMarkdownContent}
|
|
1289
|
+
|
|
1290
|
+
{/* Пользовательский рендеринг для Markdown */}
|
|
1291
|
+
{myMarkdownContent.use({
|
|
1292
|
+
h1: (props) => <h1 style={{ color: "red" }} {...props} />,
|
|
1293
|
+
})}
|
|
1294
|
+
|
|
1295
|
+
{/* Базовый рендеринг для HTML */}
|
|
1296
|
+
{myHtmlContent}
|
|
1297
|
+
|
|
1298
|
+
{/* Пользовательский рендеринг для HTML */}
|
|
1299
|
+
{myHtmlContent.use({
|
|
1300
|
+
b: (props) => <strong style={{ color: "blue" }} {...props} />,
|
|
1301
|
+
})}
|
|
1302
|
+
</div>
|
|
1303
|
+
);
|
|
1304
|
+
```
|
|
1669
1305
|
|
|
1670
1306
|
### Настройка TypeScript
|
|
1671
1307
|
|
|
1672
|
-
Intlayer использует расширение модулей (module augmentation)
|
|
1308
|
+
Intlayer использует расширение модулей (module augmentation) для получения преимуществ TypeScript и усиления вашей кодовой базы.
|
|
1673
1309
|
|
|
1674
1310
|

|
|
1675
1311
|
|
|
1676
1312
|

|
|
1677
1313
|
|
|
1678
|
-
Убедитесь, что ваша конфигурация TypeScript включает автоматически
|
|
1314
|
+
Убедитесь, что ваша конфигурация TypeScript включает автоматически генерируемые типы.
|
|
1679
1315
|
|
|
1680
1316
|
```json5 fileName="tsconfig.json"
|
|
1681
1317
|
{
|
|
@@ -1688,43 +1324,43 @@ Intlayer использует расширение модулей (module augmen
|
|
|
1688
1324
|
},
|
|
1689
1325
|
"include": [
|
|
1690
1326
|
// ... Ваши существующие конфигурации TypeScript
|
|
1691
|
-
".intlayer/**/*.ts", // Включить автоматически
|
|
1327
|
+
".intlayer/**/*.ts", // Включить автоматически генерируемые типы
|
|
1692
1328
|
],
|
|
1693
1329
|
}
|
|
1694
1330
|
```
|
|
1695
1331
|
|
|
1696
|
-
> Убедитесь, что ваш `tsconfig.json` настроен для Preact, особенно
|
|
1332
|
+
> Убедитесь, что ваш `tsconfig.json` настроен для Preact, особенно `jsx` и `jsxImportSource` или `jsxFactory`/`jsxFragmentFactory` для старых версий Preact, если вы не используете настройки по умолчанию `preset-vite`.
|
|
1697
1333
|
|
|
1698
1334
|
### Конфигурация Git
|
|
1699
1335
|
|
|
1700
|
-
Рекомендуется игнорировать файлы,
|
|
1336
|
+
Рекомендуется игнорировать файлы, генерируемые Intlayer. Это позволит избежать их фиксации в вашем Git-репозитории.
|
|
1701
1337
|
|
|
1702
|
-
|
|
1338
|
+
Для этого вы можете добавить следующие инструкции в ваш файл `.gitignore`:
|
|
1703
1339
|
|
|
1704
1340
|
```plaintext
|
|
1705
|
-
# Игнорировать файлы,
|
|
1341
|
+
# Игнорировать файлы, генерируемые Intlayer
|
|
1706
1342
|
.intlayer
|
|
1707
1343
|
```
|
|
1708
1344
|
|
|
1709
1345
|
### Расширение VS Code
|
|
1710
1346
|
|
|
1711
|
-
Для улучшения
|
|
1347
|
+
Для улучшения опыта разработки с Intlayer вы можете установить официальное **расширение Intlayer для VS Code**.
|
|
1712
1348
|
|
|
1713
|
-
[Установить из
|
|
1349
|
+
[Установить из VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
1714
1350
|
|
|
1715
1351
|
Это расширение предоставляет:
|
|
1716
1352
|
|
|
1717
|
-
-
|
|
1353
|
+
- **Автодополнение** ключей перевода.
|
|
1718
1354
|
- **Обнаружение ошибок в реальном времени** для отсутствующих переводов.
|
|
1719
|
-
- **Встроенный
|
|
1355
|
+
- **Встроенный предпросмотр** переведенного контента.
|
|
1720
1356
|
- **Быстрые действия** для удобного создания и обновления переводов.
|
|
1721
1357
|
|
|
1722
|
-
Для получения
|
|
1358
|
+
Для получения более подробной информации о том, как использовать расширение, обратитесь к [документации по расширению Intlayer для VS Code](https://intlayer.org/doc/vs-code-extension).
|
|
1723
1359
|
|
|
1724
1360
|
---
|
|
1725
1361
|
|
|
1726
|
-
###
|
|
1362
|
+
### Продвигайтесь дальше
|
|
1727
1363
|
|
|
1728
|
-
|
|
1364
|
+
Чтобы продвинуться дальше, вы можете реализовать [визуальный редактор](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_visual_editor.md) или вынести ваш контент вовне с помощью [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_CMS.md).
|
|
1729
1365
|
|
|
1730
1366
|
---
|