@intlayer/docs 7.5.11 → 7.5.13

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 (417) hide show
  1. package/blog/ar/intlayer_with_i18next.md +0 -2
  2. package/blog/ar/intlayer_with_next-i18next.md +0 -2
  3. package/blog/ar/intlayer_with_react-i18next.md +0 -2
  4. package/blog/de/intlayer_with_i18next.md +0 -45
  5. package/blog/de/intlayer_with_next-i18next.md +0 -46
  6. package/blog/de/intlayer_with_react-i18next.md +0 -2
  7. package/blog/en/intlayer_with_i18next.md +0 -46
  8. package/blog/en/intlayer_with_next-i18next.md +0 -48
  9. package/blog/en/intlayer_with_next-intl.md +0 -44
  10. package/blog/en/intlayer_with_react-i18next.md +0 -44
  11. package/blog/en/intlayer_with_react-intl.md +0 -42
  12. package/blog/en/intlayer_with_vue-i18n.md +0 -44
  13. package/blog/en-GB/intlayer_with_i18next.md +0 -45
  14. package/blog/en-GB/intlayer_with_next-i18next.md +0 -47
  15. package/blog/en-GB/intlayer_with_next-intl.md +0 -42
  16. package/blog/en-GB/intlayer_with_react-i18next.md +0 -43
  17. package/blog/en-GB/intlayer_with_react-intl.md +0 -42
  18. package/blog/en-GB/intlayer_with_vue-i18n.md +0 -46
  19. package/blog/es/intlayer_with_i18next.md +0 -45
  20. package/blog/es/intlayer_with_next-i18next.md +0 -47
  21. package/blog/es/intlayer_with_next-intl.md +0 -42
  22. package/blog/es/intlayer_with_react-i18next.md +0 -43
  23. package/blog/es/intlayer_with_react-intl.md +0 -42
  24. package/blog/es/intlayer_with_vue-i18n.md +0 -46
  25. package/blog/fr/intlayer_with_i18next.md +0 -45
  26. package/blog/fr/intlayer_with_next-i18next.md +0 -47
  27. package/blog/fr/intlayer_with_next-intl.md +0 -42
  28. package/blog/fr/intlayer_with_react-i18next.md +0 -43
  29. package/blog/fr/intlayer_with_react-intl.md +0 -42
  30. package/blog/fr/intlayer_with_vue-i18n.md +0 -46
  31. package/blog/hi/intlayer_with_i18next.md +0 -2
  32. package/blog/hi/intlayer_with_next-i18next.md +0 -2
  33. package/blog/hi/intlayer_with_react-i18next.md +0 -2
  34. package/blog/id/intlayer_with_i18next.md +0 -2
  35. package/blog/id/intlayer_with_next-i18next.md +0 -2
  36. package/blog/id/intlayer_with_react-i18next.md +0 -2
  37. package/blog/it/intlayer_with_i18next.md +0 -2
  38. package/blog/it/intlayer_with_next-i18next.md +0 -2
  39. package/blog/it/intlayer_with_react-i18next.md +0 -2
  40. package/blog/ja/intlayer_with_i18next.md +0 -45
  41. package/blog/ja/intlayer_with_next-i18next.md +0 -46
  42. package/blog/ja/intlayer_with_next-intl.md +0 -42
  43. package/blog/ja/intlayer_with_react-i18next.md +0 -42
  44. package/blog/ja/intlayer_with_react-intl.md +0 -42
  45. package/blog/ja/intlayer_with_vue-i18n.md +0 -46
  46. package/blog/ko/intlayer_with_i18next.md +0 -2
  47. package/blog/ko/intlayer_with_next-i18next.md +0 -2
  48. package/blog/ko/intlayer_with_react-i18next.md +0 -1
  49. package/blog/pl/intlayer_with_i18next.md +0 -45
  50. package/blog/pl/intlayer_with_next-i18next.md +0 -46
  51. package/blog/pl/intlayer_with_next-intl.md +0 -42
  52. package/blog/pl/intlayer_with_react-i18next.md +0 -43
  53. package/blog/pl/intlayer_with_react-intl.md +0 -42
  54. package/blog/pl/intlayer_with_vue-i18n.md +0 -46
  55. package/blog/pt/intlayer_with_i18next.md +0 -2
  56. package/blog/pt/intlayer_with_next-i18next.md +0 -2
  57. package/blog/pt/intlayer_with_react-i18next.md +0 -2
  58. package/blog/ru/intlayer_with_i18next.md +0 -45
  59. package/blog/ru/intlayer_with_next-i18next.md +0 -47
  60. package/blog/ru/intlayer_with_next-intl.md +0 -42
  61. package/blog/ru/intlayer_with_react-i18next.md +0 -43
  62. package/blog/ru/intlayer_with_react-intl.md +0 -42
  63. package/blog/ru/intlayer_with_vue-i18n.md +0 -46
  64. package/blog/tr/intlayer_with_i18next.md +0 -2
  65. package/blog/tr/intlayer_with_next-i18next.md +0 -1
  66. package/blog/tr/intlayer_with_react-i18next.md +0 -2
  67. package/blog/uk/compiler_vs_declarative_i18n.md +224 -0
  68. package/blog/uk/i18n_using_next-i18next.md +1086 -0
  69. package/blog/uk/i18n_using_next-intl.md +760 -0
  70. package/blog/uk/index.md +69 -0
  71. package/blog/uk/internationalization_and_SEO.md +273 -0
  72. package/blog/uk/intlayer_with_i18next.md +211 -0
  73. package/blog/uk/intlayer_with_next-i18next.md +202 -0
  74. package/blog/uk/intlayer_with_next-intl.md +203 -0
  75. package/blog/uk/intlayer_with_react-i18next.md +200 -0
  76. package/blog/uk/intlayer_with_react-intl.md +202 -0
  77. package/blog/uk/intlayer_with_vue-i18n.md +206 -0
  78. package/blog/uk/l10n_platform_alternative/Lokalise.md +80 -0
  79. package/blog/uk/l10n_platform_alternative/crowdin.md +80 -0
  80. package/blog/uk/l10n_platform_alternative/phrase.md +78 -0
  81. package/blog/uk/list_i18n_technologies/CMS/drupal.md +143 -0
  82. package/blog/uk/list_i18n_technologies/CMS/wix.md +167 -0
  83. package/blog/uk/list_i18n_technologies/CMS/wordpress.md +189 -0
  84. package/blog/uk/list_i18n_technologies/frameworks/angular.md +125 -0
  85. package/blog/uk/list_i18n_technologies/frameworks/flutter.md +128 -0
  86. package/blog/uk/list_i18n_technologies/frameworks/react-native.md +217 -0
  87. package/blog/uk/list_i18n_technologies/frameworks/react.md +155 -0
  88. package/blog/uk/list_i18n_technologies/frameworks/svelte.md +145 -0
  89. package/blog/uk/list_i18n_technologies/frameworks/vue.md +144 -0
  90. package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +1499 -0
  91. package/blog/uk/nextjs-multilingual-seo-comparison.md +360 -0
  92. package/blog/uk/rag_powered_documentation_assistant.md +288 -0
  93. package/blog/uk/react-i18next_vs_react-intl_vs_intlayer.md +164 -0
  94. package/blog/uk/vue-i18n_vs_intlayer.md +279 -0
  95. package/blog/uk/what_is_internationalization.md +167 -0
  96. package/blog/vi/intlayer_with_i18next.md +0 -2
  97. package/blog/vi/intlayer_with_next-i18next.md +0 -2
  98. package/blog/vi/intlayer_with_react-i18next.md +0 -2
  99. package/blog/zh/intlayer_with_i18next.md +0 -2
  100. package/blog/zh/intlayer_with_next-i18next.md +0 -2
  101. package/blog/zh/intlayer_with_react-i18next.md +0 -2
  102. package/blog/zh/intlayer_with_vue-i18n.md +0 -46
  103. package/dist/cjs/generated/blog.entry.cjs +58 -29
  104. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  105. package/dist/cjs/generated/docs.entry.cjs +218 -99
  106. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  107. package/dist/cjs/generated/frequentQuestions.entry.cjs +50 -15
  108. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  109. package/dist/cjs/generated/legal.entry.cjs +4 -2
  110. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  111. package/dist/esm/generated/blog.entry.mjs +58 -29
  112. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  113. package/dist/esm/generated/docs.entry.mjs +218 -99
  114. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  115. package/dist/esm/generated/frequentQuestions.entry.mjs +50 -15
  116. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  117. package/dist/esm/generated/legal.entry.mjs +4 -2
  118. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  119. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  120. package/dist/types/generated/docs.entry.d.ts +1 -0
  121. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  122. package/dist/types/generated/frequentQuestions.entry.d.ts +1 -0
  123. package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
  124. package/dist/types/generated/legal.entry.d.ts.map +1 -1
  125. package/docs/ar/configuration.md +6 -1
  126. package/docs/ar/dictionary/content_file.md +6 -1
  127. package/docs/ar/intlayer_with_next-i18next.md +0 -1
  128. package/docs/ar/intlayer_with_nextjs_14.md +28 -0
  129. package/docs/ar/intlayer_with_nextjs_15.md +28 -0
  130. package/docs/ar/intlayer_with_nextjs_16.md +28 -0
  131. package/docs/ar/intlayer_with_nextjs_no_locale_path.md +1159 -0
  132. package/docs/ar/plugins/sync-json.md +6 -2
  133. package/docs/de/configuration.md +6 -1
  134. package/docs/de/dictionary/content_file.md +6 -1
  135. package/docs/de/intlayer_with_next-i18next.md +0 -1
  136. package/docs/de/intlayer_with_nextjs_14.md +28 -0
  137. package/docs/de/intlayer_with_nextjs_15.md +28 -0
  138. package/docs/de/intlayer_with_nextjs_16.md +28 -0
  139. package/docs/de/intlayer_with_nextjs_no_locale_path.md +1152 -0
  140. package/docs/de/plugins/sync-json.md +6 -2
  141. package/docs/en/configuration.md +6 -1
  142. package/docs/en/dictionary/content_file.md +6 -1
  143. package/docs/en/intlayer_with_next-i18next.md +0 -1
  144. package/docs/en/intlayer_with_nextjs_14.md +28 -0
  145. package/docs/en/intlayer_with_nextjs_15.md +28 -0
  146. package/docs/en/intlayer_with_nextjs_16.md +31 -1
  147. package/docs/en/intlayer_with_nextjs_no_locale_path.md +1132 -0
  148. package/docs/en/plugins/sync-json.md +6 -2
  149. package/docs/en-GB/configuration.md +6 -1
  150. package/docs/en-GB/dictionary/content_file.md +3 -1
  151. package/docs/en-GB/intlayer_with_next-i18next.md +0 -1
  152. package/docs/en-GB/intlayer_with_nextjs_14.md +28 -0
  153. package/docs/en-GB/intlayer_with_nextjs_15.md +28 -0
  154. package/docs/en-GB/intlayer_with_nextjs_16.md +28 -0
  155. package/docs/en-GB/intlayer_with_nextjs_no_locale_path.md +1154 -0
  156. package/docs/en-GB/plugins/sync-json.md +6 -2
  157. package/docs/es/configuration.md +6 -1
  158. package/docs/es/dictionary/content_file.md +6 -1
  159. package/docs/es/intlayer_with_next-i18next.md +0 -1
  160. package/docs/es/intlayer_with_nextjs_14.md +28 -0
  161. package/docs/es/intlayer_with_nextjs_15.md +28 -0
  162. package/docs/es/intlayer_with_nextjs_16.md +28 -0
  163. package/docs/es/intlayer_with_nextjs_no_locale_path.md +1143 -0
  164. package/docs/es/plugins/sync-json.md +6 -2
  165. package/docs/fr/configuration.md +6 -1
  166. package/docs/fr/dictionary/content_file.md +3 -1
  167. package/docs/fr/intlayer_with_next-i18next.md +0 -1
  168. package/docs/fr/intlayer_with_nextjs_14.md +28 -0
  169. package/docs/fr/intlayer_with_nextjs_15.md +28 -0
  170. package/docs/fr/intlayer_with_nextjs_16.md +28 -0
  171. package/docs/fr/intlayer_with_nextjs_no_locale_path.md +1174 -0
  172. package/docs/fr/plugins/sync-json.md +9 -5
  173. package/docs/hi/configuration.md +6 -1
  174. package/docs/hi/dictionary/content_file.md +3 -1
  175. package/docs/hi/intlayer_with_next-i18next.md +0 -1
  176. package/docs/hi/intlayer_with_nextjs_14.md +28 -0
  177. package/docs/hi/intlayer_with_nextjs_15.md +28 -0
  178. package/docs/hi/intlayer_with_nextjs_16.md +28 -0
  179. package/docs/hi/intlayer_with_nextjs_no_locale_path.md +1151 -0
  180. package/docs/hi/plugins/sync-json.md +6 -2
  181. package/docs/id/configuration.md +6 -1
  182. package/docs/id/dictionary/content_file.md +3 -1
  183. package/docs/id/intlayer_with_next-i18next.md +0 -1
  184. package/docs/id/intlayer_with_nextjs_14.md +28 -0
  185. package/docs/id/intlayer_with_nextjs_15.md +28 -0
  186. package/docs/id/intlayer_with_nextjs_16.md +28 -0
  187. package/docs/id/intlayer_with_nextjs_no_locale_path.md +1154 -0
  188. package/docs/id/plugins/sync-json.md +6 -2
  189. package/docs/it/configuration.md +6 -1
  190. package/docs/it/dictionary/content_file.md +3 -1
  191. package/docs/it/intlayer_with_next-i18next.md +0 -1
  192. package/docs/it/intlayer_with_nextjs_14.md +28 -0
  193. package/docs/it/intlayer_with_nextjs_15.md +28 -0
  194. package/docs/it/intlayer_with_nextjs_16.md +28 -0
  195. package/docs/it/intlayer_with_nextjs_no_locale_path.md +1148 -0
  196. package/docs/it/plugins/sync-json.md +6 -2
  197. package/docs/ja/configuration.md +6 -1
  198. package/docs/ja/dictionary/content_file.md +3 -1
  199. package/docs/ja/intlayer_with_next-i18next.md +0 -1
  200. package/docs/ja/intlayer_with_nextjs_14.md +28 -0
  201. package/docs/ja/intlayer_with_nextjs_15.md +28 -0
  202. package/docs/ja/intlayer_with_nextjs_16.md +28 -0
  203. package/docs/ja/intlayer_with_nextjs_no_locale_path.md +1222 -0
  204. package/docs/ja/plugins/sync-json.md +6 -2
  205. package/docs/ko/configuration.md +6 -1
  206. package/docs/ko/dictionary/content_file.md +3 -1
  207. package/docs/ko/intlayer_with_next-i18next.md +0 -1
  208. package/docs/ko/intlayer_with_nextjs_14.md +28 -0
  209. package/docs/ko/intlayer_with_nextjs_15.md +28 -0
  210. package/docs/ko/intlayer_with_nextjs_16.md +28 -0
  211. package/docs/ko/intlayer_with_nextjs_no_locale_path.md +1205 -0
  212. package/docs/ko/plugins/sync-json.md +6 -2
  213. package/docs/pl/configuration.md +3 -1
  214. package/docs/pl/dictionary/content_file.md +3 -1
  215. package/docs/pl/intlayer_with_next-i18next.md +0 -1
  216. package/docs/pl/intlayer_with_nextjs_14.md +28 -0
  217. package/docs/pl/intlayer_with_nextjs_15.md +28 -0
  218. package/docs/pl/intlayer_with_nextjs_16.md +28 -0
  219. package/docs/pl/intlayer_with_nextjs_no_locale_path.md +1149 -0
  220. package/docs/pl/plugins/sync-json.md +6 -2
  221. package/docs/pt/configuration.md +6 -1
  222. package/docs/pt/dictionary/content_file.md +3 -1
  223. package/docs/pt/intlayer_with_next-i18next.md +0 -1
  224. package/docs/pt/intlayer_with_nextjs_14.md +28 -0
  225. package/docs/pt/intlayer_with_nextjs_15.md +28 -0
  226. package/docs/pt/intlayer_with_nextjs_16.md +28 -0
  227. package/docs/pt/intlayer_with_nextjs_no_locale_path.md +1152 -0
  228. package/docs/pt/plugins/sync-json.md +6 -2
  229. package/docs/ru/configuration.md +6 -1
  230. package/docs/ru/dictionary/content_file.md +6 -1
  231. package/docs/ru/intlayer_with_next-i18next.md +0 -1
  232. package/docs/ru/intlayer_with_nextjs_14.md +28 -0
  233. package/docs/ru/intlayer_with_nextjs_15.md +28 -0
  234. package/docs/ru/intlayer_with_nextjs_16.md +28 -0
  235. package/docs/ru/intlayer_with_nextjs_no_locale_path.md +1204 -0
  236. package/docs/ru/plugins/sync-json.md +6 -2
  237. package/docs/tr/configuration.md +6 -1
  238. package/docs/tr/dictionary/content_file.md +3 -1
  239. package/docs/tr/intlayer_with_next-i18next.md +0 -1
  240. package/docs/tr/intlayer_with_nextjs_14.md +28 -0
  241. package/docs/tr/intlayer_with_nextjs_15.md +28 -0
  242. package/docs/tr/intlayer_with_nextjs_16.md +28 -0
  243. package/docs/tr/intlayer_with_nextjs_no_locale_path.md +1159 -0
  244. package/docs/tr/plugins/sync-json.md +6 -2
  245. package/docs/uk/CI_CD.md +198 -0
  246. package/docs/uk/autoFill.md +307 -0
  247. package/docs/uk/bundle_optimization.md +185 -0
  248. package/docs/uk/cli/build.md +64 -0
  249. package/docs/uk/cli/ci.md +137 -0
  250. package/docs/uk/cli/configuration.md +63 -0
  251. package/docs/uk/cli/debug.md +46 -0
  252. package/docs/uk/cli/doc-review.md +43 -0
  253. package/docs/uk/cli/doc-translate.md +132 -0
  254. package/docs/uk/cli/editor.md +28 -0
  255. package/docs/uk/cli/fill.md +130 -0
  256. package/docs/uk/cli/index.md +190 -0
  257. package/docs/uk/cli/init.md +84 -0
  258. package/docs/uk/cli/list.md +90 -0
  259. package/docs/uk/cli/list_projects.md +128 -0
  260. package/docs/uk/cli/live.md +41 -0
  261. package/docs/uk/cli/login.md +157 -0
  262. package/docs/uk/cli/pull.md +78 -0
  263. package/docs/uk/cli/push.md +98 -0
  264. package/docs/uk/cli/sdk.md +71 -0
  265. package/docs/uk/cli/test.md +76 -0
  266. package/docs/uk/cli/transform.md +65 -0
  267. package/docs/uk/cli/version.md +24 -0
  268. package/docs/uk/cli/watch.md +37 -0
  269. package/docs/uk/compiler.md +133 -0
  270. package/docs/uk/component_i18n.md +194 -0
  271. package/docs/uk/configuration.md +742 -0
  272. package/docs/uk/dictionary/condition.md +237 -0
  273. package/docs/uk/dictionary/content_file.md +1134 -0
  274. package/docs/uk/dictionary/enumeration.md +245 -0
  275. package/docs/uk/dictionary/file.md +232 -0
  276. package/docs/uk/dictionary/function_fetching.md +212 -0
  277. package/docs/uk/dictionary/gender.md +273 -0
  278. package/docs/uk/dictionary/insertion.md +187 -0
  279. package/docs/uk/dictionary/markdown.md +383 -0
  280. package/docs/uk/dictionary/nesting.md +273 -0
  281. package/docs/uk/dictionary/translation.md +332 -0
  282. package/docs/uk/formatters.md +595 -0
  283. package/docs/uk/how_works_intlayer.md +256 -0
  284. package/docs/uk/index.md +175 -0
  285. package/docs/uk/interest_of_intlayer.md +297 -0
  286. package/docs/uk/intlayer_CMS.md +569 -0
  287. package/docs/uk/intlayer_visual_editor.md +292 -0
  288. package/docs/uk/intlayer_with_angular.md +710 -0
  289. package/docs/uk/intlayer_with_astro.md +256 -0
  290. package/docs/uk/intlayer_with_create_react_app.md +1258 -0
  291. package/docs/uk/intlayer_with_express.md +429 -0
  292. package/docs/uk/intlayer_with_fastify.md +446 -0
  293. package/docs/uk/intlayer_with_lynx+react.md +548 -0
  294. package/docs/uk/intlayer_with_nestjs.md +283 -0
  295. package/docs/uk/intlayer_with_next-i18next.md +640 -0
  296. package/docs/uk/intlayer_with_next-intl.md +456 -0
  297. package/docs/uk/intlayer_with_nextjs_14.md +1646 -0
  298. package/docs/uk/intlayer_with_nextjs_15.md +1910 -0
  299. package/docs/uk/intlayer_with_nextjs_16.md +1763 -0
  300. package/docs/uk/intlayer_with_nextjs_no_locale_path.md +1159 -0
  301. package/docs/uk/intlayer_with_nextjs_page_router.md +1541 -0
  302. package/docs/uk/intlayer_with_nuxt.md +711 -0
  303. package/docs/uk/intlayer_with_react_native+expo.md +715 -0
  304. package/docs/uk/intlayer_with_react_router_v7.md +600 -0
  305. package/docs/uk/intlayer_with_react_router_v7_fs_routes.md +669 -0
  306. package/docs/uk/intlayer_with_svelte_kit.md +579 -0
  307. package/docs/uk/intlayer_with_tanstack.md +818 -0
  308. package/docs/uk/intlayer_with_vite+preact.md +1748 -0
  309. package/docs/uk/intlayer_with_vite+react.md +1449 -0
  310. package/docs/uk/intlayer_with_vite+solid.md +302 -0
  311. package/docs/uk/intlayer_with_vite+svelte.md +520 -0
  312. package/docs/uk/intlayer_with_vite+vue.md +1113 -0
  313. package/docs/uk/introduction.md +222 -0
  314. package/docs/uk/locale_mapper.md +242 -0
  315. package/docs/uk/mcp_server.md +211 -0
  316. package/docs/uk/packages/express-intlayer/t.md +465 -0
  317. package/docs/uk/packages/intlayer/getConfiguration.md +145 -0
  318. package/docs/uk/packages/intlayer/getEnumeration.md +159 -0
  319. package/docs/uk/packages/intlayer/getHTMLTextDir.md +121 -0
  320. package/docs/uk/packages/intlayer/getLocaleLang.md +81 -0
  321. package/docs/uk/packages/intlayer/getLocaleName.md +135 -0
  322. package/docs/uk/packages/intlayer/getLocalizedUrl.md +338 -0
  323. package/docs/uk/packages/intlayer/getMultilingualUrls.md +359 -0
  324. package/docs/uk/packages/intlayer/getPathWithoutLocale.md +75 -0
  325. package/docs/uk/packages/intlayer/getPrefix.md +213 -0
  326. package/docs/uk/packages/intlayer/getTranslation.md +190 -0
  327. package/docs/uk/packages/intlayer/getTranslationContent.md +189 -0
  328. package/docs/uk/packages/next-intlayer/t.md +365 -0
  329. package/docs/uk/packages/next-intlayer/useDictionary.md +276 -0
  330. package/docs/uk/packages/next-intlayer/useIntlayer.md +263 -0
  331. package/docs/uk/packages/next-intlayer/useLocale.md +166 -0
  332. package/docs/uk/packages/react-intlayer/t.md +311 -0
  333. package/docs/uk/packages/react-intlayer/useDictionary.md +295 -0
  334. package/docs/uk/packages/react-intlayer/useI18n.md +250 -0
  335. package/docs/uk/packages/react-intlayer/useIntlayer.md +251 -0
  336. package/docs/uk/packages/react-intlayer/useLocale.md +210 -0
  337. package/docs/uk/per_locale_file.md +345 -0
  338. package/docs/uk/plugins/sync-json.md +398 -0
  339. package/docs/uk/readme.md +265 -0
  340. package/docs/uk/releases/v6.md +305 -0
  341. package/docs/uk/releases/v7.md +624 -0
  342. package/docs/uk/roadmap.md +346 -0
  343. package/docs/uk/testing.md +204 -0
  344. package/docs/uk/vs_code_extension.md +133 -0
  345. package/docs/vi/configuration.md +6 -1
  346. package/docs/vi/dictionary/content_file.md +6 -1
  347. package/docs/vi/intlayer_with_next-i18next.md +0 -1
  348. package/docs/vi/intlayer_with_nextjs_14.md +28 -0
  349. package/docs/vi/intlayer_with_nextjs_15.md +28 -0
  350. package/docs/vi/intlayer_with_nextjs_16.md +28 -0
  351. package/docs/vi/intlayer_with_nextjs_no_locale_path.md +1151 -0
  352. package/docs/vi/plugins/sync-json.md +6 -2
  353. package/docs/zh/configuration.md +6 -1
  354. package/docs/zh/dictionary/content_file.md +6 -1
  355. package/docs/zh/intlayer_with_next-i18next.md +0 -1
  356. package/docs/zh/intlayer_with_nextjs_14.md +28 -0
  357. package/docs/zh/intlayer_with_nextjs_15.md +28 -0
  358. package/docs/zh/intlayer_with_nextjs_16.md +28 -0
  359. package/docs/zh/intlayer_with_nextjs_no_locale_path.md +1206 -0
  360. package/docs/zh/plugins/sync-json.md +9 -5
  361. package/frequent_questions/ar/SSR_Next_no_[locale].md +1 -1
  362. package/frequent_questions/ar/error-vite-env-only.md +77 -0
  363. package/frequent_questions/de/SSR_Next_no_[locale].md +1 -1
  364. package/frequent_questions/de/error-vite-env-only.md +77 -0
  365. package/frequent_questions/en/SSR_Next_no_[locale].md +1 -1
  366. package/frequent_questions/en/error-vite-env-only.md +77 -0
  367. package/frequent_questions/en-GB/SSR_Next_no_[locale].md +1 -1
  368. package/frequent_questions/en-GB/error-vite-env-only.md +77 -0
  369. package/frequent_questions/es/SSR_Next_no_[locale].md +1 -1
  370. package/frequent_questions/es/error-vite-env-only.md +76 -0
  371. package/frequent_questions/fr/SSR_Next_no_[locale].md +1 -1
  372. package/frequent_questions/fr/error-vite-env-only.md +77 -0
  373. package/frequent_questions/hi/SSR_Next_no_[locale].md +1 -1
  374. package/frequent_questions/hi/error-vite-env-only.md +77 -0
  375. package/frequent_questions/id/SSR_Next_no_[locale].md +1 -1
  376. package/frequent_questions/id/error-vite-env-only.md +77 -0
  377. package/frequent_questions/it/SSR_Next_no_[locale].md +1 -1
  378. package/frequent_questions/it/error-vite-env-only.md +77 -0
  379. package/frequent_questions/ja/SSR_Next_no_[locale].md +1 -1
  380. package/frequent_questions/ja/error-vite-env-only.md +77 -0
  381. package/frequent_questions/ko/SSR_Next_no_[locale].md +1 -1
  382. package/frequent_questions/ko/error-vite-env-only.md +77 -0
  383. package/frequent_questions/pl/SSR_Next_no_[locale].md +1 -1
  384. package/frequent_questions/pl/error-vite-env-only.md +77 -0
  385. package/frequent_questions/pt/SSR_Next_no_[locale].md +1 -1
  386. package/frequent_questions/pt/error-vite-env-only.md +77 -0
  387. package/frequent_questions/ru/SSR_Next_no_[locale].md +1 -1
  388. package/frequent_questions/ru/error-vite-env-only.md +77 -0
  389. package/frequent_questions/tr/SSR_Next_no_[locale].md +1 -1
  390. package/frequent_questions/tr/error-vite-env-only.md +77 -0
  391. package/frequent_questions/uk/SSR_Next_no_[locale].md +104 -0
  392. package/frequent_questions/uk/array_as_content_declaration.md +72 -0
  393. package/frequent_questions/uk/build_dictionaries.md +58 -0
  394. package/frequent_questions/uk/build_error_CI_CD.md +74 -0
  395. package/frequent_questions/uk/bun_set_up.md +53 -0
  396. package/frequent_questions/uk/customized_locale_list.md +64 -0
  397. package/frequent_questions/uk/domain_routing.md +113 -0
  398. package/frequent_questions/uk/error-vite-env-only.md +77 -0
  399. package/frequent_questions/uk/esbuild_error.md +29 -0
  400. package/frequent_questions/uk/get_locale_cookie.md +142 -0
  401. package/frequent_questions/uk/intlayer_command_undefined.md +155 -0
  402. package/frequent_questions/uk/locale_incorect_in_url.md +73 -0
  403. package/frequent_questions/uk/package_version_error.md +181 -0
  404. package/frequent_questions/uk/static_rendering.md +44 -0
  405. package/frequent_questions/uk/translated_path_url.md +55 -0
  406. package/frequent_questions/uk/unknown_command.md +97 -0
  407. package/frequent_questions/vi/SSR_Next_no_[locale].md +1 -1
  408. package/frequent_questions/vi/error-vite-env-only.md +77 -0
  409. package/frequent_questions/zh/SSR_Next_no_[locale].md +1 -1
  410. package/frequent_questions/zh/error-vite-env-only.md +77 -0
  411. package/legal/uk/privacy_notice.md +83 -0
  412. package/legal/uk/terms_of_service.md +55 -0
  413. package/package.json +6 -6
  414. package/src/generated/blog.entry.ts +29 -0
  415. package/src/generated/docs.entry.ts +119 -0
  416. package/src/generated/frequentQuestions.entry.ts +35 -0
  417. package/src/generated/legal.entry.ts +2 -0
@@ -0,0 +1,1748 @@
1
+ ---
2
+ createdAt: 2025-04-18
3
+ updatedAt: 2025-12-30
4
+ title: Як перекласти ваш додаток на Vite та Preact – посібник з i18n 2026
5
+ description: Дізнайтеся, як зробити ваш вебсайт на Vite і Preact багатомовним. Дотримуйтесь документації, щоб інтернаціоналізувати (i18n) та перекласти його.
6
+ keywords:
7
+ - Інтернаціоналізація
8
+ - Документація
9
+ - Intlayer
10
+ - Vite
11
+ - Preact
12
+ - JavaScript
13
+ slugs:
14
+ - doc
15
+ - environment
16
+ - vite-and-preact
17
+ applicationTemplate: https://github.com/aymericzip/intlayer-vite-preact-template
18
+ history:
19
+ - version: 7.5.9
20
+ date: 2025-12-30
21
+ changes: Додано команду init
22
+ - version: 7.0.0
23
+ date: 2025-10-28
24
+ changes: Оновлено компонент LocaleRouter для використання нової конфігурації маршрутів
25
+ - version: 5.5.10
26
+ date: 2025-06-29
27
+ changes: Ініціалізація історії
28
+ ---
29
+
30
+ # Перекладіть свій вебсайт на Vite і Preact за допомогою Intlayer | Інтернаціоналізація (i18n)
31
+
32
+ > Цей пакет знаходиться в розробці. Див. [issue](https://github.com/aymericzip/intlayer/issues/118) для детальнішої інформації. Підтримайте Intlayer для Preact, поставивши лайк цьому issue
33
+
34
+ ## Зміст
35
+
36
+ <TOC/>
37
+
38
+ ## Що таке Intlayer?
39
+
40
+ **Intlayer** — це інноваційна open-source бібліотека для інтернаціоналізації (i18n), створена для спрощення багатомовної підтримки в сучасних вебзастосунках.
41
+
42
+ За допомогою Intlayer ви можете:
43
+
44
+ - **Легко керувати перекладами** за допомогою декларативних словників на рівні компонентів.
45
+ - **Динамічно локалізувати метадані**, маршрути та вміст.
46
+ - **Забезпечити підтримку TypeScript** через автогенеровані типи, що покращують автодоповнення та виявлення помилок.
47
+ - **Отримайте переваги розширених можливостей**, таких як динамічне визначення локалі та її перемикання.
48
+
49
+ ---
50
+
51
+ ## Покроковий посібник із налаштування Intlayer у застосунку на Vite і Preact
52
+
53
+ <iframe
54
+ src="https://stackblitz.com/github/aymericzip/intlayer-vite-preact-template?embed=1&ctl=1&file=intlayer.config.ts"
55
+ className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
56
+ title="Демо CodeSandbox — Як інтернаціоналізувати ваш застосунок за допомогою Intlayer"
57
+ sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
58
+ loading="lazy"
59
+ />
60
+
61
+ Перегляньте [шаблон застосунку](https://github.com/aymericzip/intlayer-vite-preact-template) на GitHub.
62
+
63
+ ### Крок 1: Встановіть залежності
64
+
65
+ Встановіть необхідні пакети за допомогою npm:
66
+
67
+ ```bash packageManager="npm"
68
+ npm install intlayer preact-intlayer
69
+ npm install vite-intlayer --save-dev
70
+ npx intlayer init
71
+ ```
72
+
73
+ ```bash packageManager="pnpm"
74
+ pnpm add intlayer preact-intlayer
75
+ pnpm add vite-intlayer --save-dev
76
+ pnpm intlayer init
77
+ ```
78
+
79
+ ```bash packageManager="yarn"
80
+ yarn add intlayer preact-intlayer
81
+ yarn add vite-intlayer --save-dev
82
+ yarn intlayer init
83
+ ```
84
+
85
+ ```bash packageManager="bun"
86
+ bun add intlayer preact-intlayer
87
+ bun add vite-intlayer --dev
88
+ bunx intlayer init
89
+ ```
90
+
91
+ - **intlayer**
92
+
93
+ Основний пакет, що надає інструменти інтернаціоналізації для керування конфігурацією, перекладу, [декларації контенту](https://github.com/aymericzip/intlayer/blob/main/docs/docs/{{locale}}/dictionary/content_file.md), транспіляції та [CLI-команд](https://github.com/aymericzip/intlayer/blob/main/docs/docs/{{locale}}/cli/index.md).
94
+
95
+ - **preact-intlayer**
96
+ Пакет, який інтегрує Intlayer у Preact-застосунок. Надає провайдери контексту та хуки для інтернаціоналізації в Preact.
97
+
98
+ - **vite-intlayer**
99
+ Містить плагін для Vite для інтеграції Intlayer з [Vite bundler](https://vite.dev/guide/why.html#why-bundle-for-production), а також middleware для визначення пріоритетної локалі користувача, керування cookie та обробки перенаправлень URL.
100
+
101
+ ### Крок 2: Налаштування вашого проєкту
102
+
103
+ Створіть файл конфігурації для налаштування мов вашого застосунку:
104
+
105
+ ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
106
+ import { Locales, type IntlayerConfig } from "intlayer";
107
+
108
+ const config: IntlayerConfig = {
109
+ internationalization: {
110
+ locales: [
111
+ Locales.ENGLISH,
112
+ Locales.FRENCH,
113
+ Locales.SPANISH,
114
+ // Ваші інші локалі
115
+ ],
116
+ defaultLocale: Locales.ENGLISH,
117
+ },
118
+ routing: {
119
+ mode: "prefix-no-default", // За замовчуванням: префіксувати всі локалі, крім локалі за замовчуванням
120
+ storage: ["cookie", "header"], // За замовчуванням: зберігати локаль у cookie та визначати з заголовка
121
+ },
122
+ };
123
+
124
+ export default config;
125
+ ```
126
+
127
+ ```javascript fileName="intlayer.config.mjs" codeFormat="esm"
128
+ import { Locales } from "intlayer";
129
+
130
+ /** @type {import('intlayer').IntlayerConfig} */
131
+ const config = {
132
+ internationalization: {
133
+ locales: [
134
+ Locales.ENGLISH,
135
+ Locales.FRENCH,
136
+ Locales.SPANISH,
137
+ // Ваші інші локалі
138
+ ],
139
+ defaultLocale: Locales.ENGLISH,
140
+ },
141
+ routing: {
142
+ mode: "prefix-no-default", // За замовчуванням: додавати префікс для всіх локалей, окрім локалі за замовчуванням
143
+ storage: ["cookie", "header"], // За замовчуванням: зберігати локаль у cookie та визначати її з заголовка
144
+ },
145
+ };
146
+
147
+ export default config;
148
+ ```
149
+
150
+ ```javascript fileName="intlayer.config.cjs" codeFormat="commonjs"
151
+ const { Locales } = require("intlayer");
152
+
153
+ /** @type {import('intlayer').IntlayerConfig} */
154
+ const config = {
155
+ internationalization: {
156
+ locales: [
157
+ Locales.ENGLISH,
158
+ Locales.FRENCH,
159
+ Locales.SPANISH,
160
+ // Ваші інші локалі
161
+ ],
162
+ defaultLocale: Locales.ENGLISH,
163
+ },
164
+ routing: {
165
+ mode: "prefix-no-default", // За замовчуванням: додавати префікс для всіх локалей, окрім локалі за замовчуванням
166
+ storage: ["cookie", "header"], // За замовчуванням: зберігати локаль в cookie і визначати з заголовка (header)
167
+ },
168
+ };
169
+
170
+ module.exports = config;
171
+ ```
172
+
173
+ > Через цей файл конфігурації ви можете налаштувати локалізовані URL-адреси, режими маршрутизації, опції збереження, імена cookie, місце розташування та розширення файлів з описом контенту, відключити логи Intlayer у консолі та інше. Для повного переліку доступних параметрів див. [документацію з конфігурації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/configuration.md).
174
+
175
+ ### Крок 3: Інтегруйте Intlayer у вашу конфігурацію Vite
176
+
177
+ Додайте плагін intlayer у конфігурацію.
178
+
179
+ ```typescript fileName="vite.config.ts" codeFormat="typescript"
180
+ import { defineConfig } from "vite";
181
+ import preact from "@preact/preset-vite";
182
+ import { intlayer } from "vite-intlayer";
183
+
184
+ // https://vitejs.dev/config/ — документація Vite
185
+ export default defineConfig({
186
+ plugins: [preact(), intlayer()],
187
+ });
188
+ ```
189
+
190
+ ```javascript fileName="vite.config.mjs" codeFormat="esm"
191
+ import { defineConfig } from "vite";
192
+ import preact from "@preact/preset-vite";
193
+ import { intlayer } from "vite-intlayer";
194
+
195
+ // https://vitejs.dev/config/ — документація Vite
196
+ export default defineConfig({
197
+ plugins: [preact(), intlayer()],
198
+ });
199
+ ```
200
+
201
+ ```javascript fileName="vite.config.cjs" codeFormat="commonjs"
202
+ const { defineConfig } = require("vite");
203
+ const preact = require("@preact/preset-vite");
204
+ const { intlayer } = require("vite-intlayer");
205
+
206
+ // https://vitejs.dev/config/ — документація Vite
207
+ module.exports = defineConfig({
208
+ plugins: [preact(), intlayer()],
209
+ });
210
+ ```
211
+
212
+ > Плагін Vite `intlayer()` використовується для інтеграції Intlayer з Vite. Він забезпечує побудову файлів декларацій контенту та відстежує їх у режимі розробки. Він визначає змінні середовища Intlayer у застосунку Vite. Додатково, він надає aliases для оптимізації продуктивності.
213
+
214
+ ### Крок 4: Оголосіть свій контент
215
+
216
+ Створіть і керуйте деклараціями контенту для зберігання перекладів:
217
+
218
+ ```tsx fileName="src/app.content.tsx" contentDeclarationFormat="typescript"
219
+ import { t, type Dictionary } from "intlayer";
220
+ import type { ComponentChildren } from "preact";
221
+
222
+ const appContent = {
223
+ key: "app",
224
+ content: {
225
+ viteLogo: t({
226
+ uk: "Логотип Vite",
227
+ en: "Vite logo",
228
+ fr: "Logo Vite",
229
+ es: "Logo Vite",
230
+ }),
231
+ preactLogo: t({
232
+ uk: "Логотип Preact",
233
+ en: "Preact logo",
234
+ fr: "Logo Preact",
235
+ es: "Logo Preact",
236
+ }),
237
+
238
+ title: "Vite + Preact",
239
+
240
+ count: t({
241
+ uk: "лічильник: ",
242
+ en: "count is ",
243
+ fr: "le compte est ",
244
+ es: "el recuento es ",
245
+ }),
246
+
247
+ edit: t<ComponentChildren>({
248
+ uk: (
249
+ <>
250
+ Редагуйте <code>src/app.tsx</code> і збережіть, щоб перевірити HMR
251
+ </>
252
+ ),
253
+ en: (
254
+ <>
255
+ Edit <code>src/app.tsx</code> and save to test HMR
256
+ </>
257
+ ),
258
+ fr: (
259
+ <>
260
+ Éditez <code>src/app.tsx</code> et enregistrez pour tester HMR
261
+ </>
262
+ ),
263
+ es: (
264
+ <>
265
+ Edita <code>src/app.tsx</code> y guarda para probar HMR
266
+ </>
267
+ ),
268
+ }),
269
+
270
+ readTheDocs: t({
271
+ uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
272
+ en: "Click on the Vite and Preact logos to learn more",
273
+ fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
274
+ uk: "Клацніть на логотипи Vite та Preact, щоб дізнатися більше",
275
+ es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
276
+ }),
277
+ },
278
+ } satisfies Dictionary;
279
+
280
+ export default appContent;
281
+ ```
282
+
283
+ ```javascript fileName="src/app.content.mjs" contentDeclarationFormat="esm"
284
+ import { t } from "intlayer";
285
+ // import { h } from 'preact'; // Потрібно, якщо ви використовуєте JSX безпосередньо в .mjs
286
+
287
+ /** @type {import('intlayer').Dictionary} */
288
+ const appContent = {
289
+ key: "app",
290
+ content: {
291
+ viteLogo: t({
292
+ uk: "Логотип Vite",
293
+ en: "Vite logo",
294
+ fr: "Logo Vite",
295
+ es: "Logo Vite",
296
+ }),
297
+ preactLogo: t({
298
+ uk: "Логотип Preact",
299
+ en: "Preact logo",
300
+ fr: "Logo Preact",
301
+ es: "Logo Preact",
302
+ }),
303
+
304
+ title: "Vite + Preact",
305
+
306
+ count: t({
307
+ uk: "лічильник ",
308
+ en: "count is ",
309
+ fr: "le compte est ",
310
+ es: "el recuento es ",
311
+ }),
312
+
313
+ edit: t({
314
+ uk: (
315
+ <>
316
+ Редагуйте <code>src/app.mjs</code> і збережіть, щоб перевірити HMR
317
+ </>
318
+ ),
319
+ edit: t({
320
+ uk: "Редагуйте src/app.jsx і збережіть, щоб протестувати HMR",
321
+ en: "Edit src/app.jsx and save to test HMR",
322
+ fr: "Éditez src/app.jsx et enregistrez pour tester HMR",
323
+ es: "Edita src/app.jsx y guarda para probar HMR",
324
+ }),
325
+
326
+ readTheDocs: t({
327
+ uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
328
+ en: "Click on the Vite and Preact logos to learn more",
329
+ fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
330
+ es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
331
+ }),
332
+ },
333
+ };
334
+
335
+ export default appContent;
336
+ ```
337
+
338
+ ```javascript fileName="src/app.content.cjs" contentDeclarationFormat="commonjs"
339
+ const { t } = require("intlayer");
340
+ // const { h } = require('preact'); // Потрібно, якщо ви використовуєте JSX безпосередньо в .cjs
341
+
342
+ /** @type {import('intlayer').Dictionary} */
343
+ const appContent = {
344
+ key: "app",
345
+ content: {
346
+ viteLogo: t({
347
+ en: "Vite logo",
348
+ uk: "Логотип Vite",
349
+ fr: "Logo Vite",
350
+ es: "Logo Vite",
351
+ }),
352
+ preactLogo: t({
353
+ uk: "Логотип Preact",
354
+ en: "Preact logo",
355
+ fr: "Logo Preact",
356
+ es: "Logo Preact",
357
+ }),
358
+
359
+ title: "Vite + Preact",
360
+
361
+ count: t({
362
+ uk: "Кількість: ",
363
+ en: "count is ",
364
+ fr: "le compte est ",
365
+ es: "el recuento es ",
366
+ }),
367
+
368
+ edit: t({
369
+ uk: "Редагуйте src/app.tsx і збережіть, щоб протестувати HMR",
370
+ en: "Edit src/app.tsx and save to test HMR",
371
+ fr: "Éditez src/app.tsx et enregistrez pour tester HMR",
372
+ es: "Edita src/app.tsx y guarda para probar HMR",
373
+ }),
374
+
375
+ readTheDocs: t({
376
+ uk: "Натисніть на логотипи Vite і Preact, щоб дізнатися більше",
377
+ en: "Click on the Vite and Preact logos to learn more",
378
+ fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
379
+ es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
380
+ }),
381
+ },
382
+ };
383
+
384
+ module.exports = appContent;
385
+ ```
386
+
387
+ ```json fileName="src/app.content.json" contentDeclarationFormat="json"
388
+ {
389
+ "$schema": "https://intlayer.org/schema.json",
390
+ "key": "app",
391
+ "content": {
392
+ "viteLogo": {
393
+ "nodeType": "translation",
394
+ "translation": {
395
+ "uk": "Логотип Vite",
396
+ "en": "Vite logo",
397
+ "fr": "Logo Vite",
398
+ "es": "Logo Vite"
399
+ }
400
+ },
401
+ "preactLogo": {
402
+ "nodeType": "translation",
403
+ "translation": {
404
+ "uk": "Логотип Preact",
405
+ "en": "Preact logo",
406
+ "fr": "Logo Preact",
407
+ "es": "Logo Preact"
408
+ }
409
+ },
410
+ "title": {
411
+ "nodeType": "translation",
412
+ "translation": {
413
+ "uk": "Vite + Preact",
414
+ "en": "Vite + Preact",
415
+ "fr": "Vite + Preact",
416
+ "es": "Vite + Preact"
417
+ }
418
+ },
419
+ "count": {
420
+ "nodeType": "translation",
421
+ "translation": {
422
+ "uk": "кількість ",
423
+ "en": "count is ",
424
+ "uk": "лічильник: ",
425
+ "fr": "le compte est ",
426
+ "es": "el recuento es "
427
+ }
428
+ },
429
+ "edit": {
430
+ "nodeType": "translation",
431
+ "translation": {
432
+ "uk": "Редагуйте src/app.tsx і збережіть, щоб перевірити HMR",
433
+ "en": "Edit src/app.tsx and save to test HMR",
434
+ "fr": "Éditez src/app.tsx et enregistrez pour tester HMR",
435
+ "es": "Edita src/app.tsx y guarda para probar HMR"
436
+ }
437
+ },
438
+ "readTheDocs": {
439
+ "nodeType": "translation",
440
+ "translation": {
441
+ "uk": "Натисніть на логотипи Vite та Preact, щоб дізнатися більше",
442
+ "en": "Click on the Vite and Preact logos to learn more",
443
+ "fr": "Cliquez sur les logos Vite et Preact pour en savoir plus",
444
+ "es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
445
+ }
446
+ }
447
+ }
448
+ }
449
+ ```
450
+
451
+ > Ваші декларації контенту можна розміщувати в будь-якій частині вашого застосунку, за умови, що вони включені в директорію `contentDir` (за замовчуванням `./src`). І вони повинні відповідати розширенню файлу декларації контенту (за замовчуванням `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`).
452
+
453
+ > Для детальнішої інформації див. [документацію з оголошень контенту](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/dictionary/content_file.md).
454
+
455
+ > Якщо ваш файл контенту містить TSX-код, можливо, потрібно імпортувати `import { h } from "preact";` або переконатися, що JSX pragma правильно налаштований для Preact.
456
+
457
+ ### Крок 5: Використання Intlayer у вашому коді
458
+
459
+ Отримуйте доступ до ваших словників контенту у всьому застосунку:
460
+
461
+ ```tsx {6,10} fileName="src/app.tsx" codeFormat="typescript"
462
+ import { useState } from "preact/hooks";
463
+ import type { FunctionalComponent } from "preact";
464
+ import preactLogo from "./assets/preact.svg"; // Припускаємо, що у вас є preact.svg
465
+ import viteLogo from "/vite.svg";
466
+ import "./app.css"; // Припускаємо, що ваш файл CSS називається app.css
467
+ import { IntlayerProvider, useIntlayer } from "preact-intlayer";
468
+
469
+ const AppContent: FunctionalComponent = () => {
470
+ const [count, setCount] = useState(0);
471
+ const content = useIntlayer("app");
472
+
473
+ return (
474
+ <>
475
+ <div>
476
+ <a href="https://vitejs.dev" target="_blank">
477
+ <img src={viteLogo} class="logo" alt={content.viteLogo.value} />
478
+ </a>
479
+ <a href="https://preactjs.com" target="_blank">
480
+ <img
481
+ src={preactLogo}
482
+ class="logo preact"
483
+ alt={content.preactLogo.value}
484
+ />
485
+ </a>
486
+ </div>
487
+ <h1>{content.title}</h1>
488
+ <div class="card">
489
+ <button onClick={() => setCount((count) => count + 1)}>
490
+ {content.count}
491
+ {count}
492
+ </button>
493
+ <p>{content.edit}</p>
494
+ </div>
495
+ <p class="read-the-docs">{content.readTheDocs}</p>
496
+ </>
497
+ );
498
+ };
499
+
500
+ const App: FunctionalComponent = () => (
501
+ <IntlayerProvider>
502
+ <AppContent />
503
+ </IntlayerProvider>
504
+ );
505
+
506
+ export default App;
507
+ ```
508
+
509
+ ```jsx {5,9} fileName="src/app.jsx" codeFormat="esm"
510
+ import { useState } from "preact/hooks";
511
+ import preactLogo from "./assets/preact.svg";
512
+ import viteLogo from "/vite.svg";
513
+ import "./app.css";
514
+ import { IntlayerProvider, useIntlayer } from "preact-intlayer";
515
+
516
+ const AppContent = () => {
517
+ const [count, setCount] = useState(0);
518
+ const content = useIntlayer("app");
519
+
520
+ return (
521
+ <>
522
+ <div>
523
+ <a href="https://vitejs.dev" target="_blank">
524
+ <img src={viteLogo} class="logo" alt={content.viteLogo.value} />
525
+ </a>
526
+ <a href="https://preactjs.com" target="_blank">
527
+ <img
528
+ src={preactLogo}
529
+ class="logo preact"
530
+ alt={content.preactLogo.value}
531
+ />
532
+ </a>
533
+ </div>
534
+ <h1>{content.title}</h1>
535
+ <div class="card">
536
+ <button onClick={() => setCount((count) => count + 1)}>
537
+ {content.count}
538
+ {count}
539
+ </button>
540
+ <p>{content.edit}</p>
541
+ </div>
542
+ <p class="read-the-docs">{content.readTheDocs}</p>
543
+ </>
544
+ );
545
+ };
546
+
547
+ const App = () => (
548
+ <IntlayerProvider>
549
+ <AppContent />
550
+ </IntlayerProvider>
551
+ );
552
+
553
+ export default App;
554
+ ```
555
+
556
+ ```jsx {5,9} fileName="src/app.cjsx" codeFormat="commonjs"
557
+ const { useState } = require("preact/hooks");
558
+ const preactLogo = require("./assets/preact.svg");
559
+ const viteLogo = require("/vite.svg");
560
+ require("./app.css");
561
+ const { IntlayerProvider, useIntlayer } = require("preact-intlayer");
562
+
563
+ const AppContent = () => {
564
+ const [count, setCount] = useState(0);
565
+ const content = useIntlayer("app");
566
+
567
+ return (
568
+ <>
569
+ <div>
570
+ <a href="https://vitejs.dev" target="_blank">
571
+ <img src={viteLogo} class="logo" alt={content.viteLogo.value} />
572
+ </a>
573
+ <a href="https://preactjs.com" target="_blank">
574
+ <img
575
+ src={preactLogo}
576
+ class="logo preact"
577
+ alt={content.preactLogo.value}
578
+ />
579
+ </a>
580
+ </div>
581
+ <h1>{content.title}</h1>
582
+ <div class="card">
583
+ <button onClick={() => setCount((count) => count + 1)}>
584
+ {content.count}
585
+ {count}
586
+ </button>
587
+ <p>{content.edit}</p>
588
+ </div>
589
+ <p class="read-the-docs">{content.readTheDocs}</p>
590
+ </>
591
+ );
592
+ };
593
+
594
+ const App = () => (
595
+ <IntlayerProvider>
596
+ <AppContent />
597
+ </IntlayerProvider>
598
+ );
599
+
600
+ module.exports = App;
601
+ ```
602
+
603
+ > Якщо ви хочете використати ваш вміст у атрибуті типу `string`, наприклад `alt`, `title`, `href`, `aria-label` тощо, ви повинні викликати значення функції, наприклад:
604
+
605
+ > ```jsx
606
+ > <img src={content.image.src.value} alt={content.image.value} />
607
+ > ```
608
+
609
+ > Примітка: у Preact `className` зазвичай пишеться як `class`.
610
+
611
+ > Щоб дізнатися більше про хук `useIntlayer`, зверніться до [документації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/react-intlayer/useIntlayer.md) (API схожий для `preact-intlayer`).
612
+
613
+ ### (Необов'язково) Крок 6: Змініть мову вашого контенту
614
+
615
+ Щоб змінити мову вашого контенту, ви можете використовувати функцію `setLocale`, надану хуком `useLocale`. Ця функція дозволяє встановити локаль застосунку та відповідно оновити контент.
616
+
617
+ ```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
618
+ import type { FunctionalComponent } from "preact";
619
+ import { Locales } from "intlayer";
620
+ import { useLocale } from "preact-intlayer";
621
+
622
+ const LocaleSwitcher: FunctionalComponent = () => {
623
+ const { setLocale } = useLocale();
624
+
625
+ return (
626
+ <button onClick={() => setLocale(Locales.ENGLISH)}>
627
+ Змінити мову на англійську
628
+ </button>
629
+ );
630
+ };
631
+
632
+ export default LocaleSwitcher;
633
+ ```
634
+
635
+ ```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
636
+ import { Locales } from "intlayer";
637
+ import { useLocale } from "preact-intlayer";
638
+
639
+ const LocaleSwitcher = () => {
640
+ const { setLocale } = useLocale();
641
+
642
+ return (
643
+ <button onClick={() => setLocale(Locales.ENGLISH)}>
644
+ Змінити мову на англійську
645
+ </button>
646
+ );
647
+ };
648
+
649
+ export default LocaleSwitcher;
650
+ ```
651
+
652
+ ```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
653
+ const { Locales } = require("intlayer");
654
+ const { useLocale } = require("preact-intlayer");
655
+
656
+ const LocaleSwitcher = () => {
657
+ const { setLocale } = useLocale();
658
+
659
+ return (
660
+ <button onClick={() => setLocale(Locales.ENGLISH)}>
661
+ Change Language to English
662
+ </button>
663
+ );
664
+ };
665
+
666
+ module.exports = LocaleSwitcher;
667
+ ```
668
+
669
+ > Щоб дізнатися більше про хук `useLocale`, зверніться до [документації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/react-intlayer/useLocale.md) (API схоже для `preact-intlayer`).
670
+
671
+ ### (Необов'язково) Крок 7: Додайте локалізовану маршрутизацію до вашого застосунку
672
+
673
+ Мета цього кроку — створити унікальні маршрути для кожної мови. Це корисно для SEO та SEO-дружніх URL-адрес.
674
+ Приклад:
675
+
676
+ ```plaintext
677
+ - https://example.com/about
678
+ - https://example.com/es/about
679
+ - https://example.com/fr/about
680
+ ```
681
+
682
+ > За замовчуванням маршрути не мають префікса для мови за замовчуванням (`routing.mode: "prefix-no-default"`). Якщо ви хочете додати префікс і для мови за замовчуванням, ви можете встановити опцію `routing.mode` в `"prefix-all"` у вашій конфігурації. Див. [документацію з конфігурації](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/configuration.md) для додаткової інформації.
683
+
684
+ Щоб додати локалізовану маршрутизацію до вашого застосунку, ви можете створити компонент `LocaleRouter`, який обгортає маршрути вашого застосунку та обробляє маршрутизацію на основі локалі. Ось приклад із використанням [preact-iso](https://github.com/preactjs/preact-iso):
685
+
686
+ Спочатку встановіть `preact-iso`:
687
+
688
+ ```bash packageManager="npm"
689
+ npm install preact-iso
690
+ npx intlayer init
691
+ ```
692
+
693
+ ```bash packageManager="pnpm"
694
+ pnpm add preact-iso
695
+ pnpm intlayer init
696
+ ```
697
+
698
+ ```bash packageManager="yarn"
699
+ yarn add preact-iso
700
+ ```
701
+
702
+ ```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
703
+ import { configuration, getPathWithoutLocale, type Locale } from "intlayer";
704
+ import type { ComponentChildren, FunctionalComponent } from "preact";
705
+ import { useEffect } from "preact/hooks";
706
+ import { IntlayerProvider } from "preact-intlayer";
707
+ import { LocationProvider, useLocation } from "preact-iso";
708
+
709
+ const { internationalization, routing } = configuration;
710
+ const { locales, defaultLocale } = internationalization;
711
+
712
+ const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({
713
+ to,
714
+ replace,
715
+ }) => {
716
+ const { route } = useLocation();
717
+ useEffect(() => {
718
+ route(to, replace);
719
+ }, [to, replace, route]);
720
+ return null;
721
+ };
722
+
723
+ /**
724
+ * Компонент, який обробляє локалізацію і обгортає дочірні елементи у відповідний контекст локалі.
725
+ * Він керує визначенням локалі на основі URL та її валідацією.
726
+ */
727
+ const AppLocalized: FunctionalComponent<{
728
+ children: ComponentChildren;
729
+ locale?: Locale;
730
+ }> = ({ children, locale }) => {
731
+ const { path: pathname, url } = useLocation();
732
+
733
+ if (!url) {
734
+ return null;
735
+ }
736
+
737
+ const search = url.substring(pathname.length);
738
+
739
+ // Визначає поточну локаль — використовується передана locale або локаль за замовчуванням
740
+ const currentLocale = locale ?? defaultLocale;
741
+
742
+ // Видаляє префікс локалі з шляху для побудови базового шляху
743
+ const pathWithoutLocale = getPathWithoutLocale(
744
+ pathname // Поточний шлях URL
745
+ );
746
+
747
+ /**
748
+ * Якщо routing.mode === 'prefix-all', локаль за замовчуванням повинна завжди мати префікс.
749
+ */
750
+ if (routing.mode === "prefix-all") {
751
+ // Перевірити локаль
752
+ if (!locale || !locales.includes(locale)) {
753
+ // Перенаправити на локаль за замовчуванням з оновленим шляхом
754
+ return (
755
+ <Navigate
756
+ to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
757
+ replace // Замінити поточний запис історії новим
758
+ />
759
+ );
760
+ }
761
+
762
+ // Огорнути children через IntlayerProvider і встановити поточну локаль
763
+ return (
764
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
765
+ );
766
+ } else {
767
+ /**
768
+ * Коли routing.mode не дорівнює 'prefix-all', локаль за замовчуванням не має префікса.
769
+ * Переконатися, що поточна локаль дійсна і не є локаллю за замовчуванням.
770
+ */
771
+ if (
772
+ currentLocale.toString() !== defaultLocale.toString() &&
773
+ !locales
774
+ .filter(
775
+ (loc) => loc.toString() !== defaultLocale.toString() // Виключити локаль за замовчуванням
776
+ )
777
+ .includes(currentLocale) // Перевірити, чи поточна локаль є в списку дійсних локалей
778
+ ) {
779
+ // Перенаправити на шлях без префікса локалі
780
+ return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
781
+ }
782
+
783
+ // Обгорнути children у IntlayerProvider і встановити поточну локаль
784
+ return (
785
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
786
+ );
787
+ }
788
+ };
789
+
790
+ const RouterContent: FunctionalComponent<{
791
+ children: ComponentChildren;
792
+ }> = ({ children }) => {
793
+ const { path } = useLocation();
794
+
795
+ if (!path) {
796
+ return null;
797
+ }
798
+
799
+ const pathLocale = path.split("/")[1] as Locale;
800
+
801
+ const isLocaleRoute = locales
802
+ .filter(
803
+ (locale) => routing.mode === "prefix-all" || locale !== defaultLocale
804
+ )
805
+ .some((locale) => locale.toString() === pathLocale);
806
+
807
+ if (isLocaleRoute) {
808
+ return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
809
+ }
810
+
811
+ return (
812
+ <AppLocalized
813
+ locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
814
+ >
815
+ {children}
816
+ </AppLocalized>
817
+ );
818
+ };
819
+
820
+ /**
821
+ * Компонент роутера, який налаштовує маршрути, специфічні для локалі.
822
+ * Використовує preact-iso для керування навігацією та рендерингу локалізованих компонентів.
823
+ */
824
+ export const LocaleRouter: FunctionalComponent<{
825
+ children: ComponentChildren;
826
+ }> = ({ children }) => (
827
+ <LocationProvider>
828
+ <RouterContent>{children}</RouterContent>
829
+ </LocationProvider>
830
+ );
831
+ ```
832
+
833
+ ```jsx fileName="src/components/LocaleRouter.jsx" codeFormat="esm"
834
+ // Імпорт необхідних залежностей та функцій
835
+ import { configuration, getPathWithoutLocale } from "intlayer";
836
+ import { IntlayerProvider } from "preact-intlayer";
837
+ import { LocationProvider, useLocation } from "preact-iso";
838
+ import { useEffect } from "preact/hooks";
839
+ import { h } from "preact"; // Потрібно для JSX
840
+
841
+ // Деструктуризація конфігурації з Intlayer
842
+ const { internationalization, routing } = configuration;
843
+ const { locales, defaultLocale } = internationalization;
844
+
845
+ const Navigate = ({ to, replace }) => {
846
+ const { route } = useLocation();
847
+ useEffect(() => {
848
+ route(to, replace);
849
+ }, [to, replace, route]);
850
+ return null;
851
+ };
852
+
853
+ /**
854
+ /**
855
+ * Компонент, що обробляє локалізацію та обгортає children відповідним контекстом локалі.
856
+ * Він керує визначенням локалі на основі URL та перевіркою коректності локалі.
857
+ */
858
+ const AppLocalized = ({ children, locale }) => {
859
+ const { path: pathname, url } = useLocation();
860
+
861
+ if (!url) {
862
+ return null;
863
+ }
864
+
865
+ const search = url.substring(pathname.length);
866
+
867
+ // Визначає поточну локаль, за замовчуванням використовується defaultLocale, якщо не передано
868
+ const currentLocale = locale ?? defaultLocale;
869
+
870
+ // Видаляє префікс локалі з шляху для побудови базового шляху
871
+ const pathWithoutLocale = getPathWithoutLocale(
872
+ pathname // Поточний шлях URL
873
+ );
874
+
875
+ /**
876
+ * Якщо routing.mode === "prefix-all", локаль за замовчуванням завжди має бути з префіксом.
877
+ */
878
+ if (routing.mode === "prefix-all") {
879
+ // Перевіряє локаль
880
+ if (!locale || !locales.includes(locale)) {
881
+ // Перенаправлення до мови за замовчуванням з оновленим шляхом
882
+ return (
883
+ <Navigate
884
+ to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
885
+ replace // Замінити поточний запис історії на новий
886
+ />
887
+ );
888
+ }
889
+
890
+ // Обгорнути дочірні елементи IntlayerProvider та встановити поточну локаль
891
+ return (
892
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
893
+ );
894
+ } else {
895
+ /**
896
+ * Коли routing.mode не 'prefix-all', префікс мови за замовчуванням не додається.
897
+ * Переконайтесь, що поточна локаль дійсна і не є локаллю за замовчуванням.
898
+ */
899
+ if (
900
+ currentLocale.toString() !== defaultLocale.toString() &&
901
+ !locales
902
+ .filter(
903
+ (loc) => loc.toString() !== defaultLocale.toString() // Не включати мову за замовчуванням
904
+ )
905
+ .includes(currentLocale) // Перевіряє, чи поточна локаль є в списку дійсних локалей
906
+ ) {
907
+ // Перенаправити на шлях без префікса локалі
908
+ return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
909
+ }
910
+
911
+ // Обгорнути children у IntlayerProvider та встановити поточну локаль
912
+ return (
913
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
914
+ );
915
+ }
916
+ };
917
+
918
+ const RouterContent = ({ children }) => {
919
+ const { path } = useLocation();
920
+
921
+ if (!path) {
922
+ return null;
923
+ }
924
+
925
+ const pathLocale = path.split("/")[1];
926
+
927
+ const isLocaleRoute = locales
928
+ .filter(
929
+ (locale) => routing.mode === "prefix-all" || locale !== defaultLocale
930
+ )
931
+ .some((locale) => locale.toString() === pathLocale);
932
+
933
+ if (isLocaleRoute) {
934
+ return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
935
+ }
936
+
937
+ return (
938
+ <AppLocalized
939
+ locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
940
+ >
941
+ {children}
942
+ </AppLocalized>
943
+ );
944
+ };
945
+
946
+ /**
947
+ * Компонент роутера, що налаштовує маршрути з урахуванням локалі.
948
+ * Використовує preact-iso для керування навігацією та рендерингу локалізованих компонентів.
949
+ */
950
+ export const LocaleRouter = ({ children }) => (
951
+ <LocationProvider>
952
+ <RouterContent>{children}</RouterContent>
953
+ </LocationProvider>
954
+ );
955
+ ```
956
+
957
+ ```jsx fileName="src/components/LocaleRouter.cjsx" codeFormat="commonjs"
958
+ // Імпорт необхідних залежностей та функцій
959
+ const { configuration, getPathWithoutLocale } = require("intlayer");
960
+ const { IntlayerProvider } = require("preact-intlayer");
961
+ const { LocationProvider, useLocation } = require("preact-iso");
962
+ const { useEffect } = require("preact/hooks");
963
+ const { h } = require("preact"); // Потрібно для JSX
964
+
965
+ // Деструктуризація конфігурації з Intlayer
966
+ const { internationalization, routing } = configuration;
967
+ const { locales, defaultLocale } = internationalization;
968
+
969
+ const Navigate = ({ to, replace }) => {
970
+ const { route } = useLocation();
971
+ useEffect(() => {
972
+ route(to, replace);
973
+ }, [to, replace, route]);
974
+ return null;
975
+ };
976
+
977
+ /**
978
+ * Компонент, який обробляє локалізацію та обгортає дочірні елементи відповідним локалізованим контекстом.
979
+ * Він керує визначенням локалі на основі URL та її валідацією.
980
+ */
981
+ const AppLocalized = ({ children, locale }) => {
982
+ const { path: pathname, url } = useLocation();
983
+
984
+ if (!url) {
985
+ return null;
986
+ }
987
+
988
+ const search = url.substring(pathname.length);
989
+
990
+ // Визначаємо поточну локаль, за відсутності — використовується локаль за замовчуванням
991
+ const currentLocale = locale ?? defaultLocale;
992
+
993
+ // Видаляємо префікс локалі з шляху, щоб створити базовий шлях
994
+ const pathWithoutLocale = getPathWithoutLocale(
995
+ pathname // Поточний шлях URL
996
+ );
997
+
998
+ /**
999
+ * Якщо routing.mode === 'prefix-all', локаль за замовчуванням завжди повинна мати префікс.
1000
+ */
1001
+ if (routing.mode === "prefix-all") {
1002
+ // Перевіряємо локаль
1003
+ if (!locale || !locales.includes(locale)) {
1004
+ // Перенаправляємо на локаль за замовчуванням з оновленим шляхом
1005
+ return (
1006
+ <Navigate
1007
+ to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
1008
+ replace // Замінити поточний запис у історії на новий
1009
+ />
1010
+ );
1011
+ }
1012
+
1013
+ // Обгорнути children у IntlayerProvider і встановити поточну локаль
1014
+ return (
1015
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
1016
+ );
1017
+ } else {
1018
+ /**
1019
+ * Коли routing.mode не 'prefix-all', префікс для локалі за замовчуванням не додається.
1020
+ * Переконайтесь, що поточна локаль дійсна і не є локаллю за замовчуванням.
1021
+ */
1022
+ if (
1023
+ currentLocale.toString() !== defaultLocale.toString() &&
1024
+ !locales
1025
+ .filter(
1026
+ (loc) => loc.toString() !== defaultLocale.toString() // Виключити локаль за замовчуванням
1027
+ )
1028
+ .includes(currentLocale) // Перевірити, чи поточна локаль є в списку дійсних локалей
1029
+ ) {
1030
+ // Перенаправлення на шлях без префіксу локалі
1031
+ return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
1032
+ }
1033
+
1034
+ // Обгорнути дочірні елементи в IntlayerProvider і встановити поточну локаль
1035
+ return (
1036
+ <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
1037
+ );
1038
+ }
1039
+ };
1040
+
1041
+ const RouterContent = ({ children }) => {
1042
+ const { path } = useLocation();
1043
+
1044
+ if (!path) {
1045
+ return null;
1046
+ }
1047
+
1048
+ const pathLocale = path.split("/")[1];
1049
+
1050
+ const isLocaleRoute = locales
1051
+ .filter(
1052
+ (locale) => routing.mode === "prefix-all" || locale !== defaultLocale
1053
+ )
1054
+ .some((locale) => locale.toString() === pathLocale);
1055
+
1056
+ if (isLocaleRoute) {
1057
+ return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
1058
+ }
1059
+
1060
+ return (
1061
+ <AppLocalized
1062
+ locale={routing.mode !== "prefix-all" ? defaultLocale : undefined}
1063
+ >
1064
+ {children}
1065
+ </AppLocalized>
1066
+ );
1067
+ };
1068
+
1069
+ /**
1070
+ * Компонент роутера, який налаштовує маршрути для конкретних локалей.
1071
+ * Він використовує preact-iso для керування навігацією та відображення локалізованих компонентів.
1072
+ */
1073
+ const LocaleRouter = ({ children }) => (
1074
+ <LocationProvider>
1075
+ <RouterContent>{children}</RouterContent>
1076
+ </LocationProvider>
1077
+ );
1078
+
1079
+ module.exports = { LocaleRouter };
1080
+ ```
1081
+
1082
+ Потім ви можете використовувати компонент `LocaleRouter` у вашому застосунку:
1083
+
1084
+ ```tsx fileName="src/app.tsx" codeFormat="typescript"
1085
+ import { LocaleRouter } from "./components/LocaleRouter";
1086
+ import type { FunctionalComponent } from "preact";
1087
+ // ... Ваш компонент AppContent (визначено в кроці 5)
1088
+
1089
+ const App: FunctionalComponent = () => (
1090
+ <LocaleRouter>
1091
+ <AppContent />
1092
+ </LocaleRouter>
1093
+ );
1094
+
1095
+ export default App;
1096
+ ```
1097
+
1098
+ ```jsx fileName="src/app.jsx" codeFormat="esm"
1099
+ import { LocaleRouter } from "./components/LocaleRouter";
1100
+ // ... Ваш компонент AppContent (визначений у кроці 5)
1101
+
1102
+ const App = () => (
1103
+ <LocaleRouter>
1104
+ <AppContent />
1105
+ </LocaleRouter>
1106
+ );
1107
+
1108
+ export default App;
1109
+ ```
1110
+
1111
+ ```jsx fileName="src/app.cjsx" codeFormat="commonjs"
1112
+ const { LocaleRouter } = require("./components/LocaleRouter");
1113
+ // ... Ваш компонент AppContent (визначений у кроці 5)
1114
+
1115
+ const App = () => (
1116
+ <LocaleRouter>
1117
+ <AppContent />
1118
+ </LocaleRouter>
1119
+ );
1120
+
1121
+ module.exports = App;
1122
+ ```
1123
+
1124
+ Паралельно ви також можете використовувати `intlayerProxy` для додавання серверної маршрутизації до вашого додатка. Цей плагін автоматично визначатиме поточну локаль на основі URL і встановлюватиме відповідний cookie локалі. Якщо локаль не вказана, плагін визначить найвідповіднішу локаль на основі мовних налаштувань браузера користувача. Якщо ж локаль не буде виявлена, він перенаправить на локаль за замовчуванням.
1125
+
1126
+ > Зауважте, що для використання `intlayerProxy` у production потрібно перемістити пакет `vite-intlayer` з `devDependencies` до `dependencies`.
1127
+
1128
+ ```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
1129
+ import { defineConfig } from "vite";
1130
+ import preact from "@preact/preset-vite";
1131
+ import { intlayer, intlayerProxy } from "vite-intlayer";
1132
+
1133
+ // https://vitejs.dev/config/ (див. документацію Vite)
1134
+ export default defineConfig({
1135
+ plugins: [preact(), intlayer(), intlayerProxy()],
1136
+ });
1137
+ ```
1138
+
1139
+ ```javascript {3,7} fileName="vite.config.mjs" codeFormat="esm"
1140
+ import { defineConfig } from "vite";
1141
+ import preact from "@preact/preset-vite";
1142
+ import { intlayer, intlayerProxy } from "vite-intlayer";
1143
+
1144
+ // Документація: https://vitejs.dev/config/
1145
+ export default defineConfig({
1146
+ plugins: [preact(), intlayer(), intlayerProxy()],
1147
+ });
1148
+ ```
1149
+
1150
+ ```javascript {3,7} fileName="vite.config.cjs" codeFormat="commonjs"
1151
+ const { defineConfig } = require("vite");
1152
+ const preact = require("@preact/preset-vite");
1153
+ const { intlayer, intlayerProxy } = require("vite-intlayer");
1154
+
1155
+ // Документація: https://vitejs.dev/config/
1156
+ module.exports = defineConfig({
1157
+ plugins: [preact(), intlayer(), intlayerProxy()],
1158
+ });
1159
+ ```
1160
+
1161
+ ### (Необов'язково) Крок 8: Змінити URL при зміні локалі
1162
+
1163
+ Щоб змінювати URL при зміні локалі, ви можете використовувати пропс `onLocaleChange`, який надає хук `useLocale`. Паралельно можна використовувати `useLocation` та `route` з `preact-iso` для оновлення шляху URL.
1164
+
1165
+ ```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
1166
+ import { useLocation, route } from "preact-iso";
1167
+ import {
1168
+ Locales,
1169
+ getHTMLTextDir,
1170
+ getLocaleName,
1171
+ getLocalizedUrl,
1172
+ } from "intlayer";
1173
+ import { useLocale } from "preact-intlayer";
1174
+ import type { FunctionalComponent } from "preact";
1175
+
1176
+ const LocaleSwitcher: FunctionalComponent = () => {
1177
+ const location = useLocation();
1178
+ const { locale, availableLocales, setLocale } = useLocale({
1179
+ onLocaleChange: (newLocale) => {
1180
+ const currentFullPath = location.url; // preact-iso надає повний URL
1181
+ // Сформувати URL з оновленою локаллю
1182
+ // Приклад: /es/about?foo=bar
1183
+ const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
1184
+
1185
+ // Оновити шлях URL
1186
+ route(pathWithLocale, true); // true для заміни
1187
+ },
1188
+ });
1189
+
1190
+ return (
1191
+ <div>
1192
+ <button popovertarget="localePopover">{getLocaleName(locale)}</button>
1193
+ <div id="localePopover" popover="auto">
1194
+ {availableLocales.map((localeItem) => (
1195
+ <a
1196
+ href={getLocalizedUrl(location.url, localeItem)}
1197
+ hreflang={localeItem}
1198
+ aria-current={locale === localeItem ? "page" : undefined}
1199
+ onClick={(e) => {
1200
+ e.preventDefault();
1201
+ setLocale(localeItem);
1202
+ // Програмна навігація після зміни локалі обробляється onLocaleChange
1203
+ }}
1204
+ key={localeItem}
1205
+ >
1206
+ <span>
1207
+ {/* Локаль — наприклад FR */}
1208
+ {localeItem}
1209
+ </span>
1210
+ <span>
1211
+ {/* Мова у своїй локалі — наприклад Français */}
1212
+ {getLocaleName(localeItem, localeItem)}
1213
+ </span>
1214
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1215
+ {/* Мова у поточній локалі — наприклад Francés коли поточна локаль встановлена на Locales.SPANISH */}
1216
+ {getLocaleName(localeItem, locale)}
1217
+ </span>
1218
+ <span dir="ltr" lang={Locales.ENGLISH}>
1219
+ {/* Мова англійською — наприклад French */}
1220
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1221
+ </span>
1222
+ </a>
1223
+ ))}
1224
+ </div>
1225
+ </div>
1226
+ );
1227
+ };
1228
+
1229
+ export default LocaleSwitcher;
1230
+ ```
1231
+
1232
+ ```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
1233
+ import { useLocation, route } from "preact-iso";
1234
+ import {
1235
+ Locales,
1236
+ getHTMLTextDir,
1237
+ getLocaleName,
1238
+ getLocalizedUrl,
1239
+ } from "intlayer";
1240
+ import { useLocale } from "preact-intlayer";
1241
+ import { h } from "preact"; // Для JSX
1242
+
1243
+ const LocaleSwitcher = () => {
1244
+ const location = useLocation();
1245
+ const { locale, availableLocales, setLocale } = useLocale({
1246
+ onLocaleChange: (newLocale) => {
1247
+ const currentFullPath = location.url;
1248
+ const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
1249
+ route(pathWithLocale, true);
1250
+ },
1251
+ });
1252
+
1253
+ return (
1254
+ <div>
1255
+ <button popovertarget="localePopover">{getLocaleName(locale)}</button>
1256
+ <div id="localePopover" popover="auto">
1257
+ {availableLocales.map((localeItem) => (
1258
+ <a
1259
+ href={getLocalizedUrl(location.url, localeItem)}
1260
+ hreflang={localeItem}
1261
+ aria-current={locale === localeItem ? "page" : undefined}
1262
+ onClick={(e) => {
1263
+ e.preventDefault();
1264
+ setLocale(localeItem);
1265
+ }}
1266
+ key={localeItem}
1267
+ >
1268
+ <span>{localeItem}</span>
1269
+ <span>{getLocaleName(localeItem, localeItem)}</span>
1270
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1271
+ {getLocaleName(localeItem, locale)}
1272
+ </span>
1273
+ <span dir="ltr" lang={Locales.ENGLISH}>
1274
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1275
+ </span>
1276
+ </a>
1277
+ ))}
1278
+ </div>
1279
+ </div>
1280
+ );
1281
+ };
1282
+
1283
+ export default LocaleSwitcher;
1284
+ ```
1285
+
1286
+ ```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
1287
+ const { useLocation, route } = require("preact-iso");
1288
+ const {
1289
+ Locales,
1290
+ getHTMLTextDir,
1291
+ getLocaleName,
1292
+ getLocalizedUrl,
1293
+ } = require("intlayer");
1294
+ const { useLocale } = require("preact-intlayer");
1295
+ const { h } = require("preact"); // Для JSX
1296
+
1297
+ const LocaleSwitcher = () => {
1298
+ const location = useLocation();
1299
+ const { locale, availableLocales, setLocale } = useLocale({
1300
+ onLocaleChange: (newLocale) => {
1301
+ const currentFullPath = location.url;
1302
+ const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
1303
+ route(pathWithLocale, true);
1304
+ },
1305
+ });
1306
+
1307
+ return (
1308
+ <div>
1309
+ <button popovertarget="localePopover">{getLocaleName(locale)}</button>
1310
+ <div id="localePopover" popover="auto">
1311
+ {availableLocales.map((localeItem) => (
1312
+ <a
1313
+ href={getLocalizedUrl(location.url, localeItem)}
1314
+ hreflang={localeItem}
1315
+ aria-current={locale === localeItem ? "page" : undefined}
1316
+ onClick={(e) => {
1317
+ e.preventDefault();
1318
+ setLocale(localeItem);
1319
+ }}
1320
+ key={localeItem}
1321
+ >
1322
+ <span>{localeItem}</span>
1323
+ <span>{getLocaleName(localeItem, localeItem)}</span>
1324
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1325
+ {getLocaleName(localeItem, locale)}
1326
+ </span>
1327
+ <span dir="ltr" lang={Locales.ENGLISH}>
1328
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1329
+ </span>
1330
+ </a>
1331
+ ))}
1332
+ </div>
1333
+ </div>
1334
+ );
1335
+ };
1336
+
1337
+ module.exports = LocaleSwitcher;
1338
+ ```
1339
+
1340
+ > Посилання на документацію:
1341
+ >
1342
+ > > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/react-intlayer/useLocale.md) (API схоже для `preact-intlayer`)> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getLocaleName.md)> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getLocalizedUrl.md)> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/packages/intlayer/getHTMLTextDir.md)> - [атрибут `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)> - [атрибут `lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)> - [атрибут `dir`](https://developer.mozilla.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)
1343
+
1344
+ Нижче оновлений **Крок 9** з додатковими поясненнями та вдосконаленими прикладами коду:
1345
+
1346
+ ---
1347
+
1348
+ ### (Необов'язково) Крок 9: Переключення атрибутів мови та напрямку в HTML
1349
+
1350
+ Коли ваш додаток підтримує кілька мов, важливо оновлювати атрибути `lang` та `dir` тегу `<html>`, щоб вони відповідали поточній локалі. Це гарантує:
1351
+
1352
+ - **Доступність**: Скрінрідери та допоміжні технології покладаються на правильний атрибут `lang` для коректного промовляння та інтерпретації вмісту.
1353
+ - **Відображення тексту**: Атрибут `dir` (direction) забезпечує правильний порядок відображення тексту (наприклад, зліва направо для англійської, справа наліво для арабської чи івриту), що є необхідним для читабельності.
1354
+ - **SEO**: Пошукові системи використовують атрибут `lang`, щоб визначити мову вашої сторінки, що допомагає показувати відповідний локалізований контент у результатах пошуку.
1355
+
1356
+ Оновлюючи ці атрибути динамічно при зміні локалі, ви забезпечуєте послідовний та доступний досвід для користувачів усіх підтримуваних мов.
1357
+
1358
+ #### Реалізація хука
1359
+
1360
+ Створіть власний хук для керування HTML-атрибутами. Хук відслідковує зміни локалі й відповідно оновлює атрибути:
1361
+
1362
+ ```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx" codeFormat="typescript"
1363
+ import { useEffect } from "preact/hooks";
1364
+ import { useLocale } from "preact-intlayer";
1365
+ import { getHTMLTextDir } from "intlayer";
1366
+
1367
+ /**
1368
+ * Оновлює атрибути `lang` та `dir` елемента <html> на основі поточної локалі.
1369
+ * - `lang`: Повідомляє браузерам та пошуковим системам мову сторінки.
1370
+ * - `dir`: Забезпечує правильний порядок читання (наприклад, 'ltr' для англійської, 'rtl' для арабської).
1371
+ *
1372
+ * Це динамічне оновлення має вирішальне значення для правильного відтворення тексту, доступності та SEO.
1373
+ */
1374
+ export const useI18nHTMLAttributes = () => {
1375
+ const { locale } = useLocale();
1376
+
1377
+ useEffect(() => {
1378
+ // Оновлює атрибут lang елемента відповідно до поточної локалі.
1379
+ document.documentElement.lang = locale;
1380
+
1381
+ // Встановлює напрямок тексту залежно від поточної локалі.
1382
+ document.documentElement.dir = getHTMLTextDir(locale);
1383
+ }, [locale]);
1384
+ };
1385
+ ```
1386
+
1387
+ ```jsx fileName="src/hooks/useI18nHTMLAttributes.jsx" codeFormat="esm"
1388
+ import { useEffect } from "preact/hooks";
1389
+ import { useLocale } from "preact-intlayer";
1390
+ import { getHTMLTextDir } from "intlayer";
1391
+
1392
+ /**
1393
+ * Оновлює атрибути `lang` та `dir` елемента <html> залежно від поточної локалі.
1394
+ */
1395
+ export const useI18nHTMLAttributes = () => {
1396
+ const { locale } = useLocale();
1397
+
1398
+ useEffect(() => {
1399
+ document.documentElement.lang = locale;
1400
+ document.documentElement.dir = getHTMLTextDir(locale);
1401
+ }, [locale]);
1402
+ };
1403
+ ```
1404
+
1405
+ ```jsx fileName="src/hooks/useI18nHTMLAttributes.cjsx" codeFormat="commonjs"
1406
+ const { useEffect } = require("preact/hooks");
1407
+ const { useLocale } = require("preact-intlayer");
1408
+ const { getHTMLTextDir } = require("intlayer");
1409
+
1410
+ /**
1411
+ * Оновлює атрибути `lang` та `dir` елемента <html> залежно від поточної локалі.
1412
+ */
1413
+ const useI18nHTMLAttributes = () => {
1414
+ const { locale } = useLocale();
1415
+
1416
+ useEffect(() => {
1417
+ document.documentElement.lang = locale;
1418
+ document.documentElement.dir = getHTMLTextDir(locale);
1419
+ }, [locale]);
1420
+ };
1421
+
1422
+ module.exports = { useI18nHTMLAttributes };
1423
+ ```
1424
+
1425
+ #### Використання хука у вашому застосунку
1426
+
1427
+ Інтегруйте хук у ваш головний компонент, щоб атрибути HTML оновлювалися щоразу при зміні локалі:
1428
+
1429
+ ```tsx fileName="src/app.tsx" codeFormat="typescript"
1430
+ import type { FunctionalComponent } from "preact";
1431
+ import { IntlayerProvider } from "preact-intlayer"; // useIntlayer вже імпортовано, якщо AppContent його потребує
1432
+ import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
1433
+ import "./app.css";
1434
+ // Визначення AppContent з Кроку 5
1435
+
1436
+ const AppWithHooks: FunctionalComponent = () => {
1437
+ // Застосовуємо хук, щоб оновити атрибути lang і dir елемента <html> відповідно до локалі.
1438
+ useI18nHTMLAttributes();
1439
+
1440
+ // Припускаючи, що AppContent — ваш основний компонент для відображення вмісту з Кроку 5
1441
+ return <AppContent />;
1442
+ };
1443
+
1444
+ const App: FunctionalComponent = () => (
1445
+ <IntlayerProvider>
1446
+ <AppWithHooks />
1447
+ </IntlayerProvider>
1448
+ );
1449
+
1450
+ export default App;
1451
+ ```
1452
+
1453
+ ```jsx fileName="src/app.jsx" codeFormat="esm"
1454
+ import { IntlayerProvider } from "preact-intlayer";
1455
+ import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
1456
+ import "./app.css";
1457
+ // Визначення AppContent з Кроку 5
1458
+
1459
+ const AppWithHooks = () => {
1460
+ useI18nHTMLAttributes();
1461
+ return <AppContent />;
1462
+ };
1463
+
1464
+ const App = () => (
1465
+ <IntlayerProvider>
1466
+ <AppWithHooks />
1467
+ </IntlayerProvider>
1468
+ );
1469
+
1470
+ export default App;
1471
+ ```
1472
+
1473
+ ```jsx fileName="src/app.cjsx" codeFormat="commonjs"
1474
+ const { IntlayerProvider } = require("preact-intlayer");
1475
+ const { useI18nHTMLAttributes } = require("./hooks/useI18nHTMLAttributes");
1476
+ require("./app.css");
1477
+ // Визначення AppContent із кроку 5
1478
+
1479
+ const AppWithHooks = () => {
1480
+ useI18nHTMLAttributes();
1481
+ return <AppContent />;
1482
+ };
1483
+
1484
+ const App = () => (
1485
+ <IntlayerProvider>
1486
+ <AppWithHooks />
1487
+ </IntlayerProvider>
1488
+ );
1489
+
1490
+ module.exports = App;
1491
+ ```
1492
+
1493
+ Застосувавши ці зміни, ваш додаток буде:
1494
+
1495
+ - Забезпечувати, що атрибут **language** (`lang`) правильно відображає поточну локаль, що важливо для SEO та поведінки браузера.
1496
+ - Підлаштовувати **напрямок тексту** (`dir`) відповідно до локалі, покращуючи читабельність та зручність використання для мов із різними напрямками читання.
1497
+ - Забезпечити більш **доступний** досвід, оскільки засоби допомоги (assistive technologies) залежать від цих атрибутів для оптимальної роботи.
1498
+
1499
+ ### (Необов'язково) Крок 10: Створення локалізованого компонента `Link`
1500
+
1501
+ Щоб переконатися, що навігація вашого додатка дотримується поточної локалі, ви можете створити власний компонент `Link`. Цей компонент автоматично додає префікс мови до внутрішніх URL.
1502
+
1503
+ Ця поведінка корисна з кількох причин:
1504
+
1505
+ - **SEO та User Experience**: локалізовані URL допомагають пошуковим системам правильно індексувати сторінки за мовами та надають користувачам контент їхньою бажаною мовою.
1506
+ - **Consistency**: використовуючи локалізоване посилання по всьому додатку, ви гарантуєте, що навігація залишатиметься в поточній локалі, запобігаючи несподіваним перемиканням мови.
1507
+ - **Підтримуваність**: Централізація логіки локалізації в одному компоненті спрощує керування URL-адресами.
1508
+
1509
+ Для Preact з `preact-iso` зазвичай використовуються стандартні теги `<a>` для навігації, а `preact-iso` відповідає за маршрутизацію. Якщо вам потрібна програмна навігація по кліку (наприклад, щоб виконати дії перед переходом), ви можете використовувати функцію `route` з `useLocation`. Ось як можна створити власний компонент anchor, що локалізує URL-адреси:
1510
+
1511
+ ```tsx fileName="src/components/LocalizedLink.tsx" codeFormat="typescript"
1512
+ import { getLocalizedUrl } from "intlayer";
1513
+ import { useLocale, useLocation, route } from "preact-intlayer"; // Припускається, що useLocation та route можуть бути експортовані з preact-iso через preact-intlayer, або імпортуватися безпосередньо
1514
+ // Якщо не реекспортується, імпортуйте безпосередньо: import { useLocation, route } from "preact-iso";
1515
+ import type { JSX } from "preact"; // Для HTMLAttributes
1516
+ import { forwardRef } from "preact/compat"; // Для передачі ref
1517
+
1518
+ export interface LocalizedLinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
1519
+ href: string;
1520
+ replace?: boolean; // Необов'язково: замінює стан історії
1521
+ }
1522
+
1523
+ /**
1524
+ * Утиліта для перевірки, чи є вказаний URL зовнішнім.
1525
+ * Якщо URL починається з http:// або https://, він вважається зовнішнім.
1526
+ */
1527
+ export const checkIsExternalLink = (href?: string): boolean =>
1528
+ /^https?:\/\//.test(href ?? "");
1529
+
1530
+ /**
1531
+ * Кастомний компонент Link, який адаптує атрибут href відповідно до поточної локалі.
1532
+ */
1533
+ * Для внутрішніх посилань використовується `getLocalizedUrl` для додавання префіксу локалі до URL (наприклад, /fr/about).
1534
+ * Це гарантує, що навігація залишатиметься в межах контексту тієї самої локалі.
1535
+ * Використовується стандартний тег <a>, але може ініціювати навігацію на клієнті за допомогою `route` з preact-iso.
1536
+ */
1537
+ export const LocalizedLink = forwardRef<HTMLAnchorElement, LocalizedLinkProps>(
1538
+ ({ href, children, onClick, replace = false, ...props }, ref) => {
1539
+ const { locale } = useLocale();
1540
+ const location = useLocation(); // з preact-iso
1541
+ const isExternalLink = checkIsExternalLink(href);
1542
+
1543
+ const hrefI18n =
1544
+ href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
1545
+
1546
+ const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
1547
+ if (onClick) {
1548
+ onClick(event);
1549
+ }
1550
+ if (
1551
+ !isExternalLink &&
1552
+ href && // Переконайтесь, що href визначено
1553
+ event.button === 0 && // Лівий клік
1554
+ !event.metaKey &&
1555
+ !event.ctrlKey &&
1556
+ !event.shiftKey &&
1557
+ !event.altKey && // Перевірка стандартних модифікаторів
1558
+ !props.target // Не відкривати в новій вкладці/вікні
1559
+ ) {
1560
+ event.preventDefault();
1561
+ if (location.url !== hrefI18n) {
1562
+ // Перехід лише якщо URL відрізняється
1563
+ route(hrefI18n, replace); // Використовуємо route з preact-iso
1564
+ }
1565
+ }
1566
+ };
1567
+
1568
+ return (
1569
+ <a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
1570
+ {children}
1571
+ </a>
1572
+ );
1573
+ }
1574
+ );
1575
+ ```
1576
+
1577
+ ```jsx fileName="src/components/LocalizedLink.jsx" codeFormat="esm"
1578
+ import { getLocalizedUrl } from "intlayer";
1579
+ import { useLocale } from "preact-intlayer";
1580
+ import { useLocation, route } from "preact-iso"; // Імпортуємо з preact-iso
1581
+ import { forwardRef } from "preact/compat";
1582
+ import { h } from "preact"; // Для JSX
1583
+
1584
+ export const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
1585
+
1586
+ export const LocalizedLink = forwardRef(
1587
+ ({ href, children, onClick, replace = false, ...props }, ref) => {
1588
+ const { locale } = useLocale();
1589
+ const location = useLocation();
1590
+ const isExternalLink = checkIsExternalLink(href);
1591
+
1592
+ const hrefI18n =
1593
+ href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
1594
+
1595
+ const handleClick = (event) => {
1596
+ if (onClick) {
1597
+ onClick(event);
1598
+ }
1599
+ if (
1600
+ !isExternalLink &&
1601
+ href &&
1602
+ event.button === 0 &&
1603
+ !event.metaKey &&
1604
+ !event.ctrlKey &&
1605
+ !event.shiftKey &&
1606
+ !event.altKey &&
1607
+ !props.target
1608
+ ) {
1609
+ event.preventDefault();
1610
+ if (location.url !== hrefI18n) {
1611
+ route(hrefI18n, replace);
1612
+ }
1613
+ }
1614
+ };
1615
+
1616
+ return (
1617
+ <a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
1618
+ {children}
1619
+ </a>
1620
+ );
1621
+ }
1622
+ );
1623
+ ```
1624
+
1625
+ ```jsx fileName="src/components/LocalizedLink.cjsx" codeFormat="commonjs"
1626
+ const { getLocalizedUrl } = require("intlayer");
1627
+ const { useLocale } = require("preact-intlayer");
1628
+ const { useLocation, route } = require("preact-iso"); // Імпорт з preact-iso
1629
+ const { forwardRef } = require("preact/compat");
1630
+ const { h } = require("preact"); // Для JSX
1631
+
1632
+ const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
1633
+
1634
+ const LocalizedLink = forwardRef(
1635
+ ({ href, children, onClick, replace = false, ...props }, ref) => {
1636
+ const { locale } = useLocale();
1637
+ const location = useLocation();
1638
+ const isExternalLink = checkIsExternalLink(href);
1639
+
1640
+ const hrefI18n =
1641
+ href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
1642
+
1643
+ const handleClick = (event) => {
1644
+ if (onClick) {
1645
+ onClick(event);
1646
+ }
1647
+ if (
1648
+ !isExternalLink &&
1649
+ href &&
1650
+ event.button === 0 &&
1651
+ !event.metaKey &&
1652
+ !event.ctrlKey &&
1653
+ !event.shiftKey &&
1654
+ !event.altKey &&
1655
+ !props.target
1656
+ ) {
1657
+ event.preventDefault();
1658
+ if (location.url !== hrefI18n) {
1659
+ route(hrefI18n, replace);
1660
+ }
1661
+ }
1662
+ };
1663
+
1664
+ return (
1665
+ <a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
1666
+ {children}
1667
+ </a>
1668
+ );
1669
+ }
1670
+ );
1671
+
1672
+ module.exports = { LocalizedLink, checkIsExternalLink };
1673
+ ```
1674
+
1675
+ #### Як це працює
1676
+
1677
+ - **Виявлення зовнішніх посилань**:
1678
+ Допоміжна функція `checkIsExternalLink` визначає, чи є URL зовнішнім. Зовнішні посилання залишаються без змін.
1679
+ - **Отримання поточної локалі**:
1680
+ Хук `useLocale` повертає поточну локаль.
1681
+ - **Локалізація URL**:
1682
+ Для внутрішніх посилань `getLocalizedUrl` додає префікс поточної локалі до URL.
1683
+ - **Клієнтська навігація**:
1684
+ Функція `handleClick` перевіряє, чи посилання є внутрішнім і чи слід запобігти стандартній навігації. У такому випадку вона використовує функцію `route` з `preact-iso` (отриману через `useLocation` або імпортовану напряму) для виконання навігації на клієнтській стороні. Це забезпечує поведінку, подібну до SPA, без повного перезавантаження сторінки.
1685
+ - **Повернення посилання**:
1686
+ Компонент повертає елемент `<a>` з локалізованою URL-адресою та власним обробником кліку.
1687
+
1688
+ ### Налаштування TypeScript
1689
+
1690
+ Intlayer використовує module augmentation, щоб скористатися перевагами TypeScript і посилити вашу codebase.
1691
+
1692
+ ![Автодоповнення](https://github.com/aymericzip/intlayer/blob/main/docs/assets/autocompletion.png?raw=true)
1693
+
1694
+ ![Помилка перекладу](https://github.com/aymericzip/intlayer/blob/main/docs/assets/translation_error.png?raw=true)
1695
+
1696
+ Переконайтеся, що ваша конфігурація TypeScript включає автогенеровані типи.
1697
+
1698
+ ```json5 fileName="tsconfig.json"
1699
+ {
1700
+ // ... Ваші існуючі налаштування TypeScript
1701
+ "compilerOptions": {
1702
+ // ...
1703
+ "jsx": "react-jsx",
1704
+ "jsxImportSource": "preact", // Рекомендовано для Preact 10+
1705
+ // ...
1706
+ },
1707
+ "include": [
1708
+ // ... Ваші існуючі налаштування TypeScript
1709
+ ".intlayer/**/*.ts", // Включіть автогенеровані типи
1710
+ ],
1711
+ }
1712
+ ```
1713
+
1714
+ > Переконайтеся, що ваш `tsconfig.json` налаштований для Preact, особливо параметри `jsx` та `jsxImportSource`, або `jsxFactory`/`jsxFragmentFactory` для старіших версій Preact, якщо ви не використовуєте значення за замовчуванням від `preset-vite`.
1715
+
1716
+ ### Конфігурація Git
1717
+
1718
+ Рекомендується ігнорувати файли, згенеровані Intlayer. Це дозволяє уникнути їх коміту в ваш репозиторій Git.
1719
+
1720
+ Для цього ви можете додати такі інструкції до файлу `.gitignore`:
1721
+
1722
+ ```plaintext
1723
+ # Ігнорувати файли, згенеровані Intlayer
1724
+ .intlayer
1725
+ ```
1726
+
1727
+ ### Розширення для VS Code
1728
+
1729
+ Щоб покращити досвід розробки з Intlayer, ви можете встановити офіційне розширення **Intlayer VS Code Extension**.
1730
+
1731
+ [Встановити з Marketplace для VS Code](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
1732
+
1733
+ Розширення надає:
1734
+
1735
+ - **Автодоповнення** для ключів перекладу.
1736
+ - **Виявлення помилок у режимі реального часу** для відсутніх перекладів.
1737
+ - **Вбудований перегляд** перекладеного вмісту.
1738
+ - **Швидкі дії** для легкого створення та оновлення перекладів.
1739
+
1740
+ Для детальнішої інформації щодо використання розширення зверніться до [документації Intlayer VS Code Extension](https://intlayer.org/doc/vs-code-extension).
1741
+
1742
+ ---
1743
+
1744
+ ### Далі
1745
+
1746
+ Щоб просунутися далі, ви можете реалізувати [візуальний редактор](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/intlayer_visual_editor.md) або винести ваш контент, використовуючи [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/uk/intlayer_CMS.md).
1747
+
1748
+ ---