@intlayer/docs 8.6.10 → 8.7.0-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.
Files changed (129) hide show
  1. package/blog/ar/i18n_using_next-i18next.md +1 -1
  2. package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  3. package/blog/de/i18n_using_next-i18next.md +1 -1
  4. package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  5. package/blog/en/i18n_using_next-i18next.md +1 -1
  6. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  7. package/blog/en-GB/i18n_using_next-i18next.md +1 -1
  8. package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  9. package/blog/es/i18n_using_next-i18next.md +1 -1
  10. package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  11. package/blog/fr/i18n_using_next-i18next.md +1 -1
  12. package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  13. package/blog/hi/i18n_using_next-i18next.md +1 -1
  14. package/blog/id/i18n_using_next-i18next.md +1 -1
  15. package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  16. package/blog/it/i18n_using_next-i18next.md +1 -1
  17. package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  18. package/blog/ja/i18n_using_next-i18next.md +1 -1
  19. package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  20. package/blog/ko/i18n_using_next-i18next.md +1 -1
  21. package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  22. package/blog/pl/i18n_using_next-i18next.md +1 -1
  23. package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  24. package/blog/pt/i18n_using_next-i18next.md +1 -1
  25. package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  26. package/blog/ru/i18n_using_next-i18next.md +1 -1
  27. package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  28. package/blog/tr/i18n_using_next-i18next.md +1 -1
  29. package/blog/uk/i18n_using_next-i18next.md +1 -1
  30. package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  31. package/blog/vi/i18n_using_next-i18next.md +1 -1
  32. package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +2 -2
  33. package/blog/zh/i18n_using_next-i18next.md +1 -1
  34. package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  35. package/docs/ar/bundle_optimization.md +454 -0
  36. package/docs/ar/intlayer_with_next-i18next.md +1 -1
  37. package/docs/ar/intlayer_with_next-intl.md +1 -1
  38. package/docs/ar/intlayer_with_tanstack+solid.md +24 -5
  39. package/docs/ar/intlayer_with_tanstack.md +45 -68
  40. package/docs/bn/bundle_optimization.md +454 -0
  41. package/docs/cs/bundle_optimization.md +454 -0
  42. package/docs/de/bundle_optimization.md +454 -0
  43. package/docs/de/intlayer_with_next-i18next.md +1 -1
  44. package/docs/de/intlayer_with_next-intl.md +1 -1
  45. package/docs/de/intlayer_with_tanstack+solid.md +24 -5
  46. package/docs/de/intlayer_with_tanstack.md +45 -68
  47. package/docs/en/bundle_optimization.md +36 -8
  48. package/docs/en/intlayer_with_next-i18next.md +1 -1
  49. package/docs/en/intlayer_with_next-intl.md +1 -1
  50. package/docs/en/intlayer_with_tanstack+solid.md +24 -5
  51. package/docs/en/intlayer_with_tanstack.md +45 -68
  52. package/docs/en-GB/bundle_optimization.md +454 -0
  53. package/docs/en-GB/intlayer_with_next-i18next.md +1 -1
  54. package/docs/en-GB/intlayer_with_next-intl.md +1 -1
  55. package/docs/en-GB/intlayer_with_tanstack+solid.md +24 -5
  56. package/docs/en-GB/intlayer_with_tanstack.md +47 -70
  57. package/docs/es/bundle_optimization.md +454 -0
  58. package/docs/es/intlayer_with_next-i18next.md +1 -1
  59. package/docs/es/intlayer_with_next-intl.md +1 -1
  60. package/docs/es/intlayer_with_tanstack+solid.md +24 -5
  61. package/docs/es/intlayer_with_tanstack.md +45 -68
  62. package/docs/fr/bundle_optimization.md +454 -0
  63. package/docs/fr/intlayer_with_next-i18next.md +1 -1
  64. package/docs/fr/intlayer_with_next-intl.md +1 -1
  65. package/docs/fr/intlayer_with_tanstack+solid.md +24 -5
  66. package/docs/fr/intlayer_with_tanstack.md +45 -68
  67. package/docs/hi/bundle_optimization.md +454 -0
  68. package/docs/hi/intlayer_with_next-i18next.md +1 -1
  69. package/docs/hi/intlayer_with_next-intl.md +1 -1
  70. package/docs/hi/intlayer_with_tanstack+solid.md +24 -5
  71. package/docs/hi/intlayer_with_tanstack.md +45 -68
  72. package/docs/id/bundle_optimization.md +454 -0
  73. package/docs/id/intlayer_with_next-i18next.md +1 -1
  74. package/docs/id/intlayer_with_next-intl.md +1 -1
  75. package/docs/id/intlayer_with_tanstack+solid.md +24 -5
  76. package/docs/id/intlayer_with_tanstack.md +45 -68
  77. package/docs/it/bundle_optimization.md +454 -0
  78. package/docs/it/intlayer_with_next-i18next.md +1 -1
  79. package/docs/it/intlayer_with_next-intl.md +1 -1
  80. package/docs/it/intlayer_with_tanstack+solid.md +24 -5
  81. package/docs/it/intlayer_with_tanstack.md +45 -68
  82. package/docs/ja/bundle_optimization.md +454 -0
  83. package/docs/ja/intlayer_with_next-i18next.md +1 -1
  84. package/docs/ja/intlayer_with_next-intl.md +1 -1
  85. package/docs/ja/intlayer_with_tanstack+solid.md +24 -5
  86. package/docs/ja/intlayer_with_tanstack.md +45 -36
  87. package/docs/ko/bundle_optimization.md +454 -0
  88. package/docs/ko/intlayer_with_next-i18next.md +1 -1
  89. package/docs/ko/intlayer_with_next-intl.md +1 -1
  90. package/docs/ko/intlayer_with_tanstack+solid.md +24 -5
  91. package/docs/ko/intlayer_with_tanstack.md +45 -68
  92. package/docs/nl/bundle_optimization.md +454 -0
  93. package/docs/pl/bundle_optimization.md +454 -0
  94. package/docs/pl/intlayer_with_next-i18next.md +1 -1
  95. package/docs/pl/intlayer_with_next-intl.md +1 -1
  96. package/docs/pl/intlayer_with_tanstack+solid.md +24 -5
  97. package/docs/pl/intlayer_with_tanstack.md +45 -68
  98. package/docs/pt/bundle_optimization.md +454 -0
  99. package/docs/pt/intlayer_with_next-i18next.md +1 -1
  100. package/docs/pt/intlayer_with_next-intl.md +1 -1
  101. package/docs/pt/intlayer_with_tanstack+solid.md +24 -5
  102. package/docs/pt/intlayer_with_tanstack.md +45 -68
  103. package/docs/ru/bundle_optimization.md +454 -0
  104. package/docs/ru/intlayer_with_next-i18next.md +1 -1
  105. package/docs/ru/intlayer_with_next-intl.md +1 -1
  106. package/docs/ru/intlayer_with_tanstack+solid.md +24 -5
  107. package/docs/ru/intlayer_with_tanstack.md +45 -68
  108. package/docs/tr/bundle_optimization.md +454 -0
  109. package/docs/tr/intlayer_with_next-i18next.md +1 -1
  110. package/docs/tr/intlayer_with_next-intl.md +1 -1
  111. package/docs/tr/intlayer_with_tanstack+solid.md +24 -5
  112. package/docs/tr/intlayer_with_tanstack.md +45 -68
  113. package/docs/uk/bundle_optimization.md +454 -0
  114. package/docs/uk/intlayer_with_next-i18next.md +1 -1
  115. package/docs/uk/intlayer_with_next-intl.md +1 -1
  116. package/docs/uk/intlayer_with_tanstack+solid.md +24 -5
  117. package/docs/uk/intlayer_with_tanstack.md +45 -68
  118. package/docs/ur/bundle_optimization.md +454 -0
  119. package/docs/vi/bundle_optimization.md +454 -0
  120. package/docs/vi/intlayer_with_next-i18next.md +1 -1
  121. package/docs/vi/intlayer_with_next-intl.md +1 -1
  122. package/docs/vi/intlayer_with_tanstack+solid.md +24 -5
  123. package/docs/vi/intlayer_with_tanstack.md +45 -68
  124. package/docs/zh/bundle_optimization.md +454 -0
  125. package/docs/zh/intlayer_with_next-i18next.md +1 -1
  126. package/docs/zh/intlayer_with_next-intl.md +1 -1
  127. package/docs/zh/intlayer_with_tanstack+solid.md +24 -5
  128. package/docs/zh/intlayer_with_tanstack.md +45 -68
  129. package/package.json +7 -7
@@ -0,0 +1,454 @@
1
+ ---
2
+ createdAt: 2025-11-25
3
+ updatedAt: 2026-04-08
4
+ title: Оптимизация размера бандла i18n и производительности
5
+ description: Уменьшите размер бандла вашего приложения, оптимизируя контент интернационализации (i18n). Узнайте, как использовать tree shaking и lazy loading для словарей с помощью Intlayer.
6
+ keywords:
7
+ - Оптимизация бандла
8
+ - Автоматизация контента
9
+ - Динамический контент
10
+ - Intlayer
11
+ - Next.js
12
+ - JavaScript
13
+ - React
14
+ slugs:
15
+ - doc
16
+ - concept
17
+ - bundle-optimization
18
+ history:
19
+ - version: 8.7.0
20
+ date: 2026-04-08
21
+ changes: "Добавлены опции `minify` и `purge` в конфигурацию сборки"
22
+ ---
23
+
24
+ # Оптимизация размера бандла i18n и производительности
25
+
26
+ Одной из наиболее распространенных проблем традиционных i18n-решений, полагающихся на JSON-файлы, является управление размером контента. Если разработчики вручную не разделяют контент на пространства имен (namespaces), пользователи часто скачивают переводы для каждой страницы и, возможно, для каждого языка только для того, чтобы просмотреть одну страницу.
27
+
28
+ Например, приложение с 10 страницами, переведенными на 10 языков, может привести к тому, что пользователь скачает контент 100 страниц, хотя ему нужна только **одна** (текущая страница на текущем языке). Это ведет к напрасной трате трафика и замедлению времени загрузки.
29
+
30
+ **Intlayer решает эту проблему с помощью оптимизации на этапе сборки.** Он анализирует ваш код, чтобы определить, какие словари действительно используются в каждом компоненте, и внедряет только необходимый контент в ваш бандл.
31
+
32
+ ## Содержание
33
+
34
+ <TOC />
35
+
36
+ ## Сканирование бандла
37
+
38
+ Анализ бандла — это первый шаг к выявлению "тяжелых" JSON-файлов и возможностей разделения кода. Эти инструменты генерируют визуальную древовидную карту (treemap) скомпилированного кода вашего приложения, позволяя вам точно увидеть, какие библиотеки занимают больше всего места.
39
+
40
+ <Tabs>
41
+ <Tab value="vite">
42
+
43
+ ### Vite / Rollup
44
+
45
+ Vite использует Rollup под капотом. Плагин `rollup-plugin-visualizer` генерирует интерактивный HTML-файл, показывающий размер каждого модуля в вашем графе.
46
+
47
+ ```bash
48
+ npm install -D rollup-plugin-visualizer
49
+ ```
50
+
51
+ ```typescript fileName="vite.config.ts"
52
+ import { defineConfig } from "vite";
53
+ import { visualizer } from "rollup-plugin-visualizer";
54
+
55
+ export default defineConfig({
56
+ plugins: [
57
+ visualizer({
58
+ open: true, // Автоматически открыть отчет в браузере
59
+ filename: "stats.html",
60
+ gzipSize: true,
61
+ brotliSize: true,
62
+ }),
63
+ ],
64
+ });
65
+ ```
66
+
67
+ </Tab>
68
+ <Tab value="nextjs (turbopack)">
69
+
70
+ ### Next.js (Turbopack)
71
+
72
+ Для проектов, использующих App Router и Turbopack, Next.js предоставляет встроенный экспериментальный анализатор, не требующий дополнительных зависимостей.
73
+
74
+ ```bash packageManager='npm'
75
+ npx next experimental-analyze
76
+ ```
77
+
78
+ ```bash packageManager='yarn'
79
+ yarn next experimental-analyze
80
+ ```
81
+
82
+ ```bash packageManager='pnpm'
83
+ pnpm next experimental-analyze
84
+ ```
85
+
86
+ ```bash packageManager='bun'
87
+ bun next experimental-analyze
88
+ ```
89
+
90
+ </Tab>
91
+ <Tab value="nextjs (Webpack)">
92
+
93
+ ### Next.js (Webpack)
94
+
95
+ Если вы используете стандартный сборщик Webpack в Next.js, используйте официальный анализатор бандлов. Запустите его, установив переменную окружения во время сборки.
96
+
97
+ ```bash packageManager='npm'
98
+ npm install -D @next/bundle-analyzer
99
+ ```
100
+
101
+ ```bash packageManager='yarn'
102
+ yarn add -D @next/bundle-analyzer
103
+ ```
104
+
105
+ ```bash packageManager='pnpm'
106
+ pnpm add -D @next/bundle-analyzer
107
+ ```
108
+
109
+ ```bash packageManager='bun'
110
+ bun add -d @next/bundle-analyzer
111
+ ```
112
+
113
+ ```javascript fileName="next.config.js"
114
+ const withBundleAnalyzer = require("@next/bundle-analyzer")({
115
+ enabled: process.env.ANALYZE === "true",
116
+ });
117
+
118
+ module.exports = withBundleAnalyzer({
119
+ // Ваша конфигурация Next.js
120
+ });
121
+ ```
122
+
123
+ **Использование:**
124
+
125
+ ```bash
126
+ ANALYZE=true npm run build
127
+ ```
128
+
129
+ </Tab>
130
+ <Tab value="Webpack (CRA / Angular / etc)">
131
+
132
+ ### Стандартный Webpack
133
+
134
+ Для Create React App (ejected), Angular или кастомных настроек Webpack используйте отраслевой стандарт `webpack-bundle-analyzer`.
135
+
136
+ ```bash packageManager='npm'
137
+ npm install -D webpack-bundle-analyzer
138
+ ```
139
+
140
+ ```bash packageManager='yarn'
141
+ yarn add -D webpack-bundle-analyzer
142
+ ```
143
+
144
+ ```bash packageManager='pnpm'
145
+ pnpm add -D webpack-bundle-analyzer
146
+ ```
147
+
148
+ ```bash packageManager='bun'
149
+ bun add -d webpack-bundle-analyzer
150
+ ```
151
+
152
+ ```typescript fileName="webpack.config.ts
153
+ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
154
+
155
+ export default {
156
+ plugins: [
157
+ new BundleAnalyzerPlugin({
158
+ analyzerMode: "static",
159
+ reportFilename: "bundle-analyzer.html",
160
+ openAnalyzer: false,
161
+ }),
162
+ ],
163
+ };
164
+ ```
165
+
166
+ </Tab>
167
+ </Tabs>
168
+
169
+ ## Как это работает
170
+
171
+ Intlayer использует **подход на уровне компонентов**. В отличие от глобальных JSON-файлов, ваш контент определяется рядом с вашими компонентами или внутри них. В процессе сборки Intlayer:
172
+
173
+ 1. **Анализирует** ваш код на наличие вызовов `useIntlayer`.
174
+ 2. **Собирает** соответствующий контент словаря.
175
+ 3. **Заменяет** вызов `useIntlayer` оптимизированным кодом на основе вашей конфигурации.
176
+
177
+ Это гарантирует, что:
178
+
179
+ - Если компонент не импортирован, его контент не включается в бандл (удаление мертвого кода).
180
+ - Если компонент загружается лениво (lazy-loading), его контент также загружается лениво.
181
+
182
+ ## Настройка по платформам
183
+
184
+ <Tabs>
185
+ <Tab value="nextjs">
186
+
187
+ ### Next.js
188
+
189
+ Для трансформации Next.js требуется плагин `@intlayer/swc`, так как Next.js использует SWC для сборки.
190
+
191
+ > Этот плагин не устанавливается по умолчанию, так как плагины SWC для Next.js все еще находятся в стадии эксперимента. Это может измениться в будущем.
192
+
193
+ ```bash packageManager="npm"
194
+ npm install -D @intlayer/swc
195
+ ```
196
+
197
+ ```bash packageManager="yarn"
198
+ yarn add -D @intlayer/swc
199
+ ```
200
+
201
+ ```bash packageManager="pnpm"
202
+ pnpm add -D @intlayer/swc
203
+ ```
204
+
205
+ ```bash packageManager="bun"
206
+ bun add -d @intlayer/swc
207
+ ```
208
+
209
+ После установки Intlayer автоматически обнаружит и будет использовать плагин.
210
+
211
+ </Tab>
212
+ <Tab value="vite">
213
+
214
+ ### Vite
215
+
216
+ Vite использует плагин `@intlayer/babel`, который включен как зависимость `vite-intlayer`. Оптимизация включена по умолчанию. Ничего больше делать не нужно.
217
+
218
+ </Tab>
219
+ <Tab value="webpack">
220
+
221
+ ### Webpack
222
+
223
+ Чтобы включить оптимизацию бандла с помощью Intlayer в Webpack, вам необходимо установить и настроить соответствующий плагин Babel (`@intlayer/babel`) или SWC (`@intlayer/swc`).
224
+
225
+ ```bash packageManager="npm"
226
+ npm install -D @intlayer/babel
227
+ ```
228
+
229
+ ```bash packageManager="yarn"
230
+ yarn add -D @intlayer/babel
231
+ ```
232
+
233
+ ```bash packageManager="pnpm"
234
+ pnpm add -D @intlayer/babel
235
+ ```
236
+
237
+ ```bash packageManager="bun"
238
+ bun add -d @intlayer/babel
239
+ ```
240
+
241
+ ```typescript fileName="babel.config.js"
242
+ const {
243
+ getOptimizePluginOptions,
244
+ intlayerOptimizeBabelPlugin,
245
+ } = require("@intlayer/babel");
246
+
247
+ module.exports = {
248
+ plugins: [[intlayerOptimizeBabelPlugin, getOptimizePluginOptions()]],
249
+ };
250
+ ```
251
+
252
+ </Tab>
253
+ </Tabs>
254
+
255
+ ## Конфигурация
256
+
257
+ Вы можете управлять тем, как Intlayer оптимизирует ваш бандл, с помощью свойства `build` в вашем `intlayer.config.ts`.
258
+
259
+ ```typescript fileName="intlayer.config.ts"
260
+ import { Locales, type IntlayerConfig } from "intlayer";
261
+
262
+ const config: IntlayerConfig = {
263
+ internationalization: {
264
+ locales: [Locales.ENGLISH, Locales.FRENCH],
265
+ defaultLocale: Locales.ENGLISH,
266
+ },
267
+ dictionary: {
268
+ importMode: "dynamic",
269
+ },
270
+ build: {
271
+ /**
272
+ * Минифицировать словари для уменьшения размера бандла.
273
+ */
274
+ minify: true;
275
+
276
+ /**
277
+ * Удалять неиспользуемые ключи в словарях (purge)
278
+ */
279
+ purge: true;
280
+
281
+ /**
282
+ * Указывает, должна ли сборка проверять типы TypeScript
283
+ */
284
+ checkTypes: false;
285
+ },
286
+ };
287
+
288
+ export default config;
289
+ ```
290
+
291
+ > В подавляющем большинстве случаев рекомендуется оставлять значение по умолчанию для параметра `optimize`.
292
+
293
+ > Подробности см. в документации по конфигурации: [Конфигурация](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/configuration.md)
294
+
295
+ ### Опции сборки
296
+
297
+ В объекте конфигурации `build` доступны следующие опции:
298
+
299
+ | Свойство | Тип | По умолчанию | Описание |
300
+ | :------------- | :-------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
301
+ | **`optimize`** | `boolean` | `undefined` | Управляет включением оптимизации сборки. Если `true`, Intlayer заменяет вызовы словаря оптимизированными вставками. Если `false`, оптимизация отключена. В идеале в продакшене должно быть `true`. |
302
+ | **`minify`** | `boolean` | `false` | Минифицировать ли словари для уменьшения размера бандла. |
303
+ | **`purge`** | `boolean` | `false` | Удалять ли неиспользуемые ключи в словарях. |
304
+
305
+ ### Минификация
306
+
307
+ Минификация словарей удаляет ненужные пробелы, комментарии и уменьшает размер содержимого JSON. Это особенно полезно для больших словарей.
308
+
309
+ ```typescript fileName="intlayer.config.ts"
310
+ import type { IntlayerConfig } from "intlayer";
311
+
312
+ const config: IntlayerConfig = {
313
+ build: {
314
+ minify: true,
315
+ },
316
+ };
317
+
318
+ export default config;
319
+ ```
320
+
321
+ > Примечание: Минификация игнорируется, если `optimize` отключен или если включен Визуальный редактор (так как редактору требуется полный контент для возможности редактирования).
322
+
323
+ ### Очистка (Purging)
324
+
325
+ Очистка гарантирует, что в финальный бандл словарей будут включены только те ключи, которые действительно используются в вашем коде. Это может значительно уменьшить размер вашего бандла, если у вас есть большие словари со множеством ключей, которые используются не во всех частях вашего приложения.
326
+
327
+ ```typescript fileName="intlayer.config.ts"
328
+ import type { IntlayerConfig } from "intlayer";
329
+
330
+ const config: IntlayerConfig = {
331
+ build: {
332
+ purge: true,
333
+ },
334
+ };
335
+
336
+ export default config;
337
+ ```
338
+
339
+ > Примечание: Очистка игнорируется, если параметр `optimize` отключен.
340
+
341
+ ### Режим импорта (Import Mode)
342
+
343
+ Для больших приложений, включающих множество страниц и локалей, ваши JSON-файлы могут составлять значительную часть размера бандла. Intlayer позволяет вам контролировать способ загрузки словарей.
344
+
345
+ Режим импорта может быть определен по умолчанию глобально в вашем файле `intlayer.config.ts`.
346
+
347
+ ```typescript fileName="intlayer.config.ts"
348
+ import type { IntlayerConfig } from "intlayer";
349
+
350
+ const config: IntlayerConfig = {
351
+ build: {
352
+ minify: true,
353
+ },
354
+ };
355
+
356
+ export default config;
357
+ ```
358
+
359
+ А также для каждого словаря в ваших файлах `.content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5}}`.
360
+
361
+ ```ts
362
+ import { type Dictionary, t } from "intlayer";
363
+
364
+ const appContent: Dictionary = {
365
+ key: "app",
366
+ importMode: "dynamic", // Переопределить режим импорта по умолчанию
367
+ content: {
368
+ // ...
369
+ },
370
+ };
371
+
372
+ export default appContent;
373
+ ```
374
+
375
+ | Свойство | Тип | По умолчанию | Описание |
376
+ | :--------------- | :--------------------------------- | :----------- | :---------------------------------------------------------------------------------------------------------------------- |
377
+ | **`importMode`** | `'static'`, `'dynamic'`, `'fetch'` | `'static'` | **Устарело**: Используйте `dictionary.importMode` вместо этого. Определяет, как загружаются словари (подробности ниже). |
378
+
379
+ Настройка `importMode` определяет, как содержимое словаря внедряется в ваш компонент.
380
+ Вы можете определить его глобально в файле `intlayer.config.ts` в объекте `dictionary` или переопределить для конкретного словаря в его файле `.content.ts`.
381
+
382
+ ### 1. Статический режим (`default`)
383
+
384
+ В статическом режиме Intlayer заменяет `useIntlayer` на `useDictionary` и внедряет словарь непосредственно в JavaScript бандл.
385
+
386
+ - **Плюсы:** Мгновенный рендеринг (синхронный), отсутствие дополнительных сетевых запросов во время гидратации.
387
+ - **Минусы:** Бандл включает переводы для **всех** доступных языков для этого конкретного компонента.
388
+ - **Лучше всего для:** Одностраничных приложений (SPA).
389
+
390
+ **Пример трансформированного кода:**
391
+
392
+ ```tsx
393
+ // Ваш код
394
+ const content = useIntlayer("my-key");
395
+
396
+ // Оптимизированный код (Статический)
397
+ const content = useDictionary({
398
+ key: "my-key",
399
+ content: {
400
+ nodeType: "translation",
401
+ translation: {
402
+ en: "My title",
403
+ fr: "Mon titre",
404
+ },
405
+ },
406
+ });
407
+ ```
408
+
409
+ ### 2. Динамический режим
410
+
411
+ В динамическом режиме Intlayer заменяет `useIntlayer` на `useDictionaryAsync`. Это использует `import()` (механизм типа Suspense) для ленивой загрузки конкретно JSON для текущей локали.
412
+
413
+ - **Плюсы:** **Tree shaking на уровне локали.** Пользователь, просматривающий английскую версию, скачает _только_ английский словарь. Французский словарь никогда не загрузится.
414
+ - **Минусы:** Вызывает сетевой запрос (загрузку ассета) для каждого компонента во время гидратации.
415
+ - **Лучше всего для:** Больших текстовых блоков, статей или приложений с поддержкой многих языков, где размер бандла критичен.
416
+
417
+ **Пример трансформированного кода:**
418
+
419
+ ```tsx
420
+ // Ваш код
421
+ const content = useIntlayer("my-key");
422
+
423
+ // Оптимизированный код (Динамический)
424
+ const content = useDictionaryAsync({
425
+ en: () =>
426
+ import(".intlayer/dynamic_dictionary/my-key/en.json").then(
427
+ (mod) => mod.default
428
+ ),
429
+ fr: () =>
430
+ import(".intlayer/dynamic_dictionary/my-key/fr.json").then(
431
+ (mod) => mod.default
432
+ ),
433
+ });
434
+ ```
435
+
436
+ > При использовании `importMode: 'dynamic'`, если у вас на одной странице 100 компонентов используют `useIntlayer`, браузер попытается выполнить 100 отдельных загрузок. Чтобы избежать этого "водопада" запросов, группируйте контент в меньшее количество файлов `.content` (например, один словарь на раздел страницы), а не по одному на каждый мелкий компонент.
437
+
438
+ ### 3. Режим Fetch
439
+
440
+ Ведет себя аналогично динамическому режиму, но сначала пытается получить словари из API Intlayer Live Sync. Если вызов API завершается неудачей или контент не помечен для живых обновлений, он переключается на динамический импорт.
441
+
442
+ > Подробности см. в документации CMS: [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_CMS.md)
443
+
444
+ > В режиме fetch нельзя использовать очистку (purge) и минификацию.
445
+
446
+ ## Резюме: Статический vs Динамический
447
+
448
+ | Функция | Статический режим | Динамический режим |
449
+ | :------------------------------- | :----------------------------------------- | :-------------------------------------------------- |
450
+ | **Размер JS бандла** | Больше (включает все языки для компонента) | Меньше всего (только код, контента нет) |
451
+ | **Начальная загрузка** | Мгновенно (контент уже в бандле) | Небольшая задержка (загрузка JSON) |
452
+ | **Сетевые запросы** | 0 дополнительных запросов | 1 запрос на каждый словарь |
453
+ | **Tree Shaking** | На уровне компонентов | На уровне компонентов + на уровне локалей |
454
+ | **Лучший вариант использования** | UI-компоненты, небольшие приложения | Страницы с большим количеством текста, много языков |
@@ -257,7 +257,7 @@ export default function LocaleLayout({
257
257
  params: { locale: string };
258
258
  }) {
259
259
  const locale: Locale = (locales as readonly string[]).includes(params.locale)
260
- ? (params.locale as any)
260
+ ? params.locale
261
261
  : defaultLocale;
262
262
 
263
263
  const dir = isRtl(locale) ? "rtl" : "ltr";
@@ -103,7 +103,7 @@ async function loadMessages(locale: string) {
103
103
  }
104
104
 
105
105
  export default getRequestConfig(async ({ locale }) => {
106
- if (!locales.includes(locale as any)) notFound();
106
+ if (!locales.includes(locale)) notFound();
107
107
 
108
108
  return {
109
109
  messages: await loadMessages(locale),
@@ -194,9 +194,7 @@ const RootComponent: ParentComponent = (props) => {
194
194
  </head>
195
195
  <body>
196
196
  <IntlayerProvider locale={locale}>
197
- <Suspense>
198
- {props.children}
199
- </Suspense>
197
+ <Suspense>{props.children}</Suspense>
200
198
  </IntlayerProvider>
201
199
  <Scripts />
202
200
  </body>
@@ -506,12 +504,33 @@ export const Route = createFileRoute("/{-$locale}/")({
506
504
  component: RouteComponent,
507
505
  head: ({ params }) => {
508
506
  const { locale } = params;
509
- const metaContent = getIntlayer("page-metadata", locale);
507
+ const path = "/"; // The path for this route
508
+
509
+ const metaContent = getIntlayer("app", locale);
510
510
 
511
511
  return {
512
+ links: [
513
+ // Canonical link: Points to the current localized page
514
+ { rel: "canonical", href: getLocalizedUrl(path, locale) },
515
+
516
+ // Hreflang: Tell Google about all localized versions
517
+ ...localeMap(({ locale: mapLocale }) => ({
518
+ rel: "alternate",
519
+ hrefLang: mapLocale,
520
+ href: getLocalizedUrl(path, mapLocale),
521
+ })),
522
+
523
+ // x-default: For users in unmatched languages
524
+ // Define the default fallback locale (usually your primary language)
525
+ {
526
+ rel: "alternate",
527
+ hrefLang: "x-default",
528
+ href: getLocalizedUrl(path, defaultLocale),
529
+ },
530
+ ],
512
531
  meta: [
513
532
  { title: metaContent.title },
514
- { content: metaContent.description, name: "description" },
533
+ { name: "description", content: metaContent.meta.description },
515
534
  ],
516
535
  };
517
536
  },
@@ -225,9 +225,7 @@ function RootDocument({ children }: { children: ReactNode }) {
225
225
  <HeadContent />
226
226
  </head>
227
227
  <body>
228
- <IntlayerProvider locale={locale}>
229
- {children}
230
- </IntlayerProvider>
228
+ <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
231
229
  <Scripts />
232
230
  </body>
233
231
  </html>
@@ -326,30 +324,20 @@ import { getPrefix } from "intlayer";
326
324
 
327
325
  export const LOCALE_ROUTE = "{-$locale}" as const;
328
326
 
329
- // Основная утилита
330
- export type RemoveLocaleParam<T> = T extends string
331
- ? RemoveLocaleFromString<T>
332
- : T;
327
+ export type To = StripLocalePrefix<LinkComponentProps["to"]>;
333
328
 
334
- export type To = RemoveLocaleParam<LinkComponentProps["to"]>;
335
-
336
- type CollapseDoubleSlashes<S extends string> =
337
- S extends `${infer H}//${infer T}` ? CollapseDoubleSlashes<`${H}/${T}`> : S;
329
+ export type StripLocalePrefix<T extends string | undefined> = T extends
330
+ | `/${typeof LOCALE_ROUTE}/`
331
+ | `/${typeof LOCALE_ROUTE}`
332
+ ? "/"
333
+ : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
334
+ ? `/${Rest}`
335
+ : T;
338
336
 
339
337
  type LocalizedLinkProps = {
340
338
  to?: To;
341
339
  } & Omit<LinkComponentProps, "to">;
342
340
 
343
- // Вспомогательные типы
344
- type RemoveAll<
345
- S extends string,
346
- Sub extends string,
347
- > = S extends `${infer H}${Sub}${infer T}` ? RemoveAll<`${H}${T}`, Sub> : S;
348
-
349
- type RemoveLocaleFromString<S extends string> = CollapseDoubleSlashes<
350
- RemoveAll<S, typeof LOCALE_ROUTE>
351
- >;
352
-
353
341
  export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {
354
342
  const { locale } = useLocale();
355
343
  const { localePrefix } = getPrefix(locale);
@@ -378,26 +366,26 @@ export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {
378
366
  import { useNavigate } from "@tanstack/react-router";
379
367
  import { getPrefix } from "intlayer";
380
368
  import { useLocale } from "react-intlayer";
381
- import { LOCALE_ROUTE } from "@/components/localized-link";
369
+ import type { StripLocalePrefix } from "@/components/localized-link";
382
370
  import type { FileRouteTypes } from "@/routeTree.gen";
383
371
 
384
- type StripLocalePrefix<T extends string> = T extends
385
- | `/${typeof LOCALE_ROUTE}`
386
- | `/${typeof LOCALE_ROUTE}/`
387
- ? "/"
388
- : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
389
- ? `/${Rest}`
390
- : never;
372
+ type NavigateFn = ReturnType<typeof useNavigate>;
373
+ type BaseNavigateOptions = Parameters<NavigateFn>[0];
391
374
 
392
375
  type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;
393
376
 
394
- type LocalizedNavigate = {
395
- (to: LocalizedTo): ReturnType<ReturnType<typeof useNavigate>>;
396
- (
397
- opts: { to: LocalizedTo } & Record<string, unknown>
398
- ): ReturnType<ReturnType<typeof useNavigate>>;
377
+ export type LocalizedNavigateOptions = Omit<
378
+ BaseNavigateOptions,
379
+ "to" | "params"
380
+ > & {
381
+ to: LocalizedTo;
382
+ params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;
399
383
  };
400
384
 
385
+ type LocalizedNavigate = (
386
+ options: LocalizedNavigateOptions
387
+ ) => ReturnType<NavigateFn>;
388
+
401
389
  export const useLocalizedNavigate = () => {
402
390
  const navigate = useNavigate();
403
391
 
@@ -444,38 +432,6 @@ import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";
444
432
 
445
433
  export const Route = createFileRoute("/{-$locale}/")({
446
434
  component: RouteComponent,
447
- head: ({ params }) => {
448
- const { locale } = params;
449
- const path = "/"; // The path for this route
450
-
451
- const metaContent = getIntlayer("app", locale);
452
-
453
- return {
454
- links: [
455
- // Canonical link: Points to the current localized page
456
- { rel: "canonical", href: getLocalizedUrl(path, locale) },
457
-
458
- // Hreflang: Tell Google about all localized versions
459
- ...localeMap(({ locale: mapLocale }) => ({
460
- rel: "alternate",
461
- hrefLang: mapLocale,
462
- href: getLocalizedUrl(path, mapLocale),
463
- })),
464
-
465
- // x-default: For users in unmatched languages
466
- // Define the default fallback locale (usually your primary language)
467
- {
468
- rel: "alternate",
469
- hrefLang: "x-default",
470
- href: getLocalizedUrl(path, defaultLocale),
471
- },
472
- ],
473
- meta: [
474
- { title: metaContent.title },
475
- { name: "description", content: metaContent.meta.description },
476
- ],
477
- };
478
- },
479
435
  });
480
436
 
481
437
  function RouteComponent() {
@@ -630,12 +586,33 @@ export const Route = createFileRoute("/{-$locale}/")({
630
586
  component: RouteComponent,
631
587
  head: ({ params }) => {
632
588
  const { locale } = params;
633
- const metaContent = getIntlayer("page-metadata", locale);
589
+ const path = "/"; // The path for this route
590
+
591
+ const metaContent = getIntlayer("app", locale);
634
592
 
635
593
  return {
594
+ links: [
595
+ // Canonical link: Points to the current localized page
596
+ { rel: "canonical", href: getLocalizedUrl(path, locale) },
597
+
598
+ // Hreflang: Tell Google about all localized versions
599
+ ...localeMap(({ locale: mapLocale }) => ({
600
+ rel: "alternate",
601
+ hrefLang: mapLocale,
602
+ href: getLocalizedUrl(path, mapLocale),
603
+ })),
604
+
605
+ // x-default: For users in unmatched languages
606
+ // Define the default fallback locale (usually your primary language)
607
+ {
608
+ rel: "alternate",
609
+ hrefLang: "x-default",
610
+ href: getLocalizedUrl(path, defaultLocale),
611
+ },
612
+ ],
636
613
  meta: [
637
614
  { title: metaContent.title },
638
- { content: metaContent.description, name: "description" },
615
+ { name: "description", content: metaContent.meta.description },
639
616
  ],
640
617
  };
641
618
  },