@intlayer/docs 9.5.7 → 9.5.8

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 (162) hide show
  1. package/blog/ar/is_intlayer_lighter_than_paraglide.md +284 -0
  2. package/blog/de/is_intlayer_lighter_than_paraglide.md +284 -0
  3. package/blog/en/is_intlayer_lighter_than_paraglide.md +288 -0
  4. package/blog/en-GB/is_intlayer_lighter_than_paraglide.md +285 -0
  5. package/blog/es/is_intlayer_lighter_than_paraglide.md +284 -0
  6. package/blog/fr/is_intlayer_lighter_than_paraglide.md +284 -0
  7. package/blog/hi/is_intlayer_lighter_than_paraglide.md +284 -0
  8. package/blog/id/is_intlayer_lighter_than_paraglide.md +284 -0
  9. package/blog/it/is_intlayer_lighter_than_paraglide.md +284 -0
  10. package/blog/ja/is_intlayer_lighter_than_paraglide.md +284 -0
  11. package/blog/ko/is_intlayer_lighter_than_paraglide.md +284 -0
  12. package/blog/pl/is_intlayer_lighter_than_paraglide.md +284 -0
  13. package/blog/pt/is_intlayer_lighter_than_paraglide.md +284 -0
  14. package/blog/ru/is_intlayer_lighter_than_paraglide.md +284 -0
  15. package/blog/tr/is_intlayer_lighter_than_paraglide.md +284 -0
  16. package/blog/uk/is_intlayer_lighter_than_paraglide.md +284 -0
  17. package/blog/vi/is_intlayer_lighter_than_paraglide.md +284 -0
  18. package/blog/zh/is_intlayer_lighter_than_paraglide.md +284 -0
  19. package/dist/cjs/generated/blog.entry.cjs +20 -0
  20. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  21. package/dist/cjs/generated/docs.entry.cjs +20 -0
  22. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  23. package/dist/cjs/index.cjs +2 -2
  24. package/dist/esm/generated/blog.entry.mjs +20 -0
  25. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  26. package/dist/esm/generated/docs.entry.mjs +20 -0
  27. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  28. package/dist/esm/index.mjs +2 -2
  29. package/dist/types/generated/blog.entry.d.ts +1 -0
  30. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  31. package/dist/types/generated/docs.entry.d.ts +1 -0
  32. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  33. package/docs/ar/benchmark/nextjs.md +6 -3
  34. package/docs/ar/benchmark/solid.md +21 -4
  35. package/docs/ar/benchmark/svelte.md +18 -3
  36. package/docs/ar/benchmark/tanstack.md +6 -3
  37. package/docs/ar/benchmark/vue.md +14 -5
  38. package/docs/ar/cli/index.md +6 -1
  39. package/docs/ar/cli/upgrade.md +125 -0
  40. package/docs/de/benchmark/nextjs.md +6 -3
  41. package/docs/de/benchmark/solid.md +21 -4
  42. package/docs/de/benchmark/svelte.md +18 -3
  43. package/docs/de/benchmark/tanstack.md +6 -3
  44. package/docs/de/benchmark/vue.md +14 -5
  45. package/docs/de/cli/index.md +6 -1
  46. package/docs/de/cli/upgrade.md +125 -0
  47. package/docs/en/agent_skills.md +29 -1
  48. package/docs/en/benchmark/nextjs.md +6 -3
  49. package/docs/en/benchmark/solid.md +21 -4
  50. package/docs/en/benchmark/svelte.md +18 -3
  51. package/docs/en/benchmark/tanstack.md +7 -4
  52. package/docs/en/benchmark/vue.md +15 -6
  53. package/docs/en/cli/index.md +6 -1
  54. package/docs/en/cli/upgrade.md +125 -0
  55. package/docs/en-GB/benchmark/nextjs.md +6 -3
  56. package/docs/en-GB/benchmark/solid.md +21 -4
  57. package/docs/en-GB/benchmark/svelte.md +18 -3
  58. package/docs/en-GB/benchmark/tanstack.md +6 -3
  59. package/docs/en-GB/benchmark/vue.md +15 -6
  60. package/docs/en-GB/cli/index.md +6 -1
  61. package/docs/en-GB/cli/upgrade.md +125 -0
  62. package/docs/es/benchmark/nextjs.md +6 -3
  63. package/docs/es/benchmark/solid.md +21 -4
  64. package/docs/es/benchmark/svelte.md +18 -3
  65. package/docs/es/benchmark/tanstack.md +6 -3
  66. package/docs/es/benchmark/vue.md +14 -5
  67. package/docs/es/cli/index.md +6 -1
  68. package/docs/es/cli/upgrade.md +125 -0
  69. package/docs/fr/benchmark/nextjs.md +6 -3
  70. package/docs/fr/benchmark/solid.md +21 -4
  71. package/docs/fr/benchmark/svelte.md +18 -3
  72. package/docs/fr/benchmark/tanstack.md +6 -3
  73. package/docs/fr/benchmark/vue.md +15 -6
  74. package/docs/fr/cli/index.md +6 -1
  75. package/docs/fr/cli/upgrade.md +125 -0
  76. package/docs/hi/benchmark/nextjs.md +6 -3
  77. package/docs/hi/benchmark/solid.md +21 -4
  78. package/docs/hi/benchmark/svelte.md +18 -3
  79. package/docs/hi/benchmark/tanstack.md +6 -3
  80. package/docs/hi/benchmark/vue.md +15 -6
  81. package/docs/hi/cli/index.md +6 -1
  82. package/docs/hi/cli/upgrade.md +125 -0
  83. package/docs/id/benchmark/nextjs.md +6 -3
  84. package/docs/id/benchmark/solid.md +21 -4
  85. package/docs/id/benchmark/svelte.md +18 -3
  86. package/docs/id/benchmark/tanstack.md +6 -3
  87. package/docs/id/benchmark/vue.md +15 -6
  88. package/docs/id/cli/index.md +6 -1
  89. package/docs/id/cli/upgrade.md +125 -0
  90. package/docs/it/benchmark/nextjs.md +6 -3
  91. package/docs/it/benchmark/solid.md +21 -4
  92. package/docs/it/benchmark/svelte.md +18 -3
  93. package/docs/it/benchmark/tanstack.md +6 -3
  94. package/docs/it/benchmark/vue.md +14 -5
  95. package/docs/it/cli/index.md +6 -1
  96. package/docs/it/cli/upgrade.md +125 -0
  97. package/docs/ja/benchmark/nextjs.md +6 -3
  98. package/docs/ja/benchmark/solid.md +21 -4
  99. package/docs/ja/benchmark/svelte.md +18 -3
  100. package/docs/ja/benchmark/tanstack.md +5 -2
  101. package/docs/ja/benchmark/vue.md +14 -5
  102. package/docs/ja/cli/index.md +6 -1
  103. package/docs/ja/cli/upgrade.md +125 -0
  104. package/docs/ko/benchmark/nextjs.md +6 -3
  105. package/docs/ko/benchmark/solid.md +21 -4
  106. package/docs/ko/benchmark/svelte.md +18 -3
  107. package/docs/ko/benchmark/tanstack.md +6 -3
  108. package/docs/ko/benchmark/vue.md +15 -6
  109. package/docs/ko/cli/index.md +6 -1
  110. package/docs/ko/cli/upgrade.md +126 -0
  111. package/docs/pl/benchmark/nextjs.md +6 -3
  112. package/docs/pl/benchmark/solid.md +21 -4
  113. package/docs/pl/benchmark/svelte.md +18 -3
  114. package/docs/pl/benchmark/tanstack.md +6 -3
  115. package/docs/pl/benchmark/vue.md +15 -6
  116. package/docs/pl/cli/index.md +6 -1
  117. package/docs/pl/cli/upgrade.md +125 -0
  118. package/docs/pt/benchmark/nextjs.md +6 -3
  119. package/docs/pt/benchmark/solid.md +21 -4
  120. package/docs/pt/benchmark/svelte.md +18 -3
  121. package/docs/pt/benchmark/tanstack.md +6 -3
  122. package/docs/pt/benchmark/vue.md +14 -5
  123. package/docs/pt/cli/index.md +6 -1
  124. package/docs/pt/cli/upgrade.md +125 -0
  125. package/docs/ru/benchmark/nextjs.md +6 -3
  126. package/docs/ru/benchmark/solid.md +21 -4
  127. package/docs/ru/benchmark/svelte.md +18 -3
  128. package/docs/ru/benchmark/tanstack.md +6 -3
  129. package/docs/ru/benchmark/vue.md +15 -6
  130. package/docs/ru/cli/index.md +6 -1
  131. package/docs/ru/cli/upgrade.md +125 -0
  132. package/docs/tr/benchmark/nextjs.md +6 -3
  133. package/docs/tr/benchmark/solid.md +21 -4
  134. package/docs/tr/benchmark/svelte.md +18 -3
  135. package/docs/tr/benchmark/tanstack.md +6 -3
  136. package/docs/tr/benchmark/vue.md +15 -6
  137. package/docs/tr/cli/index.md +6 -1
  138. package/docs/tr/cli/upgrade.md +125 -0
  139. package/docs/uk/benchmark/nextjs.md +6 -3
  140. package/docs/uk/benchmark/solid.md +21 -4
  141. package/docs/uk/benchmark/svelte.md +18 -3
  142. package/docs/uk/benchmark/tanstack.md +6 -3
  143. package/docs/uk/benchmark/vue.md +15 -6
  144. package/docs/uk/cli/index.md +6 -1
  145. package/docs/uk/cli/upgrade.md +125 -0
  146. package/docs/vi/benchmark/nextjs.md +6 -3
  147. package/docs/vi/benchmark/solid.md +21 -4
  148. package/docs/vi/benchmark/svelte.md +18 -3
  149. package/docs/vi/benchmark/tanstack.md +6 -3
  150. package/docs/vi/benchmark/vue.md +15 -6
  151. package/docs/vi/cli/index.md +6 -1
  152. package/docs/vi/cli/upgrade.md +125 -0
  153. package/docs/zh/benchmark/nextjs.md +6 -3
  154. package/docs/zh/benchmark/solid.md +21 -4
  155. package/docs/zh/benchmark/svelte.md +18 -3
  156. package/docs/zh/benchmark/tanstack.md +5 -2
  157. package/docs/zh/benchmark/vue.md +15 -6
  158. package/docs/zh/cli/index.md +6 -1
  159. package/docs/zh/cli/upgrade.md +125 -0
  160. package/package.json +6 -6
  161. package/src/generated/blog.entry.ts +20 -0
  162. package/src/generated/docs.entry.ts +20 -0
@@ -0,0 +1,284 @@
1
+ ---
2
+ createdAt: 2026-09-23
3
+ updatedAt: 2026-09-23
4
+ title: هل Intlayer أخف من Paraglide؟
5
+ description: يبدو Paraglide شبه مجاني في اختبارات أداء التدويل (i18n) لأن كوده يتم توليده مباشرة في مستودع مشروعك. نوضح هنا إلى أين يذهب ذلك الحجم فعلياً، ولماذا يكلفك فحص اللغة لكل عقدة أداءً إضافياً، وكيف يشحن التحميل الديناميكي في Intlayer لغة واحدة بدلاً من جميع اللغات.
6
+ keywords:
7
+ - Paraglide
8
+ - Intlayer
9
+ - تدويل
10
+ - i18n
11
+ - Bundle size
12
+ - Tree shaking
13
+ - Benchmark
14
+ - Blog
15
+ slugs:
16
+ - blog
17
+ - is-intlayer-lighter-than-paraglide
18
+ author: aymericzip
19
+ ---
20
+
21
+ # هل Intlayer أخف من Paraglide؟
22
+
23
+ نعم.
24
+
25
+ يحظى `Paraglide` بسمعة جيدة باعتباره أخف حلول التدويل المتاحة، وللوهلة الأولى يتفق [اختبار الأداء](https://intlayer.org/ar/doc/benchmark/tanstack) مع ذلك: فحجم مكتبته يقارب الصفر. لكن حجم مكتبة يقارب الصفر لا يعني إرسال صفر بايت إلى المتصفح. هذا يعني ببساطة أن البايتات تستقر في مكان لا ترصده تلك المعايير.
26
+
27
+ <TOC/>
28
+
29
+ ## النقاط الرئيسية
30
+
31
+ **حجم المكتبة مخفي، وليس محذوفاً:**
32
+
33
+ يولد Paraglide وقت التشغيل (runtime) ودوال الرسائل الخاصة به مباشرة في قاعدة الكود (codebase) لديك. يتم شحن هذا الكود إلى المتصفح، لكنه يُحسب ككود _خاص بك_، وليس ككود للمكتبة.
34
+
35
+ **غياب الـ Provider ليس مكسباً مجانياً:**
36
+
37
+ كل استدعاء للدالة `m.my_key()` يحدد اللغة بنفسه، حيث يقرأ ملف تعريف الارتباط (cookie) أو التخزين المحلي لكل عقدة يتم تصييرها (render)، بدلاً من قراءتها مرة واحدة فقط من السياق (context).
38
+
39
+ **لا يوجد تحميل ديناميكي (Dynamic Loading):**
40
+
41
+ يستورد Paraglide كل لغات الرسالة في حزمة العميل (client bundle). بينما يقوم Intlayer مع خيار `importMode: 'dynamic'` أو `'fetch'` بتحميل اللغة التي يتم عرضها حالياً فقط.
42
+
43
+ **الـ Tree Shaking ليس مضموناً دائماً:**
44
+
45
+ في بعض اختبارات الأداء لدينا، لم تعمل ميزة Tree Shaking المعلن عنها في Paraglide بالشكل المطلوب. نوصي بفحص الحزمة الخاصة بك.
46
+
47
+ ## أين يذهب حجم Paraglide الفعلي؟
48
+
49
+ في تقارير المقارنة المعيارية، يقيس مقياس "حجم المكتبة" الـ provider والـ hooks لكل مكتبة i18n في مكون فارغ، قبل إضافة أي محتوى.
50
+
51
+ | المكتبة (TanStack Start) | حجم المكتبة (gz) | حجم المكتبة (min) |
52
+ | ----------------------------- | ---------------- | ----------------- |
53
+ | `@inlang/paraglide-js@2.15.1` | 1.8 KB | 4.5 KB |
54
+ | `react-intlayer@9.5.1` | 5.0 KB | 15.2 KB |
55
+
56
+ إذا قرأت هذه الأرقام بمعزل عن السياق، يبدو أن Paraglide هو الفائز. لكن Paraglide عبارة عن مترجم (compiler): فهو يقرأ ملفات `messages/*.json` الخاصة بك وينشئ مجلد `paraglide/` داخل مستودع مشروعك، ويحتوي على ملف `runtime.js` (اكتشاف اللغة، استراتيجيات الكوكيز والتخزين، وتوطين الروابط) ودالة جافاسكريبت واحدة لكل رسالة.
57
+
58
+ ```bash
59
+ src/paraglide/
60
+ ├── runtime.js # اكتشاف اللغة، الاستراتيجيات، مساعدات الروابط
61
+ ├── server.js
62
+ ├── messages.js # إعادة تصدير كافة الرسائل
63
+ └── messages/
64
+ ├── _index.js
65
+ ├── en.js
66
+ └── fr.js
67
+ ```
68
+
69
+ نظراً لأن هذا الكود يستقر داخل مجلد `src/` الخاص بك وتقوم باستيراده بمسار نسبي، فإن أداة الحزم (bundler) تنسبه إلى تطبيقك، وليس إلى حزمة خارجية في `node_modules`. لذلك يُظهر عمود حجم المكتبة رقماً يقارب الصفر، في حين أن نفس المنطق البرمجي يُشحن فعلياً ضمن حزمة صفحتك.
70
+
71
+ توليد الكود ليس فكرة سيئة بحد ذاته: فوقت التشغيل المولد لا يتضمن سوى المنطق الذي تتطلبه إعداداتك (استراتيجية البادئة، الكوكيز مقابل التخزين المحلي، إلخ). ويحقق Intlayer نفس النتيجة بأسلوب مختلف، عن طريق حقن متغيرات البيئة أثناء مرحلة البناء، مما يسمح لأداة الحزم بحذف الفروع البرمجية التي لا تستخدمها إعداداتك. كلا الأسلوبين ينتهي بهما الأمر أخف بما يتراوح بين 3 إلى 10 مرات مقارنة بـ `i18next` أو `next-intl`.
72
+
73
+ لذا، فإن المقارنة العادلة ليست حجم المكتبة المجرد. بل هي **كمية الجافاسكريبت المرسلة فعلياً لكل صفحة**.
74
+
75
+ ## وزن الصفحة المقاس فعلياً
76
+
77
+ تطبيق TanStack Start، يتكون من 10 صفحات، تم القياس على مساري `en` و `fr`، بضغط gzip:
78
+
79
+ | الإعداد | متوسط JS للصفحة (gz) | الزيادة عن الأساس | تسريب اللغات | تسريب الصفحات الأخرى |
80
+ | ---------------------------------- | -------------------- | ----------------- | ------------ | -------------------- |
81
+ | الأساس (بدون i18n) | 111.0 KB | - | 0.0% | 0.0% |
82
+ | `paraglide` (أي استراتيجية) | 125.1 KB | +14.1 KB | 49.7% | 0.0% |
83
+ | `intlayer` (`importMode: static`) | 125.8 KB | +14.8 KB | 50.0% | 0.0% |
84
+ | `intlayer` (`importMode: dynamic`) | **118.6 KB** | **+7.6 KB** | **0.0%** | **0.0%** |
85
+
86
+ تطبيق Next.js 16 App Router، نفس التطبيق:
87
+
88
+ | الإعداد | متوسط JS للصفحة (gz) | الزيادة عن الأساس |
89
+ | ------------------ | -------------------- | ----------------- |
90
+ | الأساس (بدون i18n) | 141.0 KB | - |
91
+ | `paraglide-next` | 155.3 KB | +14.3 KB |
92
+ | `next-intlayer` | **141.3 KB** | **+0.3 KB** |
93
+
94
+ <I18nBenchmark framework="tanstack" vertical/>
95
+
96
+ > البيانات الكاملة متوفرة في [تقرير مقارنة TanStack Start](https://intlayer.org/ar/doc/benchmark/tanstack) و[تقرير مقارنة Next.js](https://intlayer.org/ar/doc/benchmark/nextjs). يمكن فحص كل حزمة في [مستودع اختبارات الأداء](https://github.com/intlayer-org/benchmark-i18n).
97
+
98
+ هناك نقطتان واضحتان:
99
+
100
+ - في الوضع الثابت (`static`)، يرسل Intlayer نفس المحتوى تقريباً مقارنة بـ Paraglide (125.8 KB مقابل 125.1 KB). وهذا أمر متوقع: فكلاهما يضم جميع لغات الرسائل التي تستخدمها الصفحة.
101
+ - يظل Paraglide عند 125.1 KB مهما كانت الاستراتيجية المستخدمة، لأنه لا يحتوي على وضع ديناميكي. كل سطر في الجدول أعلاه يمثل النمط الثابت.
102
+
103
+ ## غياب الـ Provider: فكرة تبدو جذابة ولكنها ليست كذلك
104
+
105
+ لا يتطلب Paraglide استخدام Provider. كل ما تفعله هو استيراد الرسالة واستدعاؤها:
106
+
107
+ ```tsx fileName="Hero.tsx"
108
+ import { m } from "../paraglide/messages.js";
109
+
110
+ export const Hero = () => (
111
+ <section>
112
+ <h1>{m.hero_title()}</h1>
113
+ <p>{m.hero_description()}</p>
114
+ <button>{m.hero_cta()}</button>
115
+ </section>
116
+ );
117
+ ```
118
+
119
+ لا سياق، لا غلاف، ولا خطافات (hooks). يبدو الأمر أبسط. لكن اللغة لا تزال بحاجة إلى تحديد مصدرها. تبدو كل دالة رسالة مولدة تقريباً على هذا النحو (بشكل مبسط):
120
+
121
+ ```js fileName="paraglide/messages/_index.js"
122
+ export const hero_title = (inputs = {}, options = {}) => {
123
+ const locale = options.locale ?? getLocale(); // يتم تحديدها عند كل استدعاء
124
+
125
+ if (locale === "en") return en.hero_title(inputs);
126
+ if (locale === "fr") return fr.hero_title(inputs);
127
+ // ...فرع برمجي لكل لغة
128
+ };
129
+ ```
130
+
131
+ وتقوم `getLocale()` بفحص الاستراتيجيات المحددة (الكوكيز، التخزين المحلي، الرابط، اللغة الأساسية) لمعرفة اللغة الحالية. هذا يعني أن كل عقدة نصية تصيّرها (`<>{m.my_key()}</>`) تقوم بتشغيل عملية تحديد لغة مستقلة، بما في ذلك قراءة `document.cookie` في المتصفح. صفحة تحتوي على 200 نص مترجم تقوم بتحديد اللغة 200 مرة في كل عملية تصيير، وتتكرر العملية مع كل إعادة تصيير.
132
+
133
+ في المقابل، فإن المكتبة التي تعتمد على Provider تقرأ اللغة **مرة واحدة فقط**، وتخزنها في سياق (أو signal، أو store)، وتقرأ كل عقدة قيمة مخزنة مسبقاً في الذاكرة. يكلف الـ Provider بضع مئات من البايتات فقط. وتخطي استخدامه يستهلك دورات المعالج مع كل تصيير، وهو ما يتضح جلياً في اختبار الأداء: فأوقات تحميل الصفحة وسرعة تبديل اللغة في Paraglide تتأخر باستمرار مقارنة بـ Intlayer على TanStack Start (22.1 مللي ثانية مقابل 14.6 مللي ثانية في تحميل الصفحة، و 4.3 مللي ثانية مقابل 3.2 مللي ثانية في الاستجابة E2E).
134
+
135
+ ## تجربة المطور (DX)
136
+
137
+ مصدر الحقيقة في Paraglide هو ملفات JSON، لكنك لا تستورد ملف الـ JSON مطلقاً، بل تستورد ملف الـ `.js` المولد:
138
+
139
+ <Tabs defaultTab="intlayer" group="techno">
140
+ <Tab label="Paraglide" value="paraglide">
141
+
142
+ ```json fileName="messages/en.json"
143
+ {
144
+ "hero_title": "Ship your app in every language"
145
+ }
146
+ ```
147
+
148
+ ```json fileName="messages/ar.json"
149
+ {
150
+ "hero_title": "انشر تطبيقك بكل اللغات"
151
+ }
152
+ ```
153
+
154
+ ```tsx fileName="Hero.tsx"
155
+ // لا يوجد هذا الملف إلا بعد أن يعيد المترجم توليده من ملف الـ JSON
156
+ import { m } from "../paraglide/messages.js";
157
+
158
+ export const Hero = () => <h1>{m.hero_title()}</h1>;
159
+ ```
160
+
161
+ </Tab>
162
+ <Tab label="Intlayer" value="intlayer">
163
+
164
+ ```ts fileName="Hero.content.ts"
165
+ import { t, type Dictionary } from "intlayer";
166
+
167
+ export default {
168
+ key: "hero",
169
+ content: {
170
+ title: t({
171
+ ar: "انشر تطبيقك بكل اللغات",
172
+ en: "Ship your app in every language",
173
+ }),
174
+ },
175
+ } satisfies Dictionary;
176
+ ```
177
+
178
+ ```tsx fileName="Hero.tsx"
179
+ import { useIntlayer } from "react-intlayer";
180
+
181
+ export const Hero = () => {
182
+ const { title } = useIntlayer("hero");
183
+
184
+ return <h1>{title}</h1>;
185
+ };
186
+ ```
187
+
188
+ </Tab>
189
+ </Tabs>
190
+
191
+ هذا النمط في العمل له ثمن:
192
+
193
+ - كل تعديل على ملف JSON يتطلب إعادة توليد قبل أن يتم التعرف على الاستيراد أو تتحدث الأنواع (types).
194
+ - مجلد `paraglide/` المولد إما أن يتم إدراجه في git (مما يؤدي لتعارضات دمج في الملفات المولدة مع كل طلب سحب PR يمس النصوص)، أو يتم تجاهله (مما يتطلب خطوة توليد إلزامية قبل كل فحص للأنواع أو اختبار أو مهمة CI).
195
+ - كل نص يتحول إلى استدعاء دالة. وتتحول الثوابت إلى `m.key()` في كل مكان، حتى في الأماكن التي تكفي فيها قيمة ثابتة بسيطة.
196
+
197
+ ## Tree Shaking: افحص الحزمة الخاصة بك
198
+
199
+ الوعد الأساسي لـ Paraglide هو أن الرسائل غير المستخدمة يتم التخلص منها عبر الـ Tree Shaking لأن كل رسالة تصدر كعنصر مستقل. وفي اختبار Svelte + Vite، عملت هذه الميزة كما هو متوقع.
200
+
201
+ لكن في بيئات أخرى، لم يتحقق ذلك. ففي اختبارنا على [Next.js](https://intlayer.org/ar/doc/benchmark/nextjs)، زادت صفحات Paraglide بمقدار 14 KB مقارنة بالتطبيق الأساسي، بينما أضاف `next-intlayer` فقط 0.3 KB. كما أظهرت اختبارات سابقة على TanStack Start تسرب رسائل من صفحات أخرى إلى حزمة المسار الحالي.
202
+
203
+ يعتمد الـ Tree Shaking على أداة الحزم لديك (Turbopack، Rolldown، Rollup)، وعلى طريقة استيراد الرسائل (`import { m }` مقابل `import * as m`)، وعلى تحليل الآثار الجانبية (side-effects). إذا اخترت Paraglide لصغر حجمه، افتح أداة فحص الحزم وتأكد من تحقق ذلك في تطبيقك الفعلي.
204
+
205
+ ## غياب التحميل الديناميكي
206
+
207
+ هذا هو العائق البنيوي الأبرز. لا يمتلك Paraglide وسيلة لتحميل لغة واحدة في كل مرة: فكل دالة رسالة تستورد تنفيذ كل اللغات بشكل ثابت، مما يجعل جميع اللغات تنتهي داخل حزمة العميل الخاصة بك.
208
+
209
+ عند دعم لغتين، يتم هدر نصف بيانات الترجمة المنقولة، وهو ما يطابق نسبة تسريب اللغات المقدرة بـ ~50% أعلاه. ومع 10 لغات، يرتفع الهدر إلى 90%. ومع 30 لغة، يصل إلى 97%.
210
+
211
+ والانتقال إلى التحميل الديناميكي لن يحل المشكلة أيضاً: فمع وجود دالة مستقلة لكل رسالة، فإن تحميل كل دالة بشكل كسول سيعني إطلاق آلاف الطلبات عبر الشبكة.
212
+
213
+ يتيح لك Intlayer حرية الاختيار، سواء على المستوى العام للتطبيق أو لكل قاموس على حدة:
214
+
215
+ ```ts fileName="intlayer.config.ts"
216
+ import { Locales, type IntlayerConfig } from "intlayer";
217
+
218
+ const config: IntlayerConfig = {
219
+ internationalization: {
220
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
221
+ defaultLocale: Locales.ENGLISH,
222
+ },
223
+ dictionary: {
224
+ importMode: "dynamic", // 'static' | 'dynamic' | 'fetch'
225
+ },
226
+ };
227
+
228
+ export default config;
229
+ ```
230
+
231
+ | `importMode` | ما يتم إرساله إلى العميل | مقارنة بـ Paraglide |
232
+ | ------------ | --------------------------------------------------- | ------------------------------ |
233
+ | `static` | جميع لغات القواميس التي تستخدمها الصفحة | نفس المحتوى نظرياً |
234
+ | `dynamic` | اللغة الحالية فقط، محملة بكسل لكل قاموس | **أخف بـ N مرة** مع وجود N لغة |
235
+ | `fetch` | اللغة الحالية فقط، مجلوبة عبر واجهة برمجة Live Sync | **أخف بـ N مرة** مع وجود N لغة |
236
+
237
+ بفضل [التحويل أثناء البناء](https://intlayer.org/ar/doc/concept/bundle-optimization) وخيار `importMode: 'static'`، يحمّل Intlayer نظرياً نفس المحتوى تماماً مثل Paraglide. ومع استخدام `'dynamic'` أو `'fetch'`، فإنه يحمّل فقط ما تتطلبه اللغة الحالية: لتطبيق يدعم N لغة، تصبح حمولة الترجمة أصغر بـ N مرة مقارنة بـ Paraglide.
238
+
239
+ ## متى يظل Paraglide خياراً مناسباً؟
240
+
241
+ <AccordionGroup>
242
+ <Accordion header="تطبيقات Svelte + Vite مع عدد قليل من اللغات">
243
+
244
+ إذا كانت بيئة تطويرك تعتمد على Svelte مع Vite وتدعم لغتين أو ثلاث، فإن الـ Tree Shaking يعمل كما ينبغي ويبقى العبء الإضافي للغات محدوداً.
245
+
246
+ </Accordion>
247
+ <Accordion header="سير العمل القائم حالياً على inlang">
248
+
249
+ إذا كان فريقك يستخدم بالفعل منظومة inlang (مثل Fink و Sherlock وإضافات صيغ الرسائل)، فإن Paraglide يتكامل معها بشكل أصيل وسلس.
250
+
251
+ </Accordion>
252
+ </AccordionGroup>
253
+
254
+ ## جربه على تطبيقك
255
+
256
+ تحقق من حجم تطبيقك الحي ومستوى تسريب اللغات باستخدام أداة [i18n SEO Scanner](https://intlayer.org/i18n-seo-scanner) المجانية:
257
+
258
+ <ClickToOpenIframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
259
+
260
+ لتثبيت Intlayer:
261
+
262
+ ```bash packageManager="npm"
263
+ npx intlayer init --interactive
264
+ ```
265
+
266
+ ```bash packageManager="pnpm"
267
+ pnpm dlx intlayer init --interactive
268
+ ```
269
+
270
+ ```bash packageManager="yarn"
271
+ yarn dlx intlayer init --interactive
272
+ ```
273
+
274
+ ```bash packageManager="bun"
275
+ bunx intlayer init --interactive
276
+ ```
277
+
278
+ ## قراءات إضافية
279
+
280
+ - [اختبار أداء i18n في TanStack Start](https://intlayer.org/ar/doc/benchmark/tanstack)
281
+ - [اختبار أداء i18n في Next.js](https://intlayer.org/ar/doc/benchmark/nextjs)
282
+ - [تحسين الحزم و `importMode`](https://intlayer.org/ar/doc/concept/bundle-optimization)
283
+ - [كيفية اختيار مكتبة i18n المناسبة لـ React](https://intlayer.org/ar/blog/how-to-pick-react-i18n-library)
284
+ - [دواعي ومبررات التدويل المعتمد على المترجم](https://intlayer.org/ar/blog/compiler-vs-declarative-i18n)
@@ -0,0 +1,284 @@
1
+ ---
2
+ createdAt: 2026-09-23
3
+ updatedAt: 2026-09-23
4
+ title: Ist Intlayer leichter als Paraglide?
5
+ description: Paraglide wirkt in i18n-Benchmarks nahezu kostenlos, da der Code direkt in Ihr Repository generiert wird. Hier erfahren Sie, wo dieses Gewicht wirklich landet, warum Locale-Abfragen pro Knoten Leistung kosten und wie Intlayers dynamisches Laden nur eine einzige Locale statt aller ausliefert.
6
+ keywords:
7
+ - Paraglide
8
+ - Intlayer
9
+ - Internationalisierung
10
+ - i18n
11
+ - Bundle size
12
+ - Tree shaking
13
+ - Benchmark
14
+ - Blog
15
+ slugs:
16
+ - blog
17
+ - is-intlayer-lighter-than-paraglide
18
+ author: aymericzip
19
+ ---
20
+
21
+ # Ist Intlayer leichter als Paraglide?
22
+
23
+ Ja.
24
+
25
+ `Paraglide` genießt den Ruf, die leichteste i18n-Lösung auf dem Markt zu sein, und auf den ersten Blick bestätigt der [Benchmark](https://intlayer.org/de/doc/benchmark/tanstack) diesen Eindruck: Die Bibliotheksgröße liegt nahe bei null. Doch eine Bibliotheksgröße von null bedeutet keineswegs null ausgelieferte Bytes. Es bedeutet lediglich, dass die Bytes an einer Stelle liegen, die diese Metrik nicht erfasst.
26
+
27
+ <TOC/>
28
+
29
+ ## Wichtigste Erkenntnisse
30
+
31
+ **Die Bibliotheksgröße ist versteckt, nicht verschwunden:**
32
+
33
+ Paraglide generiert seine Runtime und Nachrichtenfunktionen direkt in Ihre Codebase. Dieser Code wird an den Browser ausgeliefert, wird aber als _Ihr_ Code gewertet und nicht als der Code der Bibliothek.
34
+
35
+ **Kein Provider bedeutet keinen kostenlosen Gewinn:**
36
+
37
+ Jeder Aufruf von `m.my_key()` ermittelt die Locale eigenständig und liest bei jedem gerenderten Knoten das Cookie oder den Storage aus, anstatt den Wert einmalig aus einem Kontext zu beziehen.
38
+
39
+ **Kein dynamisches Laden:**
40
+
41
+ Paraglide importiert jede Locale einer Nachricht in Ihr Client-Bundle. Intlayer mit `importMode: 'dynamic'` oder `'fetch'` lädt ausschließlich die Locale, die gerade gerendert wird.
42
+
43
+ **Tree Shaking ist nicht garantiert:**
44
+
45
+ In einigen unserer Benchmarks griff das von Paraglide beworbene Tree Shaking nicht. Prüfen Sie Ihr eigenes Bundle.
46
+
47
+ ## Wo landet das Gewicht von Paraglide?
48
+
49
+ In den Benchmark-Berichten misst die Metrik „Bibliotheksgröße“ den Provider und die Hooks jeder i18n-Bibliothek in einer leeren Komponente, bevor Inhalte hinzugefügt werden.
50
+
51
+ | Bibliothek (TanStack Start) | Lib-Größe (gz) | Lib-Größe (min) |
52
+ | ----------------------------- | -------------- | --------------- |
53
+ | `@inlang/paraglide-js@2.15.1` | 1.8 KB | 4.5 KB |
54
+ | `react-intlayer@9.5.1` | 5.0 KB | 15.2 KB |
55
+
56
+ Isoliert betrachtet gewinnt Paraglide. Aber Paraglide ist ein Compiler: Es liest Ihre `messages/*.json`-Dateien und schreibt einen `paraglide/`-Ordner in Ihr Repository, der eine `runtime.js` (Locale-Erkennung, Cookie- und Storage-Strategien, URL-Lokalisierung) sowie eine JavaScript-Funktion pro Nachricht enthält.
57
+
58
+ ```bash
59
+ src/paraglide/
60
+ ├── runtime.js # Locale-Erkennung, Strategien, URL-Hilfsfunktionen
61
+ ├── server.js
62
+ ├── messages.js # Reexportiert alle Nachrichten
63
+ └── messages/
64
+ ├── _index.js
65
+ ├── en.js
66
+ └── fr.js
67
+ ```
68
+
69
+ Da dieser Code in Ihrem `src/`-Ordner liegt und mit einem relativen Pfad importiert wird, rechnet der Bundler ihn Ihrer Anwendung zu und nicht einem Paket in `node_modules`. Die Spalte für die Bibliotheksgröße zeigt fast nichts an, während dieselbe Logik weiterhin im Bundle Ihrer Seite ausgeliefert wird.
70
+
71
+ Code zu generieren ist an sich keine schlechte Idee: Die generierte Runtime enthält nur die Logik, die Ihre Konfiguration tatsächlich benötigt (Präfix-Strategie, Cookie vs. Local Storage usw.). Intlayer erreicht dasselbe Ergebnis auf andere Weise, indem zur Build-Zeit Umgebungsvariablen injiziert werden, sodass der Bundler Zweige entfernt, die Ihre Konfiguration nicht nutzt. Beide Ansätze sind letztlich 3- bis 10-mal leichter als `i18next` oder `next-intl`.
72
+
73
+ Der faire Vergleich ist daher nicht die Bibliotheksgröße. Es ist **das tatsächlich pro Seite übertragene JavaScript**.
74
+
75
+ ## Gemessenes Seitengewicht
76
+
77
+ TanStack Start App, 10 Seiten, gemessen auf den Routen `en` und `fr`, gzippt:
78
+
79
+ | Setup | Seiten-JS Ø (gz) | Über Basis | Locale-Leak | Leak anderer Seiten |
80
+ | ---------------------------------- | ---------------- | ----------- | ----------- | ------------------- |
81
+ | Basis (ohne i18n) | 111.0 KB | - | 0.0% | 0.0% |
82
+ | `paraglide` (jede Strategie) | 125.1 KB | +14.1 KB | 49.7% | 0.0% |
83
+ | `intlayer` (`importMode: static`) | 125.8 KB | +14.8 KB | 50.0% | 0.0% |
84
+ | `intlayer` (`importMode: dynamic`) | **118.6 KB** | **+7.6 KB** | **0.0%** | **0.0%** |
85
+
86
+ Next.js 16 App Router, dieselbe Anwendung:
87
+
88
+ | Setup | Seiten-JS Ø (gz) | Über Basis |
89
+ | ----------------- | ---------------- | ----------- |
90
+ | Basis (ohne i18n) | 141.0 KB | - |
91
+ | `paraglide-next` | 155.3 KB | +14.3 KB |
92
+ | `next-intlayer` | **141.3 KB** | **+0.3 KB** |
93
+
94
+ <I18nBenchmark framework="tanstack" vertical/>
95
+
96
+ > Vollständige Daten im [TanStack Start Benchmark-Bericht](https://intlayer.org/de/doc/benchmark/tanstack) und im [Next.js Benchmark-Bericht](https://intlayer.org/de/doc/benchmark/nextjs). Jedes Bundle kann im [Benchmark-Repository](https://github.com/intlayer-org/benchmark-i18n) eingesehen werden.
97
+
98
+ Zwei Aspekte stechen hervor:
99
+
100
+ - Im `static`-Modus liefert Intlayer praktisch denselben Inhalt wie Paraglide aus (125.8 KB vs. 125.1 KB). Das ist zu erwarten: Beide enthalten jede Locale der Nachrichten, die eine Seite verwendet.
101
+ - Paraglide verharrt unabhängig von der Strategie bei 125.1 KB, da es keinen dynamischen Modus bietet. Jede Zeile in der obigen Tabelle entspricht der statischen Variante.
102
+
103
+ ## Kein Provider: Eine vermeintlich gute Idee
104
+
105
+ Paraglide kommt ohne Provider aus. Sie importieren eine Nachricht und rufen sie direkt auf:
106
+
107
+ ```tsx fileName="Hero.tsx"
108
+ import { m } from "../paraglide/messages.js";
109
+
110
+ export const Hero = () => (
111
+ <section>
112
+ <h1>{m.hero_title()}</h1>
113
+ <p>{m.hero_description()}</p>
114
+ <button>{m.hero_cta()}</button>
115
+ </section>
116
+ );
117
+ ```
118
+
119
+ Kein Kontext, kein Wrapper, kein Hook. Das wirkt unkompliziert. Doch die Locale muss dennoch ermittelt werden. Jede generierte Nachrichtenfunktion sieht vereinfacht etwa so aus:
120
+
121
+ ```js fileName="paraglide/messages/_index.js"
122
+ export const hero_title = (inputs = {}, options = {}) => {
123
+ const locale = options.locale ?? getLocale(); // wird bei jedem Aufruf ermittelt
124
+
125
+ if (locale === "en") return en.hero_title(inputs);
126
+ if (locale === "fr") return fr.hero_title(inputs);
127
+ // ...ein Zweig pro Locale
128
+ };
129
+ ```
130
+
131
+ Und `getLocale()` durchläuft die konfigurierten Strategien (Cookie, Local Storage, URL, Basis-Locale), um die aktuelle Locale zu bestimmen. Jeder gerenderte Textknoten (`<>{m.my_key()}</>`) führt also seine eigene Locale-Auflösung aus, einschließlich des Auslesens von `document.cookie` im Browser. Eine Seite mit 200 übersetzten Zeichenfolgen ermittelt die Locale 200 Mal pro Rendervorgang und erneut bei jedem Re-Render.
132
+
133
+ Eine providerbasierte Bibliothek liest die Locale **ein einziges Mal** aus, speichert sie in einem Kontext (oder Signal bzw. Store), und jeder Knoten liest einen bereits im Speicher vorhandenen Wert. Der Provider kostet wenige hundert Bytes. Ihn wegzulassen kostet CPU-Leistung bei jedem Render. Das spiegelt sich im Benchmark wider: Paraglides Seitenlade- und Sprachwechselzeiten liegen auf TanStack Start durchweg hinter Intlayer (22.1 ms vs. 14.6 ms beim Seitenaufbau, 4.3 ms vs. 3.2 ms bei der E2E-Reaktivität).
134
+
135
+ ## Entwicklererlebnis (DX)
136
+
137
+ Die Source of Truth von Paraglide ist JSON, aber Sie importieren die JSON-Dateien nie direkt. Stattdessen importieren Sie die generierte `.js`-Datei:
138
+
139
+ <Tabs defaultTab="intlayer" group="techno">
140
+ <Tab label="Paraglide" value="paraglide">
141
+
142
+ ```json fileName="messages/en.json"
143
+ {
144
+ "hero_title": "Ship your app in every language"
145
+ }
146
+ ```
147
+
148
+ ```json fileName="messages/de.json"
149
+ {
150
+ "hero_title": "Veröffentlichen Sie Ihre App in jeder Sprache"
151
+ }
152
+ ```
153
+
154
+ ```tsx fileName="Hero.tsx"
155
+ // Existiert erst, nachdem der Compiler die Datei aus dem JSON neu generiert hat
156
+ import { m } from "../paraglide/messages.js";
157
+
158
+ export const Hero = () => <h1>{m.hero_title()}</h1>;
159
+ ```
160
+
161
+ </Tab>
162
+ <Tab label="Intlayer" value="intlayer">
163
+
164
+ ```ts fileName="Hero.content.ts"
165
+ import { t, type Dictionary } from "intlayer";
166
+
167
+ export default {
168
+ key: "hero",
169
+ content: {
170
+ title: t({
171
+ de: "Veröffentlichen Sie Ihre App in jeder Sprache",
172
+ en: "Ship your app in every language",
173
+ }),
174
+ },
175
+ } satisfies Dictionary;
176
+ ```
177
+
178
+ ```tsx fileName="Hero.tsx"
179
+ import { useIntlayer } from "react-intlayer";
180
+
181
+ export const Hero = () => {
182
+ const { title } = useIntlayer("hero");
183
+
184
+ return <h1>{title}</h1>;
185
+ };
186
+ ```
187
+
188
+ </Tab>
189
+ </Tabs>
190
+
191
+ Dieser Workflow bringt Nachteile mit sich:
192
+
193
+ - Jede Änderung an einer JSON-Datei erfordert eine Neugenerierung, bevor der Import aufgelöst werden kann oder Typen aktualisiert werden.
194
+ - Der generierte `paraglide/`-Ordner wird entweder committed (was Merge-Konflikte in generierten Dateien bei jedem Text-PR bedeutet) oder ignoriert (was einen Generierungsschritt vor jedem Type-Check, Test und CI-Job erfordert).
195
+ - Jede Zeichenkette wird zu einem Funktionsaufruf. Konstanten werden überall zu `m.key()`, selbst an Stellen, an denen ein einfacher Wert genügen würde.
196
+
197
+ ## Tree Shaking: Überprüfen Sie Ihr Bundle
198
+
199
+ Paraglides zentrales Versprechen lautet, dass ungenutzte Nachrichten per Tree Shaking entfernt werden, da jede Nachricht ein eigener Export ist. Im Benchmark mit Svelte + Vite funktioniert das wie beworben.
200
+
201
+ In anderen Konfigurationen funktionierte es nicht. In unserem [Next.js](https://intlayer.org/de/doc/benchmark/nextjs)-Lauf wiegen Paraglides Seiten 14 KB mehr als die Basisanwendung, während `next-intlayer` lediglich 0.3 KB hinzufügt. Frühere Durchläufe auf TanStack Start zeigten zudem, dass Nachrichten anderer Seiten im Bundle der Route landeten.
202
+
203
+ Tree Shaking hängt von Ihrem Bundler (Turbopack, Rolldown, Rollup), der Import-Syntax (`import { m }` vs. `import * as m`) und der Side-Effect-Analyse ab. Wenn Sie Paraglide wegen seiner Größe wählen, öffnen Sie Ihren Bundle-Visualizer und überprüfen Sie, ob das Versprechen in Ihrer Anwendung greift.
204
+
205
+ ## Kein dynamisches Laden
206
+
207
+ Hier liegt die strukturelle Grenze. Paraglide bietet keine Möglichkeit, nur eine Locale auf einmal zu laden: Jede Nachrichtenfunktion importiert statisch die Implementierung jeder Sprache, sodass alle Sprachen im Client-Bundle landen.
208
+
209
+ Bei 2 Sprachen wird die Hälfte der Übersetzungsdaten verschwendet, was den oben gemessenen ~50% Locale-Leak entspricht. Bei 10 Sprachen sind es 90%. Bei 30 Sprachen 97%.
210
+
211
+ Der Wechsel zu dynamischem Laden würde das Problem nicht beheben: Bei einer Funktion pro Nachricht würde das verzögerte Laden jeder einzelnen Funktion tausende Anfragen bedeuten.
212
+
213
+ Intlayer lässt Ihnen die Wahl, global oder pro Wörterbuch:
214
+
215
+ ```ts fileName="intlayer.config.ts"
216
+ import { Locales, type IntlayerConfig } from "intlayer";
217
+
218
+ const config: IntlayerConfig = {
219
+ internationalization: {
220
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
221
+ defaultLocale: Locales.ENGLISH,
222
+ },
223
+ dictionary: {
224
+ importMode: "dynamic", // 'static' | 'dynamic' | 'fetch'
225
+ },
226
+ };
227
+
228
+ export default config;
229
+ ```
230
+
231
+ | `importMode` | Was an den Client ausgeliefert wird | vs. Paraglide |
232
+ | ------------ | ------------------------------------------------------- | ------------------------------- |
233
+ | `static` | Alle Locales der Wörterbücher, die die Seite verwendet | Theoretisch derselbe Inhalt |
234
+ | `dynamic` | Nur die aktuelle Locale, Lazy-Loading pro Wörterbuch | **N-mal kleiner** bei N Locales |
235
+ | `fetch` | Nur die aktuelle Locale, bezogen über die Live Sync API | **N-mal kleiner** bei N Locales |
236
+
237
+ Mit der [Build-Transformation](https://intlayer.org/de/doc/concept/bundle-optimization) und `importMode: 'static'` lädt Intlayer in der Theorie exakt denselben Inhalt wie Paraglide. Mit `'dynamic'` oder `'fetch'` lädt es nur das, was die aktuelle Locale benötigt: Bei einer App in N Sprachen ist die Übersetzungs-Nutzlast um den Faktor N kleiner als bei Paraglide.
238
+
239
+ ## Wann Paraglide weiterhin passt
240
+
241
+ <AccordionGroup>
242
+ <Accordion header="Svelte + Vite mit wenigen Locales">
243
+
244
+ Wenn Ihr Stack auf Svelte mit Vite basiert und Sie zwei oder drei Sprachen unterstützen, funktioniert Tree Shaking wie beworben und der Overhead durch zusätzliche Sprachen bleibt gering.
245
+
246
+ </Accordion>
247
+ <Accordion header="Bestehender inlang-Workflow">
248
+
249
+ Wenn Ihr Team bereits das inlang-Ökosystem nutzt (Fink, Sherlock, Message-Format-Plugins), lässt sich Paraglide nahtlos integrieren.
250
+
251
+ </Accordion>
252
+ </AccordionGroup>
253
+
254
+ ## Testen Sie es in Ihrer Anwendung
255
+
256
+ Prüfen Sie Bundle-Größe und Locale-Leaks Ihrer Live-Anwendung mit dem kostenlosen [i18n SEO Scanner](https://intlayer.org/i18n-seo-scanner):
257
+
258
+ <ClickToOpenIframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
259
+
260
+ So richten Sie Intlayer ein:
261
+
262
+ ```bash packageManager="npm"
263
+ npx intlayer init --interactive
264
+ ```
265
+
266
+ ```bash packageManager="pnpm"
267
+ pnpm dlx intlayer init --interactive
268
+ ```
269
+
270
+ ```bash packageManager="yarn"
271
+ yarn dlx intlayer init --interactive
272
+ ```
273
+
274
+ ```bash packageManager="bun"
275
+ bunx intlayer init --interactive
276
+ ```
277
+
278
+ ## Weiterführende Literatur
279
+
280
+ - [TanStack Start i18n Benchmark](https://intlayer.org/de/doc/benchmark/tanstack)
281
+ - [Next.js i18n Benchmark](https://intlayer.org/de/doc/benchmark/nextjs)
282
+ - [Bundle-Optimierung und `importMode`](https://intlayer.org/de/doc/concept/bundle-optimization)
283
+ - [So wählen Sie eine React i18n-Bibliothek aus](https://intlayer.org/de/blog/how-to-pick-react-i18n-library)
284
+ - [Plädoyer für compilergestützte Internationalisierung](https://intlayer.org/de/blog/compiler-vs-declarative-i18n)