@intlayer/docs 7.5.12 → 7.5.14

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 (229) hide show
  1. package/blog/ar/per-component_vs_centralized_i18n.md +248 -0
  2. package/blog/de/per-component_vs_centralized_i18n.md +248 -0
  3. package/blog/en/_per-component_vs_centralized_i18n.md +252 -0
  4. package/blog/en/per-component_vs_centralized_i18n.md +248 -0
  5. package/blog/en-GB/per-component_vs_centralized_i18n.md +247 -0
  6. package/blog/es/per-component_vs_centralized_i18n.md +245 -0
  7. package/blog/fr/per-component_vs_centralized_i18n.md +245 -0
  8. package/blog/hi/per-component_vs_centralized_i18n.md +249 -0
  9. package/blog/id/per-component_vs_centralized_i18n.md +248 -0
  10. package/blog/it/per-component_vs_centralized_i18n.md +247 -0
  11. package/blog/ja/per-component_vs_centralized_i18n.md +247 -0
  12. package/blog/ko/per-component_vs_centralized_i18n.md +246 -0
  13. package/blog/pl/per-component_vs_centralized_i18n.md +247 -0
  14. package/blog/pt/per-component_vs_centralized_i18n.md +246 -0
  15. package/blog/ru/per-component_vs_centralized_i18n.md +251 -0
  16. package/blog/tr/per-component_vs_centralized_i18n.md +244 -0
  17. package/blog/uk/compiler_vs_declarative_i18n.md +224 -0
  18. package/blog/uk/i18n_using_next-i18next.md +1086 -0
  19. package/blog/uk/i18n_using_next-intl.md +760 -0
  20. package/blog/uk/index.md +69 -0
  21. package/blog/uk/internationalization_and_SEO.md +273 -0
  22. package/blog/uk/intlayer_with_i18next.md +211 -0
  23. package/blog/uk/intlayer_with_next-i18next.md +202 -0
  24. package/blog/uk/intlayer_with_next-intl.md +203 -0
  25. package/blog/uk/intlayer_with_react-i18next.md +200 -0
  26. package/blog/uk/intlayer_with_react-intl.md +202 -0
  27. package/blog/uk/intlayer_with_vue-i18n.md +206 -0
  28. package/blog/uk/l10n_platform_alternative/Lokalise.md +80 -0
  29. package/blog/uk/l10n_platform_alternative/crowdin.md +80 -0
  30. package/blog/uk/l10n_platform_alternative/phrase.md +78 -0
  31. package/blog/uk/list_i18n_technologies/CMS/drupal.md +143 -0
  32. package/blog/uk/list_i18n_technologies/CMS/wix.md +167 -0
  33. package/blog/uk/list_i18n_technologies/CMS/wordpress.md +189 -0
  34. package/blog/uk/list_i18n_technologies/frameworks/angular.md +125 -0
  35. package/blog/uk/list_i18n_technologies/frameworks/flutter.md +128 -0
  36. package/blog/uk/list_i18n_technologies/frameworks/react-native.md +217 -0
  37. package/blog/uk/list_i18n_technologies/frameworks/react.md +155 -0
  38. package/blog/uk/list_i18n_technologies/frameworks/svelte.md +145 -0
  39. package/blog/uk/list_i18n_technologies/frameworks/vue.md +144 -0
  40. package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +1499 -0
  41. package/blog/uk/nextjs-multilingual-seo-comparison.md +360 -0
  42. package/blog/uk/per-component_vs_centralized_i18n.md +248 -0
  43. package/blog/uk/rag_powered_documentation_assistant.md +288 -0
  44. package/blog/uk/react-i18next_vs_react-intl_vs_intlayer.md +164 -0
  45. package/blog/uk/vue-i18n_vs_intlayer.md +279 -0
  46. package/blog/uk/what_is_internationalization.md +167 -0
  47. package/blog/vi/per-component_vs_centralized_i18n.md +246 -0
  48. package/blog/zh/per-component_vs_centralized_i18n.md +248 -0
  49. package/dist/cjs/common.cjs.map +1 -1
  50. package/dist/cjs/generated/blog.entry.cjs +20 -0
  51. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  52. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  53. package/dist/cjs/generated/frequentQuestions.entry.cjs +20 -0
  54. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  55. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  56. package/dist/esm/common.mjs.map +1 -1
  57. package/dist/esm/generated/blog.entry.mjs +20 -0
  58. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  59. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  60. package/dist/esm/generated/frequentQuestions.entry.mjs +20 -0
  61. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  62. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  63. package/dist/types/generated/blog.entry.d.ts +1 -0
  64. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  65. package/dist/types/generated/frequentQuestions.entry.d.ts +1 -0
  66. package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
  67. package/docs/ar/configuration.md +6 -1
  68. package/docs/ar/dictionary/content_file.md +6 -1
  69. package/docs/de/configuration.md +6 -1
  70. package/docs/de/dictionary/content_file.md +6 -1
  71. package/docs/en/configuration.md +6 -1
  72. package/docs/en/dictionary/content_file.md +6 -1
  73. package/docs/en-GB/configuration.md +6 -1
  74. package/docs/en-GB/dictionary/content_file.md +3 -1
  75. package/docs/es/configuration.md +6 -1
  76. package/docs/es/dictionary/content_file.md +6 -1
  77. package/docs/fr/configuration.md +6 -1
  78. package/docs/fr/dictionary/content_file.md +3 -1
  79. package/docs/hi/configuration.md +6 -1
  80. package/docs/hi/dictionary/content_file.md +3 -1
  81. package/docs/id/configuration.md +6 -1
  82. package/docs/id/dictionary/content_file.md +3 -1
  83. package/docs/it/configuration.md +6 -1
  84. package/docs/it/dictionary/content_file.md +3 -1
  85. package/docs/ja/configuration.md +6 -1
  86. package/docs/ja/dictionary/content_file.md +3 -1
  87. package/docs/ko/configuration.md +6 -1
  88. package/docs/ko/dictionary/content_file.md +3 -1
  89. package/docs/pl/configuration.md +3 -1
  90. package/docs/pl/dictionary/content_file.md +3 -1
  91. package/docs/pt/configuration.md +6 -1
  92. package/docs/pt/dictionary/content_file.md +3 -1
  93. package/docs/ru/configuration.md +6 -1
  94. package/docs/ru/dictionary/content_file.md +6 -1
  95. package/docs/tr/configuration.md +6 -1
  96. package/docs/tr/dictionary/content_file.md +3 -1
  97. package/docs/uk/CI_CD.md +198 -0
  98. package/docs/uk/autoFill.md +307 -0
  99. package/docs/uk/bundle_optimization.md +185 -0
  100. package/docs/uk/cli/build.md +64 -0
  101. package/docs/uk/cli/ci.md +137 -0
  102. package/docs/uk/cli/configuration.md +63 -0
  103. package/docs/uk/cli/debug.md +46 -0
  104. package/docs/uk/cli/doc-review.md +43 -0
  105. package/docs/uk/cli/doc-translate.md +132 -0
  106. package/docs/uk/cli/editor.md +28 -0
  107. package/docs/uk/cli/fill.md +130 -0
  108. package/docs/uk/cli/index.md +190 -0
  109. package/docs/uk/cli/init.md +84 -0
  110. package/docs/uk/cli/list.md +90 -0
  111. package/docs/uk/cli/list_projects.md +128 -0
  112. package/docs/uk/cli/live.md +41 -0
  113. package/docs/uk/cli/login.md +157 -0
  114. package/docs/uk/cli/pull.md +78 -0
  115. package/docs/uk/cli/push.md +98 -0
  116. package/docs/uk/cli/sdk.md +71 -0
  117. package/docs/uk/cli/test.md +76 -0
  118. package/docs/uk/cli/transform.md +65 -0
  119. package/docs/uk/cli/version.md +24 -0
  120. package/docs/uk/cli/watch.md +37 -0
  121. package/docs/uk/configuration.md +742 -0
  122. package/docs/uk/dictionary/condition.md +237 -0
  123. package/docs/uk/dictionary/content_file.md +1134 -0
  124. package/docs/uk/dictionary/enumeration.md +245 -0
  125. package/docs/uk/dictionary/file.md +232 -0
  126. package/docs/uk/dictionary/function_fetching.md +212 -0
  127. package/docs/uk/dictionary/gender.md +273 -0
  128. package/docs/uk/dictionary/insertion.md +187 -0
  129. package/docs/uk/dictionary/markdown.md +383 -0
  130. package/docs/uk/dictionary/nesting.md +273 -0
  131. package/docs/uk/dictionary/translation.md +332 -0
  132. package/docs/uk/formatters.md +595 -0
  133. package/docs/uk/how_works_intlayer.md +256 -0
  134. package/docs/uk/index.md +175 -0
  135. package/docs/uk/interest_of_intlayer.md +297 -0
  136. package/docs/uk/intlayer_CMS.md +569 -0
  137. package/docs/uk/intlayer_visual_editor.md +292 -0
  138. package/docs/uk/intlayer_with_angular.md +710 -0
  139. package/docs/uk/intlayer_with_astro.md +256 -0
  140. package/docs/uk/intlayer_with_create_react_app.md +1258 -0
  141. package/docs/uk/intlayer_with_express.md +429 -0
  142. package/docs/uk/intlayer_with_fastify.md +446 -0
  143. package/docs/uk/intlayer_with_lynx+react.md +548 -0
  144. package/docs/uk/intlayer_with_nestjs.md +283 -0
  145. package/docs/uk/intlayer_with_next-i18next.md +640 -0
  146. package/docs/uk/intlayer_with_next-intl.md +456 -0
  147. package/docs/uk/intlayer_with_nextjs_page_router.md +1541 -0
  148. package/docs/uk/intlayer_with_nuxt.md +711 -0
  149. package/docs/uk/intlayer_with_react_router_v7.md +600 -0
  150. package/docs/uk/intlayer_with_react_router_v7_fs_routes.md +669 -0
  151. package/docs/uk/intlayer_with_svelte_kit.md +579 -0
  152. package/docs/uk/intlayer_with_tanstack.md +818 -0
  153. package/docs/uk/intlayer_with_vite+preact.md +1748 -0
  154. package/docs/uk/intlayer_with_vite+react.md +1449 -0
  155. package/docs/uk/intlayer_with_vite+solid.md +302 -0
  156. package/docs/uk/intlayer_with_vite+svelte.md +520 -0
  157. package/docs/uk/intlayer_with_vite+vue.md +1113 -0
  158. package/docs/uk/introduction.md +222 -0
  159. package/docs/uk/locale_mapper.md +242 -0
  160. package/docs/uk/mcp_server.md +211 -0
  161. package/docs/uk/packages/express-intlayer/t.md +465 -0
  162. package/docs/uk/packages/intlayer/getEnumeration.md +159 -0
  163. package/docs/uk/packages/intlayer/getHTMLTextDir.md +121 -0
  164. package/docs/uk/packages/intlayer/getLocaleLang.md +81 -0
  165. package/docs/uk/packages/intlayer/getLocaleName.md +135 -0
  166. package/docs/uk/packages/intlayer/getLocalizedUrl.md +338 -0
  167. package/docs/uk/packages/intlayer/getMultilingualUrls.md +359 -0
  168. package/docs/uk/packages/intlayer/getPathWithoutLocale.md +75 -0
  169. package/docs/uk/packages/intlayer/getPrefix.md +213 -0
  170. package/docs/uk/packages/intlayer/getTranslation.md +190 -0
  171. package/docs/uk/packages/intlayer/getTranslationContent.md +189 -0
  172. package/docs/uk/packages/next-intlayer/t.md +365 -0
  173. package/docs/uk/packages/next-intlayer/useDictionary.md +276 -0
  174. package/docs/uk/packages/next-intlayer/useIntlayer.md +263 -0
  175. package/docs/uk/packages/next-intlayer/useLocale.md +166 -0
  176. package/docs/uk/packages/react-intlayer/t.md +311 -0
  177. package/docs/uk/packages/react-intlayer/useDictionary.md +295 -0
  178. package/docs/uk/packages/react-intlayer/useI18n.md +250 -0
  179. package/docs/uk/packages/react-intlayer/useIntlayer.md +251 -0
  180. package/docs/uk/packages/react-intlayer/useLocale.md +210 -0
  181. package/docs/uk/per_locale_file.md +345 -0
  182. package/docs/uk/plugins/sync-json.md +398 -0
  183. package/docs/uk/readme.md +265 -0
  184. package/docs/uk/releases/v6.md +305 -0
  185. package/docs/uk/releases/v7.md +624 -0
  186. package/docs/uk/roadmap.md +346 -0
  187. package/docs/uk/testing.md +204 -0
  188. package/docs/vi/configuration.md +6 -1
  189. package/docs/vi/dictionary/content_file.md +6 -1
  190. package/docs/zh/configuration.md +6 -1
  191. package/docs/zh/dictionary/content_file.md +6 -1
  192. package/frequent_questions/ar/error-vite-env-only.md +77 -0
  193. package/frequent_questions/de/error-vite-env-only.md +77 -0
  194. package/frequent_questions/en/error-vite-env-only.md +77 -0
  195. package/frequent_questions/en-GB/error-vite-env-only.md +77 -0
  196. package/frequent_questions/es/error-vite-env-only.md +76 -0
  197. package/frequent_questions/fr/error-vite-env-only.md +77 -0
  198. package/frequent_questions/hi/error-vite-env-only.md +77 -0
  199. package/frequent_questions/id/error-vite-env-only.md +77 -0
  200. package/frequent_questions/it/error-vite-env-only.md +77 -0
  201. package/frequent_questions/ja/error-vite-env-only.md +77 -0
  202. package/frequent_questions/ko/error-vite-env-only.md +77 -0
  203. package/frequent_questions/pl/error-vite-env-only.md +77 -0
  204. package/frequent_questions/pt/error-vite-env-only.md +77 -0
  205. package/frequent_questions/ru/error-vite-env-only.md +77 -0
  206. package/frequent_questions/tr/error-vite-env-only.md +77 -0
  207. package/frequent_questions/uk/SSR_Next_no_[locale].md +104 -0
  208. package/frequent_questions/uk/array_as_content_declaration.md +72 -0
  209. package/frequent_questions/uk/build_dictionaries.md +58 -0
  210. package/frequent_questions/uk/build_error_CI_CD.md +74 -0
  211. package/frequent_questions/uk/bun_set_up.md +53 -0
  212. package/frequent_questions/uk/customized_locale_list.md +64 -0
  213. package/frequent_questions/uk/domain_routing.md +113 -0
  214. package/frequent_questions/uk/error-vite-env-only.md +77 -0
  215. package/frequent_questions/uk/esbuild_error.md +29 -0
  216. package/frequent_questions/uk/get_locale_cookie.md +142 -0
  217. package/frequent_questions/uk/intlayer_command_undefined.md +155 -0
  218. package/frequent_questions/uk/locale_incorect_in_url.md +73 -0
  219. package/frequent_questions/uk/package_version_error.md +181 -0
  220. package/frequent_questions/uk/static_rendering.md +44 -0
  221. package/frequent_questions/uk/translated_path_url.md +55 -0
  222. package/frequent_questions/uk/unknown_command.md +97 -0
  223. package/frequent_questions/vi/error-vite-env-only.md +77 -0
  224. package/frequent_questions/zh/error-vite-env-only.md +77 -0
  225. package/legal/uk/privacy_notice.md +83 -0
  226. package/legal/uk/terms_of_service.md +55 -0
  227. package/package.json +9 -9
  228. package/src/generated/blog.entry.ts +20 -0
  229. package/src/generated/frequentQuestions.entry.ts +20 -0
@@ -0,0 +1,245 @@
1
+ ---
2
+ createdAt: 2025-09-10
3
+ updatedAt: 2025-09-10
4
+ title: i18n par composant vs. i18n centralisé : une nouvelle approche avec Intlayer
5
+ description: Une plongée approfondie dans les stratégies d'internationalisation en React, comparant les approches centralisée, par clé et par composant, et présentant Intlayer.
6
+ keywords:
7
+ - i18n
8
+ - React
9
+ - Internationalisation
10
+ - Intlayer
11
+ - Optimisation
12
+ - taille du bundle
13
+ slugs:
14
+ - blog
15
+ - per-component-vs-centralized-i18n
16
+ ---
17
+
18
+ # i18n par composant vs. i18n centralisé
19
+
20
+ L'approche par composant n'est pas un concept nouveau. Par exemple, dans l'écosystème Vue, `vue-i18n` prend en charge l'[i18n SFC (Single File Component)](https://vue-i18n.intlify.dev/guide/advanced/sfc.html). Nuxt propose également des [traductions par composant](https://i18n.nuxtjs.org/docs/guide/per-component-translations), et Angular utilise un modèle similaire via ses [Feature Modules](https://v17.angular.io/guide/feature-modules).
21
+
22
+ Même dans une application Flutter, on retrouve souvent ce schéma :
23
+
24
+ ```bash
25
+ lib/
26
+ └── features/
27
+ └── login/
28
+ ├── login_screen.dart
29
+ └── login_screen.i18n.dart # <- Les traductions se trouvent ici
30
+ ```
31
+
32
+ ```dart fileName='lib/features/login/login_screen.i18n.dart'
33
+ import 'package:i18n_extension/i18n_extension.dart';
34
+
35
+ extension Localization on String {
36
+ static var _t = Translations.byText("en") +
37
+ {
38
+ "Hello": {
39
+ "en": "Hello",
40
+ "fr": "Bonjour",
41
+ },
42
+ };
43
+
44
+ String get i18n => localize(this, _t);
45
+ }
46
+ ```
47
+
48
+ Cependant, dans le monde React, on observe principalement différentes approches que je regrouperai en trois catégories :
49
+
50
+ <Columns>
51
+ <Column>
52
+
53
+ **Approche centralisée** (i18next, next-intl, react-intl, lingui)
54
+
55
+ - (sans namespaces) considère une seule source pour récupérer le contenu. Par défaut, vous chargez le contenu de toutes les pages lorsque votre application se charge.
56
+
57
+ </Column>
58
+ <Column>
59
+
60
+ **Approche granulaire** (intlayer, inlang)
61
+
62
+ - affiner la récupération du contenu par clé ou par composant.
63
+
64
+ </Column>
65
+ </Columns>
66
+
67
+ > Dans ce blog, je ne me concentrerai pas sur les solutions basées sur un compilateur, que j'ai déjà abordées ici : [Compilateur vs i18n déclaratif](https://github.com/aymericzip/intlayer/blob/main/docs/blog/fr/compiler_vs_declarative_i18n.md).
68
+ > Notez que l'i18n basée sur un compilateur (par exemple, Lingui) n'automatise que l'extraction et le chargement du contenu. Sous le capot, ces solutions partagent souvent les mêmes limitations que les autres approches.
69
+
70
+ > Notez que plus vous affinez la façon dont vous récupérez votre contenu, plus vous risquez d'introduire de l'état et de la logique supplémentaires dans vos composants.
71
+
72
+ Les approches granulaires sont plus flexibles que les approches centralisées, mais c'est souvent un compromis. Même si ces bibliothèques mettent en avant le "tree shaking", en pratique vous finirez souvent par charger une page dans chaque langue.
73
+
74
+ Donc, de manière générale, la décision se résume ainsi :
75
+
76
+ - Si votre application a plus de pages que de langues, vous devriez privilégier une approche granulaire.
77
+ - Si vous avez plus de langues que de pages, vous devriez opter pour une approche centralisée.
78
+
79
+ Bien sûr, les auteurs des bibliothèques sont conscients de ces limites et proposent des solutions de contournement. Parmi elles : scinder en namespaces, charger dynamiquement des fichiers JSON (`await import()`), ou purger le contenu lors du build.
80
+
81
+ En même temps, vous devez savoir que lorsque vous chargez dynamiquement votre contenu, vous introduisez des requêtes supplémentaires vers votre serveur. Chaque `useState` supplémentaire ou hook signifie une requête serveur supplémentaire.
82
+
83
+ > Pour résoudre ce point, Intlayer suggère de regrouper plusieurs définitions de contenu sous une même clé ; Intlayer fusionnera ensuite ce contenu.
84
+
85
+ Mais parmi toutes ces solutions, il est clair que l'approche centralisée est la plus populaire.
86
+
87
+ ### Alors, pourquoi l'approche centralisée est-elle si populaire ?
88
+
89
+ - Tout d'abord, i18next a été la première solution à devenir largement utilisée, suivant une philosophie inspirée des architectures PHP et Java (MVC), qui reposent sur une stricte séparation des préoccupations (garder le contenu séparé du code). Elle est arrivée en 2011, établissant ses standards bien avant le passage massif aux architectures basées sur les composants (comme React).
90
+ - Ensuite, une fois qu'une bibliothèque est largement adoptée, il devient difficile de faire évoluer l'écosystème vers d'autres approches.
91
+ - L'utilisation d'une approche centralisée facilite également l'intégration avec des systèmes de gestion de traduction tels que Crowdin, Phrase ou Localized.
92
+ - La logique d'une approche par composant est plus complexe que celle d'une approche centralisée et demande plus de temps de développement, surtout lorsqu'il faut résoudre des problèmes comme l'identification de l'emplacement du contenu.
93
+
94
+ ### Ok, mais pourquoi ne pas simplement rester sur une approche centralisée ?
95
+
96
+ Laissez-moi vous expliquer pourquoi cela peut poser problème pour votre application :
97
+
98
+ - **Données inutilisées :**
99
+ Lorsque une page se charge, vous chargez souvent le contenu de toutes les autres pages. (Dans une application de 10 pages, cela représente 90 % de contenu inutile chargé). Vous chargez un modal en lazy load ? La bibliothèque i18n s'en fiche, elle charge d'abord les chaînes de toute façon.
100
+ - **Performances :**
101
+ À chaque re-render, chacun de vos composants est hydraté avec une charge JSON massive, ce qui affecte la réactivité de votre application à mesure qu'elle grandit.
102
+ - **Maintenance :**
103
+ Maintenir de gros fichiers JSON est pénible. Vous devez sauter d'un fichier à l'autre pour insérer une traduction, en vous assurant qu'aucune traduction ne manque et qu'aucune **clé orpheline** ne subsiste.
104
+ - **Design-system :**
105
+ Cela crée une incompatibilité avec les design systems (par exemple, un composant `LoginForm`) et limite la duplication de composants entre différentes applications.
106
+
107
+ **"Mais nous avons inventé Namespaces !"**
108
+
109
+ Bien sûr, et c'est une avancée majeure. Regardons la comparaison de la taille du bundle principal d'une configuration Vite + React + React Router v7 + Intlayer. Nous avons simulé une application de 20 pages.
110
+
111
+ Le premier exemple n'inclut pas de traductions chargées à la demande par locale et aucune séparation en namespaces. Le second inclut une purge du contenu + chargement dynamique des traductions.
112
+
113
+ | Bundle optimisé | Bundle non optimisé |
114
+ | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
115
+ | ![bundle non optimisé](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png?raw=true) | ![bundle optimisé](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true) |
116
+
117
+ Donc, grâce aux namespaces, nous sommes passés de cette structure :
118
+
119
+ ```bash
120
+ locale/
121
+ ├── en.json
122
+ ├── fr.json
123
+ └── es.json
124
+ ```
125
+
126
+ À celle-ci :
127
+
128
+ ```bash
129
+ locale/
130
+ ├── en/
131
+ │ ├── common.json
132
+ │ ├── navbar.json
133
+ │ ├── footer.json
134
+ │ ├── home.json
135
+ │ └── about.json
136
+ ├── fr/
137
+ │ └── ...
138
+ └── es/
139
+ └── ...
140
+
141
+ ```
142
+
143
+ Vous devez maintenant gérer avec précision quelles parties du contenu de votre application doivent être chargées, et où. En conclusion, la grande majorité des projets passent simplement outre cette étape en raison de la complexité (voir par exemple le guide [next-i18next](https://github.com/aymericzip/intlayer/blob/main/docs/blog/fr/i18n_using_next-i18next.md) pour constater les défis que représente (simplement) le suivi des bonnes pratiques).
144
+
145
+ > Notez que ce problème n'est pas spécifique à i18next, mais concerne toutes les approches centralisées listées ci‑dessus.
146
+
147
+ Cependant, je tiens à vous rappeler que toutes les approches granulaires ne résolvent pas ce problème. Par exemple, les approches `vue-i18n SFC` ou `inlang` ne réalisent pas automatiquement le lazy loading des traductions par locale, vous échangez ainsi le problème de la taille du bundle contre un autre.
148
+
149
+ De plus, sans une séparation des préoccupations appropriée, il devient beaucoup plus difficile d'extraire et de fournir vos traductions aux traducteurs pour relecture.
150
+
151
+ ### Comment l'approche par composant d'Intlayer résout ce problème
152
+
153
+ Intlayer procède en plusieurs étapes :
154
+
155
+ 1. **Déclaration :** Déclarez votre contenu n'importe où dans votre codebase en utilisant des fichiers `*.content.{ts|jsx|cjs|json|json5|...}`. Cela garantit la séparation des préoccupations tout en gardant le contenu colocé à proximité du code. Un fichier de contenu peut être par-locale ou multilingue.
156
+ 2. **Traitement :** Intlayer exécute une étape de build pour traiter la logique JS, gérer les traductions manquantes (fallbacks), générer des types TypeScript, gérer le contenu dupliqué, récupérer le contenu depuis votre CMS, et plus encore.
157
+ 3. **Purge :** Lors du build de votre application, Intlayer purge le contenu inutilisé (un peu comme Tailwind gère vos classes) en remplaçant le contenu comme suit :
158
+
159
+ **Déclaration :**
160
+
161
+ ```tsx
162
+ // src/MyComponent.tsx
163
+ export const MyComponent = () => {
164
+ const content = useIntlayer("my-key");
165
+ return <h1>{content.title}</h1>;
166
+ };
167
+ ```
168
+
169
+ ```tsx
170
+ // src/myComponent.content.ts
171
+ export const {
172
+ key: "my-key",
173
+ content: t({
174
+ fr: { title: "Mon titre" },
175
+ en: { title: "My title" }
176
+ })
177
+ }
178
+
179
+ ```
180
+
181
+ **Traitement :** Intlayer construit le dictionnaire à partir du fichier `.content` et génère :
182
+
183
+ ```json5
184
+ // .intlayer/dynamic_dictionary/fr/my-key.json
185
+ {
186
+ "key": "my-key",
187
+ "content": { "title": "Mon titre" },
188
+ }
189
+ ```
190
+
191
+ **Remplacement :** Intlayer transforme votre composant lors du build de l'application.
192
+
193
+ **- Mode d'import statique :**
194
+
195
+ ```tsx
196
+ // Représentation du composant en syntaxe de type JSX
197
+ export const MyComponent = () => {
198
+ const content = useDictionary({
199
+ key: "my-key",
200
+ content: {
201
+ nodeType: "translation",
202
+ translation: {
203
+ en: { title: "My title" },
204
+ fr: { title: "Mon titre" },
205
+ },
206
+ },
207
+ });
208
+
209
+ return <h1>{content.title}</h1>;
210
+ };
211
+ ```
212
+
213
+ **- Mode d'import dynamique :**
214
+
215
+ ```tsx
216
+ // Représentation du composant en syntaxe de type JSX
217
+ export const MyComponent = () => {
218
+ const content = useDictionaryAsync({
219
+ en: () =>
220
+ import(".intlayer/dynamic_dictionary/en/my-key.json", {
221
+ with: { type: "json" },
222
+ }).then((mod) => mod.default),
223
+ // Idem pour les autres langues
224
+ });
225
+
226
+ return <h1>{content.title}</h1>;
227
+ };
228
+ ```
229
+
230
+ > `useDictionaryAsync` utilise un mécanisme de type Suspense pour charger le JSON localisé uniquement lorsque c'est nécessaire.
231
+
232
+ **Principaux avantages de cette approche par composant :**
233
+
234
+ - Garder la déclaration de votre contenu proche de vos composants permet une meilleure maintenabilité (p.ex. déplacer un composant vers une autre application ou design system. La suppression du dossier du composant supprime également le contenu associé, comme vous le faites probablement déjà pour vos fichiers `.test` et `.stories`)
235
+
236
+ - Une approche par composant évite que les agents IA aient besoin de parcourir tous vos fichiers. Elle regroupe toutes les traductions au même endroit, limitant la complexité de la tâche et la quantité de tokens utilisés.
237
+
238
+ ### Limitations
239
+
240
+ Bien sûr, cette approche implique des compromis :
241
+
242
+ - Il est plus difficile de se connecter à d'autres systèmes de l10n et à des outils supplémentaires.
243
+ - Cela entraîne un lock-in (ce qui est déjà le cas avec toute solution i18n en raison de leur syntaxe spécifique).
244
+
245
+ C'est pourquoi Intlayer cherche à fournir un ensemble d'outils complet pour l'i18n (100 % gratuit et OSS), incluant la traduction par IA en utilisant votre propre fournisseur d'IA et vos clés API. Intlayer fournit aussi des outils pour synchroniser vos JSON, fonctionnant comme les formatters de messages ICU / vue-i18n / i18next pour mapper le contenu vers leurs formats spécifiques.
@@ -0,0 +1,249 @@
1
+ ---
2
+ createdAt: 2025-09-10
3
+ updatedAt: 2025-09-10
4
+ title: प्रति-कम्पोनेंट बनाम केंद्रीकृत i18n: Intlayer के साथ एक नया दृष्टिकोण
5
+ description: React में internationalization रणनीतियों का गहन विश्लेषण — centralized, per-key और per-component approaches की तुलना, तथा Intlayer का परिचय।
6
+ keywords:
7
+ - i18n
8
+ - React
9
+ - Internationalization
10
+ - Intlayer
11
+ - Optimization
12
+ - Bundle Size
13
+ slugs:
14
+ - blog
15
+ - per-component-vs-centralized-i18n
16
+ ---
17
+
18
+ # प्रति-कम्पोनेंट बनाम केंद्रीकृत i18n
19
+
20
+ प्रति-कम्पोनेंट दृष्टिकोण एक नया अवधारणा नहीं है। उदाहरण के लिए, Vue इकोसिस्टम में, `vue-i18n` [SFC i18n (Single File Component)](https://vue-i18n.intlify.dev/guide/advanced/sfc.html) का समर्थन करता है। Nuxt भी [प्रति-कम्पोनेंट अनुवाद](https://i18n.nuxtjs.org/docs/guide/per-component-translations) प्रदान करता है, और Angular अपने [Feature Modules](https://v17.angular.io/guide/feature-modules) के माध्यम से एक समान पैटर्न का उपयोग करता है।
21
+
22
+ यहाँ तक कि एक Flutter एप में भी, हम अक्सर इस पैटर्न को पा सकते हैं:
23
+
24
+ ```bash
25
+ lib/
26
+ └── features/
27
+ └── login/
28
+ ├── login_screen.dart
29
+ └── login_screen.i18n.dart # <- अनुवाद यहीं रहते हैं
30
+ ```
31
+
32
+ ```dart fileName='lib/features/login/login_screen.i18n.dart'
33
+ import 'package:i18n_extension/i18n_extension.dart';
34
+
35
+ extension Localization on String {
36
+ static var _t = Translations.byText("en") +
37
+ {
38
+ "Hello": {
39
+ "en": "Hello",
40
+ "fr": "Bonjour",
41
+ },
42
+ };
43
+
44
+ String get i18n => localize(this, _t);
45
+ }
46
+ ```
47
+
48
+ हालाँकि, React दुनिया में, हम मुख्य रूप से विभिन्न दृष्टिकोण देखते हैं, जिन्हें मैं तीन श्रेणियों में समूहीकृत करूँगा:
49
+
50
+ <Columns>
51
+ <Column>
52
+
53
+ **केंद्रित दृष्टिकोण** (i18next, next-intl, react-intl, lingui)
54
+
55
+ - (namespace के बिना) सामग्री प्राप्त करने के लिए एकल स्रोत मानता है। डिफ़ॉल्ट रूप से, जब आपका ऐप लोड होता है तो आप सभी पृष्ठों से सामग्री लोड कर लेते हैं।
56
+
57
+ </Column>
58
+ <Column>
59
+
60
+ **ग्रैन्युलर अप्रोच** (intlayer, inlang)
61
+
62
+ - सामग्री पुनःप्राप्ति को प्रति-कुंजी या प्रति-कॉम्पोनेंट के स्तर पर फाइन-ग्रेन करें।
63
+
64
+ </Column>
65
+ </Columns>
66
+
67
+ > इस ब्लॉग में, मैं compiler-based समाधानों पर ध्यान नहीं दूँगा, जिन्हें मैंने पहले यहाँ कवर किया है: [Compiler vs Declarative i18n](https://github.com/aymericzip/intlayer/blob/main/docs/blog/hi/compiler_vs_declarative_i18n.md).
68
+ > ध्यान दें कि compiler-based i18n (उदा., Lingui) केवल सामग्री के extraction और loading को स्वचालित करता है। आंतरिक रूप से, इनके पास अक्सर अन्य approaches की जैसी ही सीमाएँ होती हैं।
69
+
70
+ > ध्यान दें कि जितना अधिक आप अपनी सामग्री को फाइन-ग्रेन तरीके से पुनःप्राप्त करते हैं, उतना ही अधिक आप अपने कॉम्पोनेंट्स में अतिरिक्त state और logic जोड़ने का जोखिम उठाते हैं।
71
+
72
+ ग्रैन्युलर approaches केंद्रीकृत (centralized) approaches की तुलना में अधिक लचीली होती हैं, लेकिन अक्सर यह एक tradeoff होता है। भले ही उन लाइब्रेरीज़ द्वारा "tree shaking" का दावा किया जाता हो, व्यवहार में अक्सर आप हर भाषा में एक पेज लोड करते हुए ही समाप्त होते हैं।
73
+
74
+ तो, मोटे तौर पर, निर्णय इस तरह टूटता है:
75
+
76
+ - यदि आपके एप्लिकेशन में भाषाओं की तुलना में पेज अधिक हैं, तो आपको granular approach को प्राथमिकता देनी चाहिए।
77
+ - यदि आपके पास पृष्ठों की तुलना में भाषाएँ अधिक हैं, तो आपको centralized approach की ओर झुकना चाहिए।
78
+
79
+ बेशक, लाइब्रेरी के लेखक इन सीमाओं से अवगत हैं और वर्कअराउंड प्रदान करते हैं।
80
+ इनमें से कुछ: namespaces में विभाजन, डायनामिक रूप से JSON फाइलें लोड करना (`await import()`), या बिल्ड टाइम पर कंटेंट को purge करना।
81
+
82
+ साथ ही, आपको यह जानना चाहिए कि जब आप अपना कंटेंट डायनामिक रूप से लोड करते हैं, तो आप अपने सर्वर पर अतिरिक्त अनुरोध जोड़ देते हैं। हर अतिरिक्त `useState` या hook का मतलब एक अतिरिक्त सर्वर अनुरोध होता है।
83
+
84
+ > इस बिंदु को ठीक करने के लिए, Intlayer सुझाव देता है कि कई कंटेंट परिभाषाओं को एक ही key के तहत समूहित किया जाए; Intlayer तब उन कंटेंट्स को मर्ज कर देगा।
85
+
86
+ लेकिन इन सभी समाधानों से स्पष्ट है कि सबसे लोकप्रिय तरीका केंद्रीकृत (centralized) ही है।
87
+
88
+ ### तो केंद्रीकृत दृष्टिकोण इतना लोकप्रिय क्यों है?
89
+
90
+ - सबसे पहले, i18next वह पहला समाधान था जो व्यापक रूप से अपनाया गया, एक दर्शन का पालन करते हुए जो PHP और Java आर्किटेक्चर (MVC) से प्रेरित था और कड़े separation of concerns (content को code से अलग रखने) पर निर्भर करता है। यह 2011 में आया और Component-Based Architectures (जैसे React) की ओर बड़े बदलाव से पहले ही अपने मानक स्थापित कर चुका था।
91
+ - फिर, एक बार कोई लाइब्रेरी व्यापक रूप से अपनाई जाने के बाद, इकोसिस्टम को अन्य पैटर्न की ओर शिफ्ट करना मुश्किल हो जाता है।
92
+ - केंद्रीयकृत दृष्टिकोण का उपयोग Translation Management Systems जैसे Crowdin, Phrase, या Localized में चीज़ों को भी आसान बनाता है।
93
+ - per-component approach के पीछे की logic केंद्रीय दृष्टिकोण की तुलना में अधिक जटिल है और विकसित करने में अतिरिक्त समय लेती है, खासकर जब आपको यह पहचानने जैसी समस्याओं को हल करना हो कि content कहाँ स्थित है।
94
+
95
+ ### ठीक है, लेकिन सिर्फ़ Centralized दृष्टिकोण पर क्यों न रहें?
96
+
97
+ Let me tell you why it can be problematic for your app:
98
+
99
+ - **अप्रयुक्त डेटा (Unused Data):**
100
+ जब कोई पेज लोड होता है, तो अक्सर आप सभी अन्य पेजों की सामग्री भी लोड कर लेते हैं। (एक 10-पेज ऐप में, इसका मतलब है कि 90% सामग्री अनुपयोगी रूप से लोड होती है)। क्या आप किसी modal को lazy load करते हैं? i18n लाइब्रेरी के लिए फर्क नहीं पड़ता — वह पहले ही strings लोड कर लेती है।
101
+ - **प्रदर्शन (Performance):**
102
+ हर re-render के लिए, आपके हर एक component को एक भारी JSON payload से hydrate किया जाता है, जो जैसे-जैसे आपका ऐप बढ़ता है उसकी प्रतिक्रियाशीलता (reactivity) को प्रभावित करता है।
103
+ - **रखरखाव (Maintenance):**
104
+ बड़े JSON फाइलों का रखरखाव कष्टदायक है। किसी अनुवाद को जोड़ने के लिए आपको फाइलों के बीच कूदना पड़ता है, यह सुनिश्चित करते हुए कि कोई अनुवाद गायब न हो और कोई **orphan keys** पीछे न रह जाएँ।
105
+ - **डिज़ाइन-सिस्टम (Design-system):**
106
+ यह design systems के साथ असंगति पैदा करता है (उदा., एक `LoginForm` कंपोनेंट) और विभिन्न apps में कॉम्पोनेंट के डुप्लिकेशन को सीमित कर देता है।
107
+
108
+ **"लेकिन हमने Namespaces का आविष्कार किया!"**
109
+
110
+ बिल्कुल, और यह एक बड़ा कदम आगे है। आइए Vite + React + React Router v7 + Intlayer सेटअप के मेन बंडल साइज की तुलना देखें। हमने एक 20-पेज एप्लिकेशन का सिमुलेशन किया।
111
+
112
+ पहला उदाहरण प्रति-लोकल lazy-loaded अनुवाद शामिल नहीं करता है और namespace splitting नहीं है। दूसरा content purging + dynamic loading के साथ अनुवाद दिखाता है।
113
+
114
+ | ऑप्टिमाइज़्ड बंडल | अनऑप्टिमाइज़्ड बंडल |
115
+ | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
116
+ | ![अनुकूलित नहीं किया गया बंडल](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png?raw=true) | ![अनुकूलित बंडल](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true) |
117
+
118
+ Namespaces के कारण, हम इस संरचना से नीचे दी गई संरचना में आ गए:
119
+
120
+ ```bash
121
+ locale/
122
+ ├── en.json
123
+ ├── fr.json
124
+ └── es.json
125
+ ```
126
+
127
+ To this one:
128
+
129
+ ```bash
130
+ locale/
131
+ ├── en/
132
+ │ ├── common.json
133
+ │ ├── navbar.json
134
+ │ ├── footer.json
135
+ │ ├── home.json
136
+ │ └── about.json
137
+ ├── fr/
138
+ │ └── ...
139
+ └── es/
140
+ └── ...
141
+
142
+ ```
143
+
144
+ अब आपको बारीकी से यह प्रबंधित करना होगा कि आपके ऐप का कौन सा कंटेंट कब और कहाँ लोड किया जाना चाहिए। नतीजा, जटिलता के कारण अधिकांश प्रोजेक्ट इस हिस्से को छोड़ देते हैं (उदाहरण के लिए चुनौतियाँ देखने के लिए [next-i18next गाइड](https://github.com/aymericzip/intlayer/blob/main/docs/blog/hi/i18n_using_next-i18next.md) देखें — जो सिर्फ़ अच्छी प्रथाओं का पालन करने से उत्पन्न होती हैं)।
145
+ परिणामस्वरूप, वे प्रोजेक्ट पहले बताई गई भारी JSON लोडिंग समस्या का सामना कर लेते हैं।
146
+
147
+ > ध्यान दें कि यह समस्या केवल i18next तक सीमित नहीं है, बल्कि ऊपर सूचीबद्ध सभी केंद्रीकृत approaches पर लागू होती है।
148
+
149
+ हालाँकि, मैं आपको यह याद दिलाना चाहता हूँ कि सभी granular approaches इसे हल नहीं करतीं। उदाहरण के लिए, `vue-i18n SFC` या `inlang` approaches स्वाभाविक रूप से प्रति-लोकैल के अनुसार translations को lazy load नहीं करतीं, इसलिए आप केवल bundle size की समस्या को किसी और समस्या से बदल देते हैं।
150
+
151
+ इसके अलावा, proper separation of concerns के बिना, translators के लिए अपने translations को निकालना और review के लिए प्रदान करना काफी मुश्किल हो जाता है।
152
+
153
+ ### Intlayer का per-component approach इसे कैसे हल करता है
154
+
155
+ Intlayer कई चरणों में आगे बढ़ता है:
156
+
157
+ 1. **Declaration:** अपनी सामग्री को अपने codebase में कहीं भी `*.content.{ts|jsx|cjs|json|json5|...}` फ़ाइलों का उपयोग करके Declare करें। इससे separation of concerns सुनिश्चित होती है जबकि content को colocated रखा जाता है। एक content फ़ाइल per-locale हो सकती है या multilingual।
158
+ 2. **प्रोसेसिंग:** Intlayer एक बिल्ड स्टेप चलाता है ताकि JS लॉजिक को प्रोसेस किया जा सके, अनुपस्थित अनुवाद fallback को संभाला जा सके, TypeScript टाइप्स जनरेट किए जा सकें, डुप्लिकेट कंटेंट का प्रबंधन किया जा सके, आपके CMS से कंटेंट फ़ेच किया जा सके, और भी बहुत कुछ।
159
+ 3. **पर्जिंग:** जब आपकी ऐप बिल्ड होती है, Intlayer अनयूज़्ड कंटेंट को पर्ज करता है (थोड़ा वैसा ही जैसे Tailwind आपके क्लासेज़ को मैनेज करता है) और कंटेंट को निम्नानुसार बदल देता है:
160
+
161
+ **घोषणा:**
162
+
163
+ ```tsx
164
+ // src/MyComponent.tsx
165
+ export const MyComponent = () => {
166
+ const content = useIntlayer("my-key");
167
+ return <h1>{content.title}</h1>;
168
+ };
169
+ ```
170
+
171
+ ```tsx
172
+ // src/myComponent.content.ts
173
+ export const {
174
+ key: "my-key",
175
+ content: t({
176
+ hi: { title: "मेरा शीर्षक" },
177
+ en: { title: "My title" },
178
+ fr: { title: "Mon titre" }
179
+ })
180
+ }
181
+
182
+ ```
183
+
184
+ **प्रोसेसिंग:** Intlayer `.content` फ़ाइल के आधार पर डिक्शनरी बनाता है और जेनरेट करता है:
185
+
186
+ ```json5
187
+ // .intlayer/dynamic_dictionary/en/my-key.json
188
+ {
189
+ "key": "my-key",
190
+ "content": { "title": "My title" },
191
+ }
192
+ ```
193
+
194
+ **प्रतिस्थापन:** Intlayer आपके एप्लिकेशन बिल्ड के दौरान आपके कंपोनेंट को रूपांतरित करता है।
195
+
196
+ **- स्टैटिक इम्पोर्ट मोड:**
197
+
198
+ ```tsx
199
+ // JSX जैसी सिंटैक्स में कंपोनेंट का प्रतिनिधित्व
200
+ export const MyComponent = () => {
201
+ const content = useDictionary({
202
+ key: "my-key",
203
+ content: {
204
+ nodeType: "translation",
205
+ translation: {
206
+ hi: { title: "मेरा शीर्षक" },
207
+ en: { title: "My title" },
208
+ fr: { title: "Mon titre" },
209
+ },
210
+ },
211
+ });
212
+
213
+ return <h1>{content.title}</h1>;
214
+ };
215
+ ```
216
+
217
+ **- डायनामिक इम्पोर्ट मोड:**
218
+
219
+ ```tsx
220
+ // JSX जैसी सिंटैक्स में कंपोनेंट का प्रतिनिधित्व
221
+ export const MyComponent = () => {
222
+ const content = useDictionaryAsync({
223
+ en: () =>
224
+ import(".intlayer/dynamic_dictionary/en/my-key.json", {
225
+ with: { type: "json" },
226
+ }).then((mod) => mod.default),
227
+ // अन्य भाषाओं के लिए भी समान
228
+ });
229
+
230
+ return <h1>{content.title}</h1>;
231
+ };
232
+ ```
233
+
234
+ > `useDictionaryAsync` एक Suspense-जैसी मैकेनिज़्म का उपयोग करता है ताकि स्थानीयकृत JSON केवल आवश्यकता पड़ने पर लोड हो।
235
+
236
+ **इस प्रति-कॉम्पोनेंट दृष्टिकोण के प्रमुख लाभ:**
237
+
238
+ - अपनी content घोषणा को अपने components के पास रखकर मेंटेनबिलिटी बेहतर होती है (उदा. किसी component को किसी अन्य app या design system में लेकर जाना)। Component फ़ोल्डर हटाने पर संबंधित content भी हट जाता है, जैसा कि आप शायद अपने `.test`, `.stories` के साथ पहले से करते हैं)
239
+
240
+ - प्रति-कम्पोनेंट दृष्टिकोण AI एजेंटों को आपकी सभी अलग-अलग फ़ाइलों में उछलने की आवश्यकता से बचाता है। यह सभी अनुवादों को एक ही स्थान पर रखता है, जिससे कार्य की जटिलता और उपयोग किए जाने वाले टोकन्स की मात्रा सीमित रहती है।
241
+
242
+ ### सीमाएँ
243
+
244
+ बेशक, इस दृष्टिकोण के साथ कुछ समझौते आते हैं:
245
+
246
+ - अन्य l10n सिस्टम्स और अतिरिक्त टूलिंग से कनेक्ट करना कठिन हो जाता है।
247
+ - आप लॉक-इन हो जाते हैं (जो कि मूलतः किसी भी i18n समाधान के साथ पहले से ही होता है उनके विशिष्ट सिंटैक्स के कारण)।
248
+
249
+ यही कारण है कि Intlayer i18n के लिए एक संपूर्ण टूलसेट प्रदान करने का प्रयास करता है (100% फ्री और OSS), जिसमें आपके अपने AI Provider और API keys का उपयोग करके AI अनुवाद शामिल है। Intlayer यह भी टूलिंग प्रदान करता है ताकि आपका JSON सिंक्रोनाइज़ हो सके, जो ICU / vue-i18n / i18next संदेश फॉर्मेटर्स की तरह कार्य करता है ताकि सामग्री को उनके विशिष्ट फॉर्मैट्स में मैप किया जा सके।