@intlayer/docs 7.3.14 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/blog/ar/intlayer_with_i18next.md +3 -0
  2. package/blog/ar/intlayer_with_next-i18next.md +3 -0
  3. package/blog/ar/intlayer_with_next-intl.md +3 -0
  4. package/blog/ar/intlayer_with_react-i18next.md +3 -0
  5. package/blog/ar/intlayer_with_react-intl.md +3 -0
  6. package/blog/ar/intlayer_with_vue-i18n.md +3 -0
  7. package/blog/de/intlayer_with_i18next.md +3 -0
  8. package/blog/de/intlayer_with_next-i18next.md +3 -0
  9. package/blog/de/intlayer_with_next-intl.md +3 -0
  10. package/blog/de/intlayer_with_react-i18next.md +3 -0
  11. package/blog/de/intlayer_with_react-intl.md +3 -0
  12. package/blog/de/intlayer_with_vue-i18n.md +3 -0
  13. package/blog/en/intlayer_with_i18next.md +7 -0
  14. package/blog/en/intlayer_with_next-i18next.md +3 -0
  15. package/blog/en/intlayer_with_next-intl.md +7 -0
  16. package/blog/en/intlayer_with_react-i18next.md +3 -0
  17. package/blog/en/intlayer_with_react-intl.md +3 -0
  18. package/blog/en/intlayer_with_vue-i18n.md +3 -0
  19. package/blog/en-GB/intlayer_with_i18next.md +3 -0
  20. package/blog/en-GB/intlayer_with_next-i18next.md +3 -0
  21. package/blog/en-GB/intlayer_with_next-intl.md +3 -0
  22. package/blog/en-GB/intlayer_with_react-i18next.md +3 -0
  23. package/blog/en-GB/intlayer_with_react-intl.md +3 -0
  24. package/blog/en-GB/intlayer_with_vue-i18n.md +3 -0
  25. package/blog/es/intlayer_with_i18next.md +3 -0
  26. package/blog/es/intlayer_with_next-i18next.md +3 -0
  27. package/blog/es/intlayer_with_next-intl.md +3 -0
  28. package/blog/es/intlayer_with_react-i18next.md +3 -0
  29. package/blog/es/intlayer_with_react-intl.md +3 -0
  30. package/blog/es/intlayer_with_vue-i18n.md +3 -0
  31. package/blog/fr/intlayer_with_i18next.md +3 -0
  32. package/blog/fr/intlayer_with_next-i18next.md +3 -0
  33. package/blog/fr/intlayer_with_next-intl.md +3 -0
  34. package/blog/fr/intlayer_with_react-i18next.md +3 -0
  35. package/blog/fr/intlayer_with_react-intl.md +3 -0
  36. package/blog/fr/intlayer_with_vue-i18n.md +3 -0
  37. package/blog/hi/intlayer_with_i18next.md +3 -0
  38. package/blog/hi/intlayer_with_next-i18next.md +3 -0
  39. package/blog/hi/intlayer_with_next-intl.md +3 -0
  40. package/blog/hi/intlayer_with_react-i18next.md +3 -0
  41. package/blog/hi/intlayer_with_react-intl.md +3 -0
  42. package/blog/hi/intlayer_with_vue-i18n.md +3 -0
  43. package/blog/id/intlayer_with_i18next.md +3 -0
  44. package/blog/id/intlayer_with_next-i18next.md +3 -0
  45. package/blog/id/intlayer_with_next-intl.md +3 -0
  46. package/blog/id/intlayer_with_react-i18next.md +3 -0
  47. package/blog/id/intlayer_with_react-intl.md +3 -0
  48. package/blog/id/intlayer_with_vue-i18n.md +3 -0
  49. package/blog/it/intlayer_with_i18next.md +3 -0
  50. package/blog/it/intlayer_with_next-i18next.md +3 -0
  51. package/blog/it/intlayer_with_next-intl.md +3 -0
  52. package/blog/it/intlayer_with_react-i18next.md +3 -0
  53. package/blog/it/intlayer_with_react-intl.md +3 -0
  54. package/blog/it/intlayer_with_vue-i18n.md +3 -0
  55. package/blog/ja/intlayer_with_i18next.md +3 -0
  56. package/blog/ja/intlayer_with_next-i18next.md +3 -0
  57. package/blog/ja/intlayer_with_next-intl.md +3 -0
  58. package/blog/ja/intlayer_with_react-i18next.md +3 -0
  59. package/blog/ja/intlayer_with_react-intl.md +3 -0
  60. package/blog/ja/intlayer_with_vue-i18n.md +3 -0
  61. package/blog/ko/intlayer_with_i18next.md +3 -0
  62. package/blog/ko/intlayer_with_next-i18next.md +3 -0
  63. package/blog/ko/intlayer_with_next-intl.md +3 -0
  64. package/blog/ko/intlayer_with_react-i18next.md +3 -0
  65. package/blog/ko/intlayer_with_react-intl.md +3 -0
  66. package/blog/ko/intlayer_with_vue-i18n.md +3 -0
  67. package/blog/pl/intlayer_with_i18next.md +3 -0
  68. package/blog/pl/intlayer_with_next-i18next.md +3 -0
  69. package/blog/pl/intlayer_with_next-intl.md +3 -0
  70. package/blog/pl/intlayer_with_react-i18next.md +3 -0
  71. package/blog/pl/intlayer_with_react-intl.md +3 -0
  72. package/blog/pl/intlayer_with_vue-i18n.md +3 -0
  73. package/blog/pt/intlayer_with_i18next.md +3 -0
  74. package/blog/pt/intlayer_with_next-i18next.md +3 -0
  75. package/blog/pt/intlayer_with_next-intl.md +3 -0
  76. package/blog/pt/intlayer_with_react-i18next.md +3 -0
  77. package/blog/pt/intlayer_with_react-intl.md +3 -0
  78. package/blog/pt/intlayer_with_vue-i18n.md +3 -0
  79. package/blog/ru/intlayer_with_i18next.md +3 -0
  80. package/blog/ru/intlayer_with_next-i18next.md +3 -0
  81. package/blog/ru/intlayer_with_next-intl.md +3 -0
  82. package/blog/ru/intlayer_with_react-i18next.md +3 -0
  83. package/blog/ru/intlayer_with_react-intl.md +3 -0
  84. package/blog/ru/intlayer_with_vue-i18n.md +3 -0
  85. package/blog/tr/intlayer_with_i18next.md +3 -0
  86. package/blog/tr/intlayer_with_next-i18next.md +3 -0
  87. package/blog/tr/intlayer_with_next-intl.md +3 -0
  88. package/blog/tr/intlayer_with_react-i18next.md +3 -0
  89. package/blog/tr/intlayer_with_vue-i18n.md +3 -0
  90. package/blog/vi/intlayer_with_i18next.md +3 -0
  91. package/blog/vi/intlayer_with_next-i18next.md +3 -0
  92. package/blog/vi/intlayer_with_next-intl.md +3 -0
  93. package/blog/vi/intlayer_with_react-i18next.md +3 -0
  94. package/blog/vi/intlayer_with_react-intl.md +3 -0
  95. package/blog/vi/intlayer_with_vue-i18n.md +3 -0
  96. package/blog/zh/intlayer_with_i18next.md +3 -0
  97. package/blog/zh/intlayer_with_next-i18next.md +3 -0
  98. package/blog/zh/intlayer_with_next-intl.md +3 -0
  99. package/blog/zh/intlayer_with_react-i18next.md +3 -0
  100. package/blog/zh/intlayer_with_react-intl.md +3 -0
  101. package/blog/zh/intlayer_with_vue-i18n.md +3 -0
  102. package/docs/ar/intlayer_with_lynx+react.md +1 -1
  103. package/docs/ar/intlayer_with_tanstack.md +132 -2
  104. package/docs/ar/intlayer_with_vite+react.md +99 -331
  105. package/docs/ar/plugins/sync-json.md +3 -0
  106. package/docs/de/intlayer_with_lynx+react.md +1 -1
  107. package/docs/de/intlayer_with_tanstack.md +132 -2
  108. package/docs/de/intlayer_with_vite+react.md +116 -380
  109. package/docs/de/plugins/sync-json.md +3 -0
  110. package/docs/en/intlayer_with_tanstack.md +131 -1
  111. package/docs/en/intlayer_with_vite+react.md +6 -10
  112. package/docs/en/plugins/sync-json.md +3 -0
  113. package/docs/en-GB/intlayer_with_tanstack.md +131 -1
  114. package/docs/en-GB/intlayer_with_vite+react.md +62 -74
  115. package/docs/en-GB/plugins/sync-json.md +3 -0
  116. package/docs/es/intlayer_with_tanstack.md +132 -2
  117. package/docs/es/intlayer_with_vite+react.md +101 -333
  118. package/docs/es/plugins/sync-json.md +3 -0
  119. package/docs/fr/intlayer_with_tanstack.md +132 -2
  120. package/docs/fr/intlayer_with_vite+react.md +101 -357
  121. package/docs/fr/plugins/sync-json.md +3 -0
  122. package/docs/hi/intlayer_with_tanstack.md +132 -2
  123. package/docs/hi/intlayer_with_vite+react.md +120 -333
  124. package/docs/hi/plugins/sync-json.md +3 -0
  125. package/docs/id/intlayer_with_tanstack.md +132 -2
  126. package/docs/id/intlayer_with_vite+react.md +7 -13
  127. package/docs/id/plugins/sync-json.md +3 -0
  128. package/docs/it/intlayer_with_lynx+react.md +1 -1
  129. package/docs/it/intlayer_with_tanstack.md +132 -2
  130. package/docs/it/intlayer_with_vite+react.md +121 -393
  131. package/docs/it/plugins/sync-json.md +3 -0
  132. package/docs/ja/intlayer_with_tanstack.md +132 -2
  133. package/docs/ja/intlayer_with_vite+react.md +106 -378
  134. package/docs/ja/plugins/sync-json.md +3 -0
  135. package/docs/ko/intlayer_with_lynx+react.md +1 -1
  136. package/docs/ko/intlayer_with_tanstack.md +132 -2
  137. package/docs/ko/intlayer_with_vite+react.md +90 -322
  138. package/docs/ko/plugins/sync-json.md +3 -0
  139. package/docs/pl/intlayer_with_tanstack.md +132 -2
  140. package/docs/pl/intlayer_with_vite+react.md +25 -21
  141. package/docs/pl/plugins/sync-json.md +3 -0
  142. package/docs/pt/intlayer_with_tanstack.md +132 -2
  143. package/docs/pt/intlayer_with_vite+react.md +96 -328
  144. package/docs/pt/plugins/sync-json.md +3 -0
  145. package/docs/ru/intlayer_with_lynx+react.md +1 -1
  146. package/docs/ru/intlayer_with_tanstack.md +132 -2
  147. package/docs/ru/intlayer_with_vite+react.md +109 -362
  148. package/docs/ru/plugins/sync-json.md +3 -0
  149. package/docs/tr/intlayer_with_tanstack.md +132 -2
  150. package/docs/tr/intlayer_with_vite+react.md +132 -366
  151. package/docs/tr/plugins/sync-json.md +3 -0
  152. package/docs/vi/intlayer_with_tanstack.md +132 -2
  153. package/docs/vi/intlayer_with_vite+react.md +16 -19
  154. package/docs/vi/plugins/sync-json.md +3 -0
  155. package/docs/zh/intlayer_with_tanstack.md +133 -3
  156. package/docs/zh/intlayer_with_vite+react.md +91 -374
  157. package/docs/zh/plugins/sync-json.md +3 -0
  158. package/frequent_questions/ar/customized_locale_list.md +1 -1
  159. package/frequent_questions/de/customized_locale_list.md +1 -1
  160. package/frequent_questions/en/customized_locale_list.md +1 -1
  161. package/frequent_questions/en-GB/customized_locale_list.md +1 -1
  162. package/frequent_questions/es/customized_locale_list.md +1 -1
  163. package/frequent_questions/fr/customized_locale_list.md +1 -1
  164. package/frequent_questions/hi/customized_locale_list.md +1 -1
  165. package/frequent_questions/id/customized_locale_list.md +1 -1
  166. package/frequent_questions/it/customized_locale_list.md +1 -1
  167. package/frequent_questions/ja/customized_locale_list.md +1 -1
  168. package/frequent_questions/ko/customized_locale_list.md +1 -1
  169. package/frequent_questions/pl/customized_locale_list.md +1 -1
  170. package/frequent_questions/pt/customized_locale_list.md +1 -1
  171. package/frequent_questions/ru/customized_locale_list.md +1 -1
  172. package/frequent_questions/tr/customized_locale_list.md +1 -1
  173. package/frequent_questions/vi/customized_locale_list.md +1 -1
  174. package/frequent_questions/zh/customized_locale_list.md +1 -1
  175. package/package.json +6 -6
@@ -22,6 +22,7 @@ slugs:
22
22
  - doc
23
23
  - plugin
24
24
  - sync-json
25
+ youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
25
26
  history:
26
27
  - version: 6.1.6
27
28
  date: 2025-10-05
@@ -30,6 +31,8 @@ history:
30
31
 
31
32
  # Sync JSON (i18n-Brücken)
32
33
 
34
+ <iframe title="Wie Sie Ihre JSON-Übersetzungen mit Intlayer synchronisiert halten" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&amp;origin=http://intlayer.org&amp;controls=0&amp;rel=1"/>
35
+
33
36
  Verwenden Sie Intlayer als Ergänzung zu Ihrem bestehenden i18n-Stack. Dieses Plugin hält Ihre JSON-Nachrichten mit den Intlayer-Wörterbüchern synchron, sodass Sie:
34
37
 
35
38
  - i18next, next-intl, react-intl, vue-i18n, next-translate, nuxt-i18n, Solid-i18next, svelte-i18n usw. beibehalten können.
@@ -19,6 +19,9 @@ slugs:
19
19
  applicationTemplate: https://github.com/aymericzip/intlayer-tanstack-start-template
20
20
  youtubeVideo: https://www.youtube.com/watch?v=_XTdKVWaeqg
21
21
  history:
22
+ - version: 7.4.0
23
+ date: 2025-12-11
24
+ changes: Introduce validatePrefix and add step 14: Handling 404 pages with localized routes.
22
25
  - version: 7.3.9
23
26
  date: 2025-12-05
24
27
  changes: Add step 13: Retrieve the locale in your server actions (Optional)
@@ -611,7 +614,134 @@ export const getLocaleServer = createServerFn().handler(async () => {
611
614
 
612
615
  ---
613
616
 
614
- ### Step 14: Configure TypeScript (Optional)
617
+ ### Step 14: Manage not found pages (Optional)
618
+
619
+ When a user visits a non-existing page, you can display a custom not found page and the locale prefix may impact the way the not found page is triggered.
620
+
621
+ #### Understanding TanStack Router's 404 Handling with Locale Prefixes
622
+
623
+ In TanStack Router, handling 404 pages with localized routes requires a multi-layered approach:
624
+
625
+ 1. **Dedicated 404 route**: A specific route to display the 404 UI
626
+ 2. **Route-level validation**: Validates locale prefixes and redirects invalid ones to 404
627
+ 3. **Catch-all route**: Captures any unmatched paths within the locale segment
628
+
629
+ ```tsx fileName="src/routes/{-$locale}/404.tsx"
630
+ import { createFileRoute } from "@tanstack/react-router";
631
+
632
+ // This creates a dedicated /[locale]/404 route
633
+ // It's used both as a direct route and imported as a component in other files
634
+ export const Route = createFileRoute("/{-$locale}/404")({
635
+ component: NotFoundComponent,
636
+ });
637
+
638
+ // Exported separately so it can be reused in notFoundComponent and catch-all routes
639
+ export function NotFoundComponent() {
640
+ return (
641
+ <div>
642
+ <h1>404</h1>
643
+ </div>
644
+ );
645
+ }
646
+ ```
647
+
648
+ ```tsx fileName="src/routes/__root.tsx"
649
+ import { createRootRoute } from "@tanstack/react-router";
650
+
651
+ // The root route serves as the top-level layout
652
+ // It doesn't handle 404s directly - that's delegated to child routes
653
+ // This keeps the root simple and lets locale-aware routes manage their own 404 logic
654
+ export const Route = createRootRoute({
655
+ component: Outlet,
656
+ });
657
+ ```
658
+
659
+ ```tsx fileName="src/routes/{-$locale}/route.tsx"
660
+ import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
661
+ import { validatePrefix } from "intlayer";
662
+ import { IntlayerProvider, useLocale } from "react-intlayer";
663
+
664
+ import { LocaleSwitcher } from "@/components/locale-switcher";
665
+ import { NotFoundComponent } from "./404";
666
+
667
+ export const Route = createFileRoute("/{-$locale}")({
668
+ // beforeLoad runs before the route renders (on both server and client)
669
+ // It's the ideal place to validate the locale prefix
670
+ beforeLoad: ({ params }) => {
671
+ // Get locale from route params (not from server headers, as beforeLoad runs on both client and server)
672
+ const localeParam = params.locale;
673
+
674
+ // validatePrefix checks if the locale is valid according to your intlayer config
675
+ // Returns: { isValid: boolean, localePrefix: string }
676
+ // - isValid: true if the prefix matches a configured locale (or is empty when prefix is optional)
677
+ // - localePrefix: the validated prefix or the default locale prefix for redirects
678
+ const { isValid, localePrefix } = validatePrefix(localeParam);
679
+
680
+ if (isValid) {
681
+ // Locale is valid, allow the route to render normally
682
+ return;
683
+ }
684
+
685
+ // Invalid locale prefix (e.g., /xyz/about where "xyz" isn't a valid locale)
686
+ // Redirect to the 404 page with a valid locale prefix
687
+ // This ensures the 404 page is still properly localized
688
+ throw redirect({
689
+ to: "/{-$locale}/404",
690
+ params: { locale: localePrefix },
691
+ });
692
+ },
693
+ component: RouteComponent,
694
+ // notFoundComponent is called when a child route doesn't exist
695
+ // e.g., /en/non-existent-page triggers this within the /en layout
696
+ notFoundComponent: NotFoundLayout,
697
+ });
698
+
699
+ function RouteComponent() {
700
+ const { defaultLocale } = useLocale();
701
+ const { locale } = Route.useParams();
702
+
703
+ return (
704
+ // Wrap the entire locale segment with IntlayerProvider
705
+ // Falls back to defaultLocale when locale param is undefined (optional prefix mode)
706
+ <IntlayerProvider locale={locale ?? defaultLocale}>
707
+ <Outlet />
708
+ </IntlayerProvider>
709
+ );
710
+ }
711
+
712
+ // NotFoundLayout wraps the 404 component with IntlayerProvider
713
+ // This ensures translations still work on the 404 page
714
+ function NotFoundLayout() {
715
+ const { defaultLocale } = useLocale();
716
+ const { locale } = Route.useParams();
717
+
718
+ return (
719
+ <IntlayerProvider locale={locale ?? defaultLocale}>
720
+ <NotFoundComponent />
721
+ {/* Include LocaleSwitcher so users can change language even on 404 */}
722
+ <LocaleSwitcher />
723
+ </IntlayerProvider>
724
+ );
725
+ }
726
+ ```
727
+
728
+ ```tsx fileName="src/routes/{-$locale}/$.tsx"
729
+ import { createFileRoute } from "@tanstack/react-router";
730
+
731
+ import { NotFoundComponent } from "./404";
732
+
733
+ // The $ (splat/catch-all) route matches any path that doesn't match other routes
734
+ // e.g., /en/some/deeply/nested/invalid/path
735
+ // This ensures ALL unmatched paths within a locale show the 404 page
736
+ // Without this, unmatched deep paths might show a blank page or error
737
+ export const Route = createFileRoute("/{-$locale}/$")({
738
+ component: NotFoundComponent,
739
+ });
740
+ ```
741
+
742
+ ---
743
+
744
+ ### Step 15: Configure TypeScript (Optional)
615
745
 
616
746
  Intlayer uses module augmentation to get benefits of TypeScript and make your codebase stronger.
617
747
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2024-03-07
3
- updatedAt: 2024-03-07
3
+ updatedAt: 2025-12-10
4
4
  title: How to translate your Vite and React app – i18n guide 2025
5
5
  description: Learn how to add internationalization (i18n) to your Vite and React application using Intlayer. Follow this guide to make your app multilingual.
6
6
  keywords:
@@ -85,7 +85,6 @@ yarn add vite-intlayer --save-dev
85
85
  ```
86
86
 
87
87
  - **intlayer**
88
-
89
88
  The core package that provides internationalization tools for configuration management, translation, [content declaration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md), transpilation, and [CLI commands](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md).
90
89
 
91
90
  - **react-intlayer**
@@ -1218,11 +1217,10 @@ import {
1218
1217
  } from "react";
1219
1218
  import { useLocale } from "react-intlayer";
1220
1219
 
1221
- export interface LinkProps
1222
- extends DetailedHTMLProps<
1223
- AnchorHTMLAttributes<HTMLAnchorElement>,
1224
- HTMLAnchorElement
1225
- > {}
1220
+ export interface LinkProps extends DetailedHTMLProps<
1221
+ AnchorHTMLAttributes<HTMLAnchorElement>,
1222
+ HTMLAnchorElement
1223
+ > {}
1226
1224
 
1227
1225
  /**
1228
1226
  * Utility function to check whether a given URL is external.
@@ -1371,7 +1369,7 @@ It is recommended to ignore the files generated by Intlayer. This allows you to
1371
1369
 
1372
1370
  To do this, you can add the following instructions to your `.gitignore` file:
1373
1371
 
1374
- ```plaintext
1372
+ ```plaintext fileName=".gitignore"
1375
1373
  # Ignore the files generated by Intlayer
1376
1374
  .intlayer
1377
1375
  ```
@@ -1396,5 +1394,3 @@ For more details on how to use the extension, refer to the [Intlayer VS Code Ext
1396
1394
  ### Go Further
1397
1395
 
1398
1396
  To go further, you can implement the [visual editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md) or externalize your content using the [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md).
1399
-
1400
- ---
@@ -22,6 +22,7 @@ slugs:
22
22
  - doc
23
23
  - plugin
24
24
  - sync-json
25
+ youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
25
26
  history:
26
27
  - version: 6.1.6
27
28
  date: 2025-10-05
@@ -30,6 +31,8 @@ history:
30
31
 
31
32
  # Sync JSON (i18n bridges)
32
33
 
34
+ <iframe title="How to keep your JSON translations in sync with Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&amp;origin=http://intlayer.org&amp;controls=0&amp;rel=1"/>
35
+
33
36
  Use Intlayer as an add‑on to your existing i18n stack. This plugin keeps your JSON messages in sync with Intlayer dictionaries so you can:
34
37
 
35
38
  - Keep i18next, next‑intl, react‑intl, vue‑i18n, next‑translate, nuxt‑i18n, Solid‑i18next, svelte‑i18n, etc.
@@ -19,6 +19,9 @@ slugs:
19
19
  applicationTemplate: https://github.com/aymericzip/intlayer-tanstack-start-template
20
20
  youtubeVideo: https://www.youtube.com/watch?v=_XTdKVWaeqg
21
21
  history:
22
+ - version: 7.4.0
23
+ date: 2025-12-11
24
+ changes: Introduce validatePrefix and add step 14: Handling 404 pages with localized routes.
22
25
  - version: 7.3.9
23
26
  date: 2025-12-05
24
27
  changes: Add step 13: Retrieve the locale in your server actions (Optional)
@@ -602,7 +605,134 @@ export const getLocaleServer = createServerFn().handler(async () => {
602
605
 
603
606
  ---
604
607
 
605
- ### Step 14: Configure TypeScript (Optional)
608
+ ### Step 14: Manage not found pages (Optional)
609
+
610
+ When a user visits a non-existing page, you can display a custom not found page and the locale prefix may impact the way the not found page is triggered.
611
+
612
+ #### Understanding TanStack Router's 404 Handling with Locale Prefixes
613
+
614
+ In TanStack Router, handling 404 pages with localized routes requires a multi-layered approach:
615
+
616
+ 1. **Dedicated 404 route**: A specific route to display the 404 UI
617
+ 2. **Route-level validation**: Validates locale prefixes and redirects invalid ones to 404
618
+ 3. **Catch-all route**: Captures any unmatched paths within the locale segment
619
+
620
+ ```tsx fileName="src/routes/{-$locale}/404.tsx"
621
+ import { createFileRoute } from "@tanstack/react-router";
622
+
623
+ // This creates a dedicated /[locale]/404 route
624
+ // It's used both as a direct route and imported as a component in other files
625
+ export const Route = createFileRoute("/{-$locale}/404")({
626
+ component: NotFoundComponent,
627
+ });
628
+
629
+ // Exported separately so it can be reused in notFoundComponent and catch-all routes
630
+ export function NotFoundComponent() {
631
+ return (
632
+ <div>
633
+ <h1>404</h1>
634
+ </div>
635
+ );
636
+ }
637
+ ```
638
+
639
+ ```tsx fileName="src/routes/__root.tsx"
640
+ import { createRootRoute } from "@tanstack/react-router";
641
+
642
+ // The root route serves as the top-level layout
643
+ // It doesn't handle 404s directly - that's delegated to child routes
644
+ // This keeps the root simple and lets locale-aware routes manage their own 404 logic
645
+ export const Route = createRootRoute({
646
+ component: Outlet,
647
+ });
648
+ ```
649
+
650
+ ```tsx fileName="src/routes/{-$locale}/route.tsx"
651
+ import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
652
+ import { validatePrefix } from "intlayer";
653
+ import { IntlayerProvider, useLocale } from "react-intlayer";
654
+
655
+ import { LocaleSwitcher } from "@/components/locale-switcher";
656
+ import { NotFoundComponent } from "./404";
657
+
658
+ export const Route = createFileRoute("/{-$locale}")({
659
+ // beforeLoad runs before the route renders (on both server and client)
660
+ // It's the ideal place to validate the locale prefix
661
+ beforeLoad: ({ params }) => {
662
+ // Get locale from route params (not from server headers, as beforeLoad runs on both client and server)
663
+ const localeParam = params.locale;
664
+
665
+ // validatePrefix checks if the locale is valid according to your intlayer config
666
+ // Returns: { isValid: boolean, localePrefix: string }
667
+ // - isValid: true if the prefix matches a configured locale (or is empty when prefix is optional)
668
+ // - localePrefix: the validated prefix or the default locale prefix for redirects
669
+ const { isValid, localePrefix } = validatePrefix(localeParam);
670
+
671
+ if (isValid) {
672
+ // Locale is valid, allow the route to render normally
673
+ return;
674
+ }
675
+
676
+ // Invalid locale prefix (e.g., /xyz/about where "xyz" isn't a valid locale)
677
+ // Redirect to the 404 page with a valid locale prefix
678
+ // This ensures the 404 page is still properly localized
679
+ throw redirect({
680
+ to: "/{-$locale}/404",
681
+ params: { locale: localePrefix },
682
+ });
683
+ },
684
+ component: RouteComponent,
685
+ // notFoundComponent is called when a child route doesn't exist
686
+ // e.g., /en/non-existent-page triggers this within the /en layout
687
+ notFoundComponent: NotFoundLayout,
688
+ });
689
+
690
+ function RouteComponent() {
691
+ const { defaultLocale } = useLocale();
692
+ const { locale } = Route.useParams();
693
+
694
+ return (
695
+ // Wrap the entire locale segment with IntlayerProvider
696
+ // Falls back to defaultLocale when locale param is undefined (optional prefix mode)
697
+ <IntlayerProvider locale={locale ?? defaultLocale}>
698
+ <Outlet />
699
+ </IntlayerProvider>
700
+ );
701
+ }
702
+
703
+ // NotFoundLayout wraps the 404 component with IntlayerProvider
704
+ // This ensures translations still work on the 404 page
705
+ function NotFoundLayout() {
706
+ const { defaultLocale } = useLocale();
707
+ const { locale } = Route.useParams();
708
+
709
+ return (
710
+ <IntlayerProvider locale={locale ?? defaultLocale}>
711
+ <NotFoundComponent />
712
+ {/* Include LocaleSwitcher so users can change language even on 404 */}
713
+ <LocaleSwitcher />
714
+ </IntlayerProvider>
715
+ );
716
+ }
717
+ ```
718
+
719
+ ```tsx fileName="src/routes/{-$locale}/$.tsx"
720
+ import { createFileRoute } from "@tanstack/react-router";
721
+
722
+ import { NotFoundComponent } from "./404";
723
+
724
+ // The $ (splat/catch-all) route matches any path that doesn't match other routes
725
+ // e.g., /en/some/deeply/nested/invalid/path
726
+ // This ensures ALL unmatched paths within a locale show the 404 page
727
+ // Without this, unmatched deep paths might show a blank page or error
728
+ export const Route = createFileRoute("/{-$locale}/$")({
729
+ component: NotFoundComponent,
730
+ });
731
+ ```
732
+
733
+ ---
734
+
735
+ ### Step 15: Configure TypeScript (Optional)
606
736
 
607
737
  Intlayer uses module augmentation to benefit from TypeScript and strengthen your codebase.
608
738
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2024-03-07
3
- updatedAt: 2024-03-07
3
+ updatedAt: 2025-12-10
4
4
  title: How to translate your Vite and React app – i18n guide 2025
5
5
  description: Learn how to add internationalisation (i18n) to your Vite and React application using Intlayer. Follow this guide to make your app multilingual.
6
6
  keywords:
@@ -16,23 +16,19 @@ slugs:
16
16
  - environment
17
17
  - vite-and-react
18
18
  applicationTemplate: https://github.com/aymericzip/intlayer-vite-react-template
19
- youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4---
19
+ youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
20
20
  history:
21
21
  - version: 5.5.10
22
22
  date: 2025-06-29
23
23
  changes: Init history
24
24
  ---
25
25
 
26
- # Getting Started Internationalising (i18n) with Intlayer and Vite and React
26
+ # Translate your Vite and React website using Intlayer | Internationalization (i18n)
27
27
 
28
28
  ## Table of Contents
29
29
 
30
30
  <TOC/>
31
31
 
32
- <iframe title="The best i18n solution for Vite and React? Discover Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/dS9L7uJeak4?si=VaKmrYMmXjo3xpk2"/>
33
-
34
- See [Application Template](https://github.com/aymericzip/intlayer-vite-react-template) on GitHub.
35
-
36
32
  ## What is Intlayer?
37
33
 
38
34
  **Intlayer** is an innovative, open-source internationalisation (i18n) library designed to simplify multilingual support in modern web applications.
@@ -48,6 +44,27 @@ With Intlayer, you can:
48
44
 
49
45
  ## Step-by-Step Guide to Set Up Intlayer in a Vite and React Application
50
46
 
47
+ <Tab defaultTab="video">
48
+ <TabItem label="Video" value="video">
49
+
50
+ <iframe title="The best i18n solution for Vite and React? Discover Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/dS9L7uJeak4?si=VaKmrYMmXjo3xpk2"/>
51
+
52
+ </TabItem>
53
+ <TabItem label="Code" value="code">
54
+
55
+ <iframe
56
+ src="https://stackblitz.com/github/aymericzip/intlayer-vite-react-template?embed=1&ctl=1&file=intlayer.config.ts"
57
+ className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
58
+ title="Demo CodeSandbox - How to Internationalize your application using Intlayer"
59
+ sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
60
+ loading="lazy"
61
+ />
62
+
63
+ </TabItem>
64
+ </Tab>
65
+
66
+ See [Application Template](https://github.com/aymericzip/intlayer-vite-react-template) on GitHub.
67
+
51
68
  ### Step 1: Install Dependencies
52
69
 
53
70
  Install the necessary packages using npm:
@@ -68,8 +85,7 @@ yarn add vite-intlayer --save-dev
68
85
  ```
69
86
 
70
87
  - **intlayer**
71
-
72
- The core package that provides internationalisation tools for configuration management, translation, [content declaration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/get_started.md), transpilation, and [CLI commands](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_cli.md).
88
+ The core package that provides internationalization tools for configuration management, translation, [content declaration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/content_file.md), transpilation, and [CLI commands](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/cli/index.md).
73
89
 
74
90
  - **react-intlayer**
75
91
  The package that integrates Intlayer with React applications. It provides context providers and hooks for React internationalisation.
@@ -137,7 +153,7 @@ const config = {
137
153
  module.exports = config;
138
154
  ```
139
155
 
140
- > Through this configuration file, you can set up localised URLs, middleware redirection, cookie names, the location and extension of your content declarations, disable Intlayer logs in the console, and more. For a complete list of available parameters, refer to the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/configuration.md).
156
+ > Through this configuration file, you can set up localised URLs, middleware redirection, cookie names, the location and extension of your content declarations, disable Intlayer logs in the console, and more. For a complete list of available parameters, refer to the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
141
157
 
142
158
  ### Step 3: Integrate Intlayer in Your Vite Configuration
143
159
 
@@ -254,13 +270,13 @@ const appContent = {
254
270
  key: "app",
255
271
  content: {
256
272
  viteLogo: t({
257
- 'en-GB': "Vite logo",
273
+ "en-GB": "Vite logo",
258
274
  en: "Vite logo",
259
275
  fr: "Logo Vite",
260
276
  es: "Logo Vite",
261
277
  }),
262
278
  reactLogo: t({
263
- 'en-GB': "React logo",
279
+ "en-GB": "React logo",
264
280
  en: "React logo",
265
281
  fr: "Logo React",
266
282
  es: "Logo React",
@@ -269,24 +285,24 @@ const appContent = {
269
285
  title: "Vite + React",
270
286
 
271
287
  count: t({
272
- 'en-GB': "count is ",
288
+ "en-GB": "count is ",
273
289
  en: "count is ",
274
290
  fr: "le compte est ",
275
291
  es: "el recuento es ",
276
292
  }),
277
293
 
278
- edit: t<ReactNode>({
279
- // Remember to import React if you use a React node in your content
280
- 'en-GB': (
281
- <>
282
- Edit <code>src/App.tsx</code> and save to test HMR
283
- </>
284
- ),
285
- en: (
286
- <>
287
- Edit <code>src/App.tsx</code> and save to test HMR
288
- </>
289
- ),
294
+ edit:
295
+ t <
296
+ ReactNode >
297
+ {
298
+ // Remember to import React if you use a React node in your content
299
+ "en-GB": (
300
+ <>
301
+ Edit <code>src/App.tsx</code> and save to test HMR
302
+ </>
303
+ ),
304
+ en: (
305
+ <>
290
306
  Edit <code>src/App.tsx</code> and save to test HMR
291
307
  </>
292
308
  ),
@@ -303,7 +319,7 @@ const appContent = {
303
319
  },
304
320
 
305
321
  readTheDocs: t({
306
- 'en-GB': "Click on the Vite and React logos to learn more",
322
+ "en-GB": "Click on the Vite and React logos to learn more",
307
323
  en: "Click on the Vite and React logos to learn more",
308
324
  fr: "Cliquez sur les logos Vite et React pour en savoir plus",
309
325
  es: "Haga clic en los logotipos de Vite y React para obtener más información",
@@ -447,7 +463,7 @@ module.exports = appContent;
447
463
 
448
464
  > Your content declarations can be defined anywhere in your application as soon as they are included in the `contentDir` directory (by default, `./src`). And match the content declaration file extension (by default, `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`).
449
465
 
450
- > For more details, refer to the [content declaration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/get_started.md).
466
+ > For more details, refer to the [content declaration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/content_file.md).
451
467
 
452
468
  > If your content file includes TSX code, you should consider importing `import React from "react";` in your content file.
453
469
 
@@ -804,7 +820,6 @@ const { locales, defaultLocale } = internationalization;
804
820
 
805
821
  /**
806
822
  * A component that handles localisation and wraps children with the appropriate locale context.
807
- /**
808
823
  * It manages URL-based locale detection and validation.
809
824
  */
810
825
  const AppLocalized = ({ children, locale }) => {
@@ -1005,8 +1020,12 @@ const LocaleRouter = ({ children }) => (
1005
1020
  </Routes>
1006
1021
  </BrowserRouter>
1007
1022
  );
1023
+
1024
+ exports.LocaleRouter = LocaleRouter;
1008
1025
  ```
1009
1026
 
1027
+ > Note: If you use `routing.mode: 'no-prefix' | 'search-params'`, you probably don't need to use the `localeMap` function.
1028
+
1010
1029
  Then, you can use the `LocaleRouter` component in your application:
1011
1030
 
1012
1031
  ```tsx fileName="src/App.tsx" codeFormat="typescript"
@@ -1048,6 +1067,8 @@ const App = () => (
1048
1067
 
1049
1068
  In parallel, you can also use the `intlayerProxy` to add server-side routing to your application. This plugin will automatically detect the current locale based on the URL and set the appropriate locale cookie. If no locale is specified, the plugin will determine the most appropriate locale based on the user's browser language preferences. If no locale is detected, it will redirect to the default locale.
1050
1069
 
1070
+ > Note that to use the `intlayerProxy` in production, you need to switch the `vite-intlayer` package from `devDependencies` to `dependencies`.
1071
+
1051
1072
  ```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
1052
1073
  import { defineConfig } from "vite";
1053
1074
  import react from "@vitejs/plugin-react-swc";
@@ -1280,14 +1301,14 @@ const LocaleSwitcher = () => {
1280
1301
 
1281
1302
  > Documentation references:
1282
1303
  >
1283
- > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/{{locale}}/packages/react-intlayer/useLocale.md)
1284
- > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/{{locale}}/packages/intlayer/getLocaleName.md)
1285
- > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/{{locale}}/packages/intlayer/getLocalizedUrl.md)
1304
+ > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/react-intlayer/useLocale.md)
1305
+ > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/intlayer/getLocaleName.md)
1306
+ > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/intlayer/getLocalizedUrl.md)
1286
1307
  > - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/packages/intlayer/getHTMLTextDir.md)
1287
1308
  > - [`hrefLang` attribute](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
1288
- > - [`lang` attribute`](https://developer.mozilla.org/en-GB/docs/Web/HTML/Global_attributes/lang)
1289
- > - [`dir` attribute`](https://developer.mozilla.org/en-GB/docs/Web/HTML/Global_attributes/dir)
1290
- > - [`aria-current` attribute`](https://developer.mozilla.org/en-GB/docs/Web/Accessibility/ARIA/Attributes/aria-current)
1309
+ > - [`lang` attribute](https://developer.mozilla.org/en-GB/docs/Web/HTML/Global_attributes/lang)
1310
+ > - [`dir` attribute](https://developer.mozilla.org/en-GB/docs/Web/HTML/Global_attributes/dir)
1311
+ > - [`aria-current` attribute](https://developer.mozilla.org/en-GB/docs/Web/Accessibility/ARIA/Attributes/aria-current)
1291
1312
 
1292
1313
  Below is the updated **Step 9** with added explanations and refined code examples:
1293
1314
 
@@ -1461,36 +1482,6 @@ By applying these changes, your application will:
1461
1482
 
1462
1483
  ### (Optional) Step 10: Creating a Localised Link Component
1463
1484
 
1464
- ```tsx fileName="src/App.tsx" codeFormat="typescript"
1465
- import type { FC } from "react";
1466
- import { IntlayerProvider, useIntlayer } from "react-intlayer";
1467
- import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";
1468
- import "./App.css";
1469
-
1470
- const AppContent: FC = () => {
1471
- // Apply the hook to update the <html> tag's lang and dir attributes based on the locale.
1472
- useI18nHTMLAttributes();
1473
-
1474
- // ... Rest of your component
1475
- };
1476
-
1477
- const App = () => (
1478
- <IntlayerProvider>
1479
- <AppContent />
1480
- </IntlayerProvider>
1481
- );
1482
-
1483
- module.exports = App;
1484
- ```
1485
-
1486
- By applying these changes, your application will:
1487
-
1488
- - Ensure the **language** (`lang`) attribute correctly reflects the current locale, which is important for SEO and browser behaviour.
1489
- - Adjust the **text direction** (`dir`) according to the locale, enhancing readability and usability for languages with different reading orders.
1490
- - Provide a more **accessible** experience, as assistive technologies depend on these attributes to function optimally.
1491
-
1492
- ### (Optional) Step 10: Creating a Localised Link Component
1493
-
1494
1485
  To ensure that your application’s navigation respects the current locale, you can create a custom `Link` component. This component automatically prefixes internal URLs with the current language. For example, when a French-speaking user clicks on a link to the "About" page, they are redirected to `/fr/about` instead of `/about`.
1495
1486
 
1496
1487
  This behaviour is useful for several reasons:
@@ -1510,15 +1501,14 @@ import {
1510
1501
  } from "react";
1511
1502
  import { useLocale } from "react-intlayer";
1512
1503
 
1513
- export interface LinkProps
1514
- extends DetailedHTMLProps<
1515
- AnchorHTMLAttributes<HTMLAnchorElement>,
1516
- HTMLAnchorElement
1517
- > {}
1504
+ export interface LinkProps extends DetailedHTMLProps<
1505
+ AnchorHTMLAttributes<HTMLAnchorElement>,
1506
+ HTMLAnchorElement
1507
+ > {}
1518
1508
 
1519
1509
  /**
1520
1510
  * Utility function to check whether a given URL is external.
1521
- * If the URL starts with http:// or https://, it is considered external.
1511
+ * If the URL starts with http:// or https://, it's considered external.
1522
1512
  */
1523
1513
  export const checkIsExternalLink = (href?: string): boolean =>
1524
1514
  /^https?:\/\//.test(href ?? "");
@@ -1526,14 +1516,14 @@ export const checkIsExternalLink = (href?: string): boolean =>
1526
1516
  /**
1527
1517
  * A custom Link component that adapts the href attribute based on the current locale.
1528
1518
  * For internal links, it uses `getLocalizedUrl` to prefix the URL with the locale (e.g., /fr/about).
1529
- * This ensures that navigation remains within the same locale context.
1519
+ * This ensures that navigation stays within the same locale context.
1530
1520
  */
1531
1521
  export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
1532
1522
  ({ href, children, ...props }, ref) => {
1533
1523
  const { locale } = useLocale();
1534
1524
  const isExternalLink = checkIsExternalLink(href);
1535
1525
 
1536
- // If the link is internal and a valid href is provided, get the localised URL.
1526
+ // If the link is internal and a valid href is provided, get the localized URL.
1537
1527
  const hrefI18n =
1538
1528
  href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
1539
1529
 
@@ -1688,5 +1678,3 @@ For more details on how to use the extension, refer to the [Intlayer VS Code Ext
1688
1678
  ### Go Further
1689
1679
 
1690
1680
  To go further, you can implement the [visual editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_visual_editor.md) or externalise your content using the [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_CMS.md).
1691
-
1692
- ---
@@ -22,6 +22,7 @@ slugs:
22
22
  - doc
23
23
  - plugin
24
24
  - sync-json
25
+ youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
25
26
  history:
26
27
  - version: 6.1.6
27
28
  date: 2025-10-05
@@ -30,6 +31,8 @@ history:
30
31
 
31
32
  ## Sync JSON (i18n bridges)
32
33
 
34
+ <iframe title="How to keep your JSON translations in sync with Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&amp;origin=http://intlayer.org&amp;controls=0&amp;rel=1"/>
35
+
33
36
  Use Intlayer as an add‑on to your existing i18n stack. This plugin keeps your JSON messages in sync with Intlayer dictionaries so you can:
34
37
 
35
38
  - Keep i18next, next‑intl, react‑intl, vue‑i18n, next‑translate, nuxt‑i18n, Solid‑i18next, svelte‑i18n, etc.