@intlayer/docs 7.3.3 → 7.3.4
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.
- package/blog/ar/compiler_vs_declarative_i18n.md +137 -54
- package/blog/de/compiler_vs_declarative_i18n.md +131 -48
- package/blog/en/compiler_vs_declarative_i18n.md +112 -27
- package/blog/en-GB/compiler_vs_declarative_i18n.md +110 -27
- package/blog/es/compiler_vs_declarative_i18n.md +128 -45
- package/blog/fr/compiler_vs_declarative_i18n.md +133 -50
- package/blog/hi/compiler_vs_declarative_i18n.md +136 -53
- package/blog/id/compiler_vs_declarative_i18n.md +124 -41
- package/blog/it/compiler_vs_declarative_i18n.md +130 -47
- package/blog/ja/compiler_vs_declarative_i18n.md +140 -57
- package/blog/ko/compiler_vs_declarative_i18n.md +134 -51
- package/blog/pl/compiler_vs_declarative_i18n.md +134 -51
- package/blog/pt/compiler_vs_declarative_i18n.md +128 -45
- package/blog/ru/compiler_vs_declarative_i18n.md +135 -52
- package/blog/tr/compiler_vs_declarative_i18n.md +131 -48
- package/blog/vi/compiler_vs_declarative_i18n.md +136 -53
- package/blog/zh/compiler_vs_declarative_i18n.md +132 -49
- package/docs/en/interest_of_intlayer.md +4 -0
- package/docs/en/per_locale_file.md +98 -77
- package/package.json +6 -6
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-11-24
|
|
3
3
|
updatedAt: 2025-11-24
|
|
4
|
-
title: المترجم مقابل التدوين التصريحي
|
|
5
|
-
description: استكشاف
|
|
4
|
+
title: المترجم مقابل التدوين التصريحي للتدويل
|
|
5
|
+
description: استكشاف التنازلات المعمارية بين التدويل "السحري" المعتمد على المترجم وإدارة المحتوى التصريحية الصريحة.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- التدويل
|
|
@@ -12,7 +12,7 @@ keywords:
|
|
|
12
12
|
- React
|
|
13
13
|
- i18n
|
|
14
14
|
- المترجم
|
|
15
|
-
-
|
|
15
|
+
- تصريحي
|
|
16
16
|
slugs:
|
|
17
17
|
- blog
|
|
18
18
|
- compiler-vs-declarative-i18n
|
|
@@ -20,118 +20,201 @@ slugs:
|
|
|
20
20
|
|
|
21
21
|
# الحجج المؤيدة والمعارضة للتدويل المعتمد على المترجم
|
|
22
22
|
|
|
23
|
-
إذا كنت تبني تطبيقات ويب لأكثر من عقد من الزمن، فأنت تعلم أن التدويل (i18n) كان دائمًا نقطة احتكاك. غالبًا ما تكون مهمة لا يرغب أحد في القيام بها
|
|
23
|
+
إذا كنت تبني تطبيقات ويب لأكثر من عقد من الزمن، فأنت تعلم أن التدويل (i18n) كان دائمًا نقطة احتكاك. غالبًا ما تكون مهمة لا يرغب أحد في القيام بها - استخراج النصوص، إدارة ملفات JSON، والقلق بشأن قواعد الجمع.
|
|
24
24
|
|
|
25
|
-
مؤخرًا، ظهرت موجة جديدة من أدوات التدويل
|
|
25
|
+
مؤخرًا، ظهرت موجة جديدة من أدوات التدويل **المعتمدة على المترجم**، والتي تعد بجعل هذه المعاناة تختفي. العرض مغرٍ: **فقط اكتب النصوص في مكوناتك، ودع أداة البناء تتولى الباقي.** لا مفاتيح، لا استيرادات، فقط سحر.
|
|
26
26
|
|
|
27
27
|
ولكن كما هو الحال مع جميع التجريدات في هندسة البرمجيات، يأتي السحر بثمن.
|
|
28
28
|
|
|
29
|
-
في هذه التدوينة، سوف نستكشف التحول من المكتبات التصريحية إلى النهج المعتمد على المترجم، والديون المعمارية الخفية التي يقدمونها، ولماذا قد
|
|
29
|
+
في هذه التدوينة، سوف نستكشف التحول من المكتبات التصريحية إلى النهج المعتمد على المترجم، والديون المعمارية الخفية التي يقدمونها، ولماذا قد تظل الطريقة "المملة" هي الأفضل للتطبيقات المهنية.
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## جدول المحتويات
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
<TOC/>
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
## لمحة تاريخية عن التدويل
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
لفهم مكاننا الحالي، يجب أن ننظر إلى الوراء حيث بدأنا.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
في الفترة ما بين 2011 و2012، كان مشهد جافا سكريبت مختلفًا تمامًا. لم تكن أدوات التجميع كما نعرفها اليوم (Webpack، Vite) موجودة أو كانت في مراحلها الأولى. كنا نلصق السكريبتات معًا في المتصفح. في هذه الحقبة، وُلدت مكتبات مثل **i18next**.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
لقد حلت المشكلة بالطريقة الوحيدة الممكنة في ذلك الوقت: **القواميس أثناء وقت التشغيل**. كنت تقوم بتحميل كائن JSON ضخم في الذاكرة، وكانت دالة تبحث عن المفاتيح أثناء التنفيذ. كانت طريقة موثوقة وصريحة وتعمل في كل مكان.
|
|
42
|
+
|
|
43
|
+
تقدم سريعًا إلى اليوم. لدينا مترجمات قوية (SWC، أدوات تجميع مبنية على Rust) يمكنها تحليل أشجار البنية المجردة (AST) في غضون ميلي ثانية. هذه القوة ولدت فكرة جديدة: _لماذا ندير المفاتيح يدويًا؟ لماذا لا يستطيع المترجم فقط رؤية النص "Hello World" واستبداله لنا؟_
|
|
44
|
+
|
|
45
|
+
وهكذا وُلد التدويل المعتمد على المترجم.
|
|
46
|
+
|
|
47
|
+
> **مثال على التدويل المعتمد على المترجم:**
|
|
48
|
+
>
|
|
49
|
+
> - Paraglide (وحدات تم تقليلها باستخدام tree-shaking تقوم بترجمة كل رسالة إلى دالة ESM صغيرة بحيث يمكن لأدوات التجميع حذف اللغات والمفاتيح غير المستخدمة تلقائيًا. تقوم باستيراد الرسائل كدوال بدلاً من البحث عن المفاتيح كنصوص.)
|
|
50
|
+
> - LinguiJS (مترجم من الماكرو إلى الدالة يعيد كتابة ماكرو الرسائل مثل `<Trans>` إلى استدعاءات دوال جافاسكريبت عادية أثناء وقت البناء. تحصل على صيغة ICU/MessageFormat مع بصمة تشغيل صغيرة جدًا.)
|
|
51
|
+
> - Lingo.dev (يركز على أتمتة خط أنابيب التوطين عن طريق حقن المحتوى المترجم مباشرة أثناء بناء تطبيق React الخاص بك. يمكنه توليد الترجمات تلقائيًا باستخدام الذكاء الاصطناعي والتكامل مباشرة في CI/CD.)
|
|
52
|
+
> - Wuchale (معالج مسبق يركز على Svelte يقوم باستخراج النصوص المضمنة في ملفات .svelte ويحولها إلى دوال ترجمة بدون تغليف. يتجنب استخدام مفاتيح نصية، ويفصل منطق استخراج المحتوى تمامًا عن وقت تشغيل التطبيق الرئيسي.)
|
|
53
|
+
> - Intlayer (مترجم / أداة CLI للاستخراج تقوم بتحليل مكوناتك، وتوليد قواميس ذات أنواع، ويمكنها اختياريًا إعادة كتابة الكود لاستخدام محتوى Intlayer صريح. الهدف هو استخدام المترجم للسرعة مع الحفاظ على جوهر إعلاني مستقل عن الإطار.)
|
|
54
|
+
|
|
55
|
+
> **مثال على التوطين الإعلاني:**
|
|
56
|
+
>
|
|
57
|
+
> - i18next / react-i18next / next-i18next (المعيار الصناعي الناضج الذي يستخدم قواميس JSON وقت التشغيل ونظام إضافات واسع)
|
|
58
|
+
> - react-intl (جزء من مكتبة FormatJS، يركز على صياغة رسائل ICU القياسية وتنسيق البيانات الصارم)
|
|
59
|
+
> - next-intl (محسّن خصيصًا لـ Next.js مع تكامل مع App Router ومكونات React Server)
|
|
60
|
+
> - vue-i18n / @nuxt/i18n (الحل القياسي في نظام Vue البيئي الذي يقدم كتل ترجمة على مستوى المكونات وتكامل تفاعلي محكم)
|
|
61
|
+
> - svelte-i18n (غلاف خفيف حول مخازن Svelte للترجمات التفاعلية وقت التشغيل)
|
|
62
|
+
> - angular-translate (مكتبة الترجمة الديناميكية القديمة التي تعتمد على البحث عن المفاتيح وقت التشغيل بدلاً من الدمج أثناء البناء)
|
|
63
|
+
> - angular-i18n (النهج الأصلي لـ Angular المسبق للوقت الذي يدمج ملفات XLIFF مباشرة في القوالب أثناء البناء)
|
|
64
|
+
> - Tolgee (يجمع بين الكود التصريحي وSDK ضمن السياق لتحرير "انقر للترجمة" مباشرة في واجهة المستخدم)
|
|
65
|
+
> - Intlayer (نهج لكل مكون، يستخدم ملفات إعلانات المحتوى التي تمكّن من tree-shaking أصلي والتحقق من TypeScript)
|
|
66
|
+
|
|
67
|
+
## مترجم Intlayer
|
|
68
|
+
|
|
69
|
+
على الرغم من أن **Intlayer** هو حل يشجع أساسًا على **النهج التصريحي** لمحتواك، إلا أنه يتضمن مترجمًا للمساعدة في تسريع التطوير أو تسهيل النماذج الأولية السريعة.
|
|
70
|
+
|
|
71
|
+
يقوم مترجم Intlayer بتصفح شجرة البنية المجردة (AST) لمكونات React أو Vue أو Svelte الخاصة بك، بالإضافة إلى ملفات JavaScript/TypeScript الأخرى. دوره هو اكتشاف السلاسل النصية المضمنة واستخراجها إلى إعلانات `.content` مخصصة.
|
|
72
|
+
|
|
73
|
+
> لمزيد من التفاصيل، اطلع على الوثائق: [وثائق مترجم Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/compiler.md)
|
|
42
74
|
|
|
43
75
|
## جاذبية المترجم (النهج "السحري")
|
|
44
76
|
|
|
45
|
-
هناك سبب يجعل هذا النهج الجديد شائعًا. بالنسبة للمطور،
|
|
77
|
+
هناك سبب يجعل هذا النهج الجديد شائعًا. بالنسبة للمطور، التجربة مذهلة.
|
|
46
78
|
|
|
47
79
|
### 1. السرعة و"التدفق"
|
|
48
80
|
|
|
49
|
-
عندما تكون في حالة تركيز، التوقف للتفكير في اسم متغير (`home_hero_title_v2`) يكسر تدفقك. مع نهج المترجم، تكتب `<p>Welcome back</p>`
|
|
81
|
+
عندما تكون في حالة تركيز، التوقف للتفكير في اسم متغير دلالي (`home_hero_title_v2`) يكسر تدفقك. مع نهج المترجم، تكتب `<p>Welcome back</p>` وتستمر في العمل. الاحتكاك معدوم.
|
|
50
82
|
|
|
51
83
|
### 2. مهمة إنقاذ التراث
|
|
52
84
|
|
|
53
|
-
تخيل أنك ترث قاعدة كود ضخمة تحتوي على 5000 مكون وبدون أي ترجمات.
|
|
85
|
+
تخيل أنك ترث قاعدة كود ضخمة تحتوي على 5000 مكون وبدون أي ترجمات. إعادة تجهيز هذا النظام باستخدام نظام مفاتيح يدوي هو كابوس يستمر لأشهر. أداة تعتمد على المترجم تعمل كاستراتيجية إنقاذ، حيث تستخرج آلاف السلاسل النصية فورًا دون الحاجة إلى لمس أي ملف يدويًا.
|
|
54
86
|
|
|
55
87
|
### 3. عصر الذكاء الاصطناعي
|
|
56
88
|
|
|
57
|
-
هذه
|
|
89
|
+
هذه ميزة حديثة لا ينبغي تجاهلها. مساعدو البرمجة بالذكاء الاصطناعي (مثل Copilot أو ChatGPT) يولدون بشكل طبيعي JSX/HTML قياسي. هم لا يعرفون مخطط مفاتيح الترجمة الخاص بك.
|
|
58
90
|
|
|
59
91
|
- **إعلاني:** عليك إعادة كتابة مخرجات الذكاء الاصطناعي لاستبدال النص بالمفاتيح.
|
|
60
92
|
- **المترجم:** تقوم بنسخ ولصق كود الذكاء الاصطناعي، ويعمل مباشرة.
|
|
61
93
|
|
|
62
|
-
##
|
|
94
|
+
## التحقق من الواقع: لماذا "السحر" خطير
|
|
95
|
+
|
|
96
|
+
بينما تبدو "السحرية" جذابة، إلا أن التجريد يتسرب. الاعتماد على أداة بناء لفهم نية الإنسان يُدخل هشاشة معمارية.
|
|
97
|
+
|
|
98
|
+
### هشاشة الاستدلال (لعبة التخمين)
|
|
99
|
+
|
|
100
|
+
يجب على المترجم أن يخمن ما هو المحتوى وما هو الكود. هذا يؤدي إلى حالات حافة حيث ينتهي بك الأمر إلى "مقاتلة" الأداة.
|
|
101
|
+
|
|
102
|
+
ضع في اعتبارك هذه السيناريوهات:
|
|
103
|
+
|
|
104
|
+
- هل يتم استخراج `<span className="active"></span>`؟ (إنها سلسلة نصية، لكنها على الأرجح فئة).
|
|
105
|
+
- هل يتم استخراج `<span status="pending"></span>`؟ (إنها قيمة خاصية).
|
|
106
|
+
- هل يتم استخراج `<span>{"Hello World"}</span>`؟ (إنها تعبير جافاسكريبت).
|
|
107
|
+
- هل يتم استخراج `<span>Hello {name}. How are you?</span>`؟ (التضمين معقد).
|
|
108
|
+
- هل يتم استخراج `<span aria-label="Image of cat"></span>`؟ (سمات الوصول تحتاج إلى ترجمة).
|
|
109
|
+
- هل يتم استخراج `<span data-testid="my-element"></span>`؟ (يجب عدم ترجمة معرفات الاختبار).
|
|
110
|
+
- هل يتم استخراج `<MyComponent errorMessage="An error occurred" />`؟
|
|
111
|
+
- هل يتم استخراج `<p>This is a paragraph{" "}\n containing multiple lines</p>`؟
|
|
112
|
+
- هل يتم استخراج نتيجة الدالة `<p>{getStatusMessage()}</p>`؟
|
|
113
|
+
- هل يتم استخراج `<div>{isLoading ? "The page is loading" : <MyComponent/>} </div>`؟
|
|
114
|
+
- هل يتم استخراج معرف منتج مثل `<span>AX-99</span>`؟
|
|
115
|
+
|
|
116
|
+
في النهاية، ستضطر إلى إضافة تعليقات محددة (مثل `// ignore-translation`، أو خصائص محددة مثل `data-compiler-ignore="true"`) لمنع ذلك من كسر منطق تطبيقك.
|
|
117
|
+
|
|
118
|
+
### كيف يتعامل Intlayer مع هذه التعقيدات؟
|
|
63
119
|
|
|
64
|
-
|
|
120
|
+
تستخدم Intlayer نهجًا مختلطًا لاكتشاف ما إذا كان يجب استخراج حقل للترجمة، مع محاولة تقليل الإيجابيات الكاذبة:
|
|
65
121
|
|
|
66
|
-
|
|
122
|
+
1. **تحليل AST:** يتحقق من نوع العنصر (مثل التمييز بين `reactNode` أو `label` أو خاصية `title`).
|
|
123
|
+
2. **التعرف على الأنماط:** يكتشف ما إذا كانت السلسلة تبدأ بحرف كبير أو تحتوي على مسافات، مما يشير إلى أنها على الأرجح نص قابل للقراءة من قبل الإنسان بدلاً من معرف كود.
|
|
67
124
|
|
|
68
|
-
|
|
125
|
+
### الحد الصعب للبيانات الديناميكية
|
|
69
126
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- هل يتم ترجمة `<MyComponent errorMessage="An error occurred" />`؟
|
|
73
|
-
- هل يتم ترجمة معرف منتج مثل `"AX-99"`؟
|
|
127
|
+
يعتمد استخراج المترجم على **التحليل الثابت**. يجب أن يرى السلسلة الحرفية في الكود الخاص بك لتوليد معرف ثابت.
|
|
128
|
+
إذا كانت واجهة برمجة التطبيقات (API) الخاصة بك تُرجع سلسلة رمز خطأ مثل `server_error`، فلا يمكنك ترجمتها باستخدام المترجم (compiler) لأن المترجم لا يعرف بوجود هذه السلسلة أثناء وقت البناء. ستضطر إلى بناء نظام ثانوي "للوقت التشغيلي فقط" خصيصًا للبيانات الديناميكية.
|
|
74
129
|
|
|
75
|
-
|
|
130
|
+
### نقص التجزئة (chunking)
|
|
76
131
|
|
|
77
|
-
|
|
132
|
+
بعض المترجمات لا تقوم بتجزئة الترجمات حسب الصفحة. إذا كان المترجم الخاص بك يُنتج ملف JSON كبير لكل لغة (مثل `./lang/en.json`، `./lang/fr.json`، إلخ)، فمن المحتمل أن ينتهي بك الأمر بتحميل محتوى من جميع صفحاتك لصفحة واحدة فقط يتم زيارتها. أيضًا، من المحتمل أن يتم تهيئة كل مكون يستخدم المحتوى الخاص بك بمحتوى أكثر بكثير مما هو ضروري، مما قد يسبب مشاكل في الأداء.
|
|
78
133
|
|
|
79
|
-
|
|
80
|
-
إذا أعاد API الخاص بك رمز خطأ مثل `server_error`، فلا يمكنك ترجمته باستخدام المترجم لأن المترجم لا يعرف بوجود هذه السلسلة أثناء وقت البناء. تُجبر على بناء نظام ثانوي "للتشغيل فقط" مخصص للبيانات الديناميكية.
|
|
134
|
+
كن حذرًا أيضًا بشأن تحميل ترجماتك بشكل ديناميكي. إذا لم يتم ذلك، فستقوم بتحميل محتوى لجميع اللغات بالإضافة إلى اللغة الحالية.
|
|
81
135
|
|
|
82
|
-
|
|
136
|
+
> لتوضيح المشكلة، تخيل موقعًا يحتوي على 10 صفحات و10 لغات (جميعها فريدة بنسبة 100%). ستقوم بتحميل محتوى لـ 99 صفحة إضافية (10 × 10 - 1).
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
### "انفجار القطع" وشلالات الشبكة
|
|
85
139
|
|
|
86
|
-
|
|
140
|
+
لحل مشكلة تقسيم القطع، تقدم بعض الحلول تقسيمًا حسب المكون، أو حتى حسب المفتاح. ومع ذلك، فإن المشكلة تُحل جزئيًا فقط. النقطة التسويقية لهذه الحلول غالبًا ما تكون "محتواك يتم تنظيفه من غير المستخدم."
|
|
87
141
|
|
|
88
|
-
|
|
142
|
+
في الواقع، إذا قمت بتحميل المحتوى بشكل ثابت، فإن حلك سيقوم بتنظيف المحتوى غير المستخدم، لكنك ستظل تحصل على محتوى من جميع اللغات محمّلًا مع تطبيقك.
|
|
89
143
|
|
|
90
|
-
|
|
144
|
+
فلماذا لا تقوم بتحميله ديناميكيًا؟ نعم، في هذه الحالة ستقوم بتحميل أكثر من المحتوى الضروري، لكن هذا ليس بدون مقايضات.
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
تحميل المحتوى ديناميكيًا يعزل كل قطعة من المحتوى في جزء خاص بها، والذي سيتم تحميله فقط عند عرض المكون. هذا يعني أنك ستقوم بعمل طلب HTTP واحد لكل كتلة نصية. هل لديك 1000 كتلة نصية في صفحتك؟ → 1000 طلب HTTP إلى خوادمك. وللحد من الضرر وتحسين وقت العرض الأول لتطبيقك، ستحتاج إلى إدخال عدة حدود Suspense أو محملات Skeleton.
|
|
93
147
|
|
|
94
|
-
|
|
148
|
+
> ملاحظة: حتى مع Next.js و SSR، ستظل مكوناتك مروية (hydrated) بعد التحميل، لذا ستظل طلبات HTTP تتم.
|
|
95
149
|
|
|
96
|
-
|
|
150
|
+
الحل؟ اعتماد حل يسمح بالإعلان عن محتوى محدود النطاق، كما يفعل `i18next`، `next-intl`، أو `intlayer`.
|
|
97
151
|
|
|
98
|
-
|
|
152
|
+
> ملاحظة: يتطلب `i18next` و `next-intl` منك إدارة استيراد مساحة الأسماء / الرسائل يدويًا لكل صفحة لتحسين حجم الحزمة الخاصة بك. يجب عليك استخدام محلل الحزم مثل `rollup-plugin-visualizer` (vite)، `@next/bundle-analyzer` (next.js)، أو `webpack-bundle-analyzer` (React CRA / Angular / إلخ) لاكتشاف ما إذا كنت تلوث حزمة التطبيق بترجمات غير مستخدمة.
|
|
99
153
|
|
|
100
|
-
|
|
101
|
-
|
|
154
|
+
### العبء على أداء وقت التشغيل
|
|
155
|
+
|
|
156
|
+
لجعل الترجمات تفاعلية (حتى يتم تحديثها فورًا عند تبديل اللغات)، غالبًا ما يقوم المترجم بحقن خطاطيف إدارة الحالة في كل مكون.
|
|
157
|
+
|
|
158
|
+
- **التكلفة:** إذا قمت بعرض قائمة تحتوي على 5000 عنصر، فأنت تقوم بتهيئة 5000 خطاف `useState` و `useEffect` فقط للنصوص. يجب على React التعرف على جميع المستهلكين الخمسة آلاف وإعادة عرضهم في نفس الوقت. هذا يسبب حظرًا كبيرًا في "الخيط الرئيسي"، مما يؤدي إلى تجميد واجهة المستخدم أثناء التبديل. هذا يستهلك الذاكرة ودورات وحدة المعالجة المركزية التي توفرها المكتبات التصريحية (التي تستخدم عادة مزود Context واحد).
|
|
159
|
+
|
|
160
|
+
> لاحظ أن المشكلة مشابهة في أطر عمل أخرى غير React.
|
|
161
|
+
|
|
162
|
+
## الفخ: القفل مع البائع
|
|
163
|
+
|
|
164
|
+
كن حذرًا عند اختيار حل i18n يسمح باستخراج أو ترحيل مفاتيح الترجمة.
|
|
165
|
+
|
|
166
|
+
في حالة استخدام مكتبة تصريحية، يحتوي كود المصدر الخاص بك صراحةً على نية الترجمة الخاصة بك: هذه هي المفاتيح الخاصة بك، وأنت تتحكم بها. إذا أردت تغيير المكتبات، فعادةً ما تحتاج فقط إلى تحديث الاستيراد.
|
|
167
|
+
|
|
168
|
+
مع نهج المترجم، قد يكون كود المصدر الخاص بك مجرد نص إنجليزي عادي، بدون أي أثر لمنطق الترجمة: كل شيء مخفي في تكوين أداة البناء. إذا أصبح ذلك المكون الإضافي غير مدعوم أو أردت تغيير الحلول، قد تجد نفسك عالقًا. لا توجد طريقة سهلة لـ "الإخراج": لا توجد مفاتيح قابلة للاستخدام في كودك، وقد تحتاج إلى إعادة توليد جميع ترجماتك لمكتبة جديدة.
|
|
169
|
+
|
|
170
|
+
بعض الحلول تقدم أيضًا خدمات توليد الترجمة. لا مزيد من الرصيد؟ لا مزيد من الترجمات.
|
|
171
|
+
|
|
172
|
+
يقوم المترجمون غالبًا بتجزئة النص (على سبيل المثال، `"Hello World"` -> `x7f2a`). تبدو ملفات الترجمة الخاصة بك مثل `{ "x7f2a": "Hola Mundo" }`. الفخ: إذا قمت بتغيير المكتبات، فإن المكتبة الجديدة ترى `"Hello World"` وتبحث عن هذا المفتاح. لن تجده لأن ملف الترجمة الخاص بك مليء بالتجزئات (`x7f2a`).
|
|
173
|
+
|
|
174
|
+
### القفل على المنصة
|
|
175
|
+
|
|
176
|
+
من خلال اختيار نهج قائم على المترجم، تقيد نفسك بالمنصة الأساسية. على سبيل المثال، بعض المترجمين غير متاحين لجميع أدوات الحزم (مثل Vite أو Turbopack أو Metro). يمكن أن يجعل هذا عمليات النقل المستقبلية صعبة، وقد تحتاج إلى اعتماد حلول متعددة لتغطية جميع تطبيقاتك.
|
|
102
177
|
|
|
103
178
|
## الجانب الآخر: مخاطر النهج التصريحي
|
|
104
179
|
|
|
105
|
-
|
|
180
|
+
للنزاهة، الطريقة التصريحية التقليدية ليست مثالية أيضًا. لديها مجموعة من "الأخطاء الشائعة".
|
|
106
181
|
|
|
107
|
-
1. **جحيم المساحات الاسمية:** غالبًا ما يتعين عليك إدارة ملفات JSON التي يجب تحميلها يدويًا (`common.json`، `dashboard.json`، `footer.json`). إذا نسيت واحدًا،
|
|
108
|
-
2. **التحميل الزائد:** بدون تكوين دقيق، من السهل جدًا تحميل _جميع_ مفاتيح الترجمة الخاصة بك
|
|
182
|
+
1. **جحيم المساحات الاسمية:** غالبًا ما يتعين عليك إدارة ملفات JSON التي يجب تحميلها يدويًا (`common.json`، `dashboard.json`، `footer.json`). إذا نسيت واحدًا، يرى المستخدم المفاتيح الخام.
|
|
183
|
+
2. **التحميل الزائد:** بدون تكوين دقيق، من السهل جدًا تحميل _جميع_ مفاتيح الترجمة الخاصة بك لجميع الصفحات عند التحميل الأولي، مما يؤدي إلى تضخم حجم الحزمة الخاصة بك.
|
|
109
184
|
3. **انحراف التزامن:** من الشائع أن تبقى المفاتيح في ملف JSON لفترة طويلة بعد حذف المكون الذي يستخدمها. تنمو ملفات الترجمة الخاصة بك بلا حدود، مليئة بـ "مفاتيح الزومبي".
|
|
110
185
|
|
|
111
|
-
## الحل
|
|
186
|
+
## الحل الوسيط من Intlayer
|
|
112
187
|
|
|
113
|
-
هنا تحاول أدوات مثل **Intlayer** الابتكار. يفهم Intlayer أنه بينما
|
|
188
|
+
هنا تحاول أدوات مثل **Intlayer** الابتكار. يفهم Intlayer أنه بينما المجمعات قوية، فإن السحر الضمني خطير.
|
|
114
189
|
|
|
115
|
-
يقدم Intlayer
|
|
190
|
+
يقدم Intlayer نهجًا مختلطًا، يتيح لك الاستفادة من مزايا كلا النهجين: إدارة المحتوى التصريحية، والمتوافقة أيضًا مع المجمع الخاص به لتوفير وقت التطوير.
|
|
191
|
+
|
|
192
|
+
وحتى إذا لم تستخدم مترجم Intlayer، فإن Intlayer يقدم أمر `transform` (يمكن الوصول إليه أيضًا باستخدام امتداد VSCode). بدلاً من القيام بالسحر فقط في خطوة البناء المخفية، يمكنه فعليًا **إعادة كتابة كود المكون الخاص بك**. يقوم بمسح نصك ويستبدله بإعلانات محتوى صريحة في قاعدة الكود الخاصة بك.
|
|
116
193
|
|
|
117
194
|
هذا يمنحك أفضل ما في العالمين:
|
|
118
195
|
|
|
119
|
-
1. **الدقة:** تحتفظ بترجماتك قريبة من مكوناتك (
|
|
196
|
+
1. **الدقة:** تحتفظ بترجماتك قريبة من مكوناتك (مما يحسن من التجزئة وإزالة الشجر غير المستخدم).
|
|
120
197
|
2. **الأمان:** تصبح الترجمة كودًا صريحًا، وليس سحرًا مخفيًا في وقت البناء.
|
|
121
|
-
3. **عدم القفل:** نظرًا لأن الكود يتم تحويله إلى هيكل إعلاني
|
|
198
|
+
3. **عدم القفل:** نظرًا لأن الكود يتم تحويله إلى هيكل إعلاني داخل مستودعك، يمكنك بسهولة الضغط على Tab، أو استخدام مساعد IDE الخاص بك (copilot)، لتوليد إعلانات المحتوى الخاصة بك، أنت لا تخفي المنطق في مكون إضافي لـ webpack.
|
|
122
199
|
|
|
123
200
|
## الخلاصة
|
|
124
201
|
|
|
125
|
-
فأي
|
|
202
|
+
فأي خيار يجب أن تختار؟
|
|
203
|
+
|
|
204
|
+
**إذا كنت تبني MVP، أو تريد التحرك بسرعة:**
|
|
205
|
+
النهج المعتمد على المترجم هو خيار صالح. يسمح لك بالتحرك بسرعة كبيرة. لا تحتاج للقلق بشأن هيكل الملفات أو المفاتيح. فقط قم بالبناء. الدين الفني سيكون مشكلة لـ "أنت في المستقبل".
|
|
206
|
+
|
|
207
|
+
**إذا كنت مطورًا مبتدئًا، أو لا تهتم بالتحسين:**
|
|
208
|
+
إذا كنت تريد أقل إدارة يدوية، فمن المحتمل أن يكون النهج المعتمد على المترجم هو الأفضل. لن تحتاج إلى التعامل مع المفاتيح أو ملفات الترجمة بنفسك - فقط اكتب النص، والمترجم يقوم بالباقي تلقائيًا. هذا يقلل من جهد الإعداد والأخطاء الشائعة في التدويل المرتبطة بالخطوات اليدوية.
|
|
126
209
|
|
|
127
|
-
**إذا كنت
|
|
128
|
-
النهج القائم على المترجم
|
|
210
|
+
**إذا كنت تقوم بتدويل مشروع قائم يحتوي بالفعل على آلاف المكونات التي تحتاج لإعادة هيكلة:**
|
|
211
|
+
يمكن أن يكون النهج القائم على المترجم خيارًا عمليًا هنا. يمكن لمرحلة الاستخراج الأولية أن توفر أسابيع أو شهورًا من العمل اليدوي. ومع ذلك، فكر في استخدام أداة مثل أمر `transform` في Intlayer، والتي يمكنها استخراج السلاسل النصية وتحويلها إلى إعلانات محتوى صريحة وتصريحية. هذا يمنحك سرعة الأتمتة مع الحفاظ على أمان وقابلية نقل النهج التصريحي. تحصل على أفضل ما في العالمين: هجرة أولية سريعة دون ديون معمارية طويلة الأمد.
|
|
129
212
|
|
|
130
|
-
**إذا كنت تبني تطبيقًا احترافيًا
|
|
131
|
-
السحر عادةً ما يكون فكرة سيئة.
|
|
213
|
+
**إذا كنت تبني تطبيقًا احترافيًا من الدرجة المؤسسية:**
|
|
214
|
+
السحر عادةً ما يكون فكرة سيئة. أنت بحاجة إلى التحكم.
|
|
132
215
|
|
|
133
216
|
- تحتاج إلى التعامل مع البيانات الديناميكية من الخلفيات.
|
|
134
|
-
- تحتاج إلى ضمان الأداء على الأجهزة منخفضة المواصفات (تجنب انفجارات الـ
|
|
217
|
+
- تحتاج إلى ضمان الأداء على الأجهزة منخفضة المواصفات (تجنب انفجارات الـ hook).
|
|
135
218
|
- تحتاج إلى التأكد من أنك لست مقيدًا بأداة بناء معينة إلى الأبد.
|
|
136
219
|
|
|
137
|
-
بالنسبة للتطبيقات
|
|
220
|
+
بالنسبة للتطبيقات المهنية، تظل **إدارة المحتوى التصريحية** (مثل Intlayer أو المكتبات المعروفة) هي المعيار الذهبي. فهي تفصل بين اهتماماتك، وتحافظ على نظافة هيكلك المعماري، وتضمن أن قدرة تطبيقك على التحدث بعدة لغات لا تعتمد على "صندوق أسود" يقوم المترجم بتخمين نواياك.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
createdAt: 2025-11-24
|
|
3
3
|
updatedAt: 2025-11-24
|
|
4
4
|
title: Compiler vs. deklarative i18n
|
|
5
|
-
description: Untersuchung der architektonischen Kompromisse zwischen "magischer"
|
|
5
|
+
description: Untersuchung der architektonischen Kompromisse zwischen "magischer" compilerbasierter Internationalisierung und explizitem deklarativem Content-Management.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- Internationalisierung
|
|
@@ -18,27 +18,59 @@ slugs:
|
|
|
18
18
|
- compiler-vs-declarative-i18n
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
# Pro und Contra
|
|
21
|
+
# Pro und Contra compilerbasierte i18n
|
|
22
22
|
|
|
23
|
-
Wenn Sie seit mehr als einem Jahrzehnt Webanwendungen entwickeln, wissen Sie, dass Internationalisierung (i18n) schon immer ein Reibungspunkt war. Es ist oft die Aufgabe, die niemand machen möchte – Strings
|
|
23
|
+
Wenn Sie seit mehr als einem Jahrzehnt Webanwendungen entwickeln, wissen Sie, dass Internationalisierung (i18n) schon immer ein Reibungspunkt war. Es ist oft die Aufgabe, die niemand machen möchte – das Extrahieren von Strings, das Verwalten von JSON-Dateien und das Sorgen um Pluralisierungsregeln.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Kürzlich ist eine neue Welle von **"compilerbasierten" i18n-Tools** aufgetaucht, die versprechen, diesen Schmerz verschwinden zu lassen. Das Versprechen ist verlockend: **Schreiben Sie einfach den Text in Ihre Komponenten, und lassen Sie das Build-Tool den Rest erledigen.** Keine Schlüssel, keine Importe, einfach Magie.
|
|
26
26
|
|
|
27
27
|
Aber wie bei allen Abstraktionen in der Softwareentwicklung hat Magie ihren Preis.
|
|
28
28
|
|
|
29
|
-
In diesem Blogbeitrag werden wir den Wandel von deklarativen Bibliotheken hin zu
|
|
29
|
+
In diesem Blogbeitrag werden wir den Wandel von deklarativen Bibliotheken hin zu compilerbasierten Ansätzen untersuchen, die versteckten architektonischen Schulden, die sie mit sich bringen, und warum der „langweilige" Weg für professionelle Anwendungen vielleicht immer noch der beste ist.
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Inhaltsverzeichnis
|
|
32
|
+
|
|
33
|
+
<TOC/>
|
|
34
|
+
|
|
35
|
+
## Eine kurze Geschichte der Internationalisierung
|
|
32
36
|
|
|
33
37
|
Um zu verstehen, wo wir stehen, müssen wir zurückblicken, wo wir angefangen haben.
|
|
34
38
|
|
|
35
39
|
Um 2011–2012 sah die JavaScript-Landschaft ganz anders aus. Bundler, wie wir sie heute kennen (Webpack, Vite), existierten entweder noch nicht oder steckten noch in den Kinderschuhen. Wir klebten Skripte direkt im Browser zusammen. In dieser Zeit entstanden Bibliotheken wie **i18next**.
|
|
36
40
|
|
|
37
|
-
Sie lösten das Problem auf die damals einzig mögliche Weise: **
|
|
41
|
+
Sie lösten das Problem auf die damals einzig mögliche Weise: **Laufzeit-Wörterbücher**. Man lud ein riesiges JSON-Objekt in den Speicher, und eine Funktion suchte die Schlüssel zur Laufzeit nach. Es war zuverlässig, explizit und funktionierte überall.
|
|
42
|
+
|
|
43
|
+
Schneller Vorlauf bis heute. Wir haben leistungsstarke Compiler (SWC, Rust-basierte Bundler), die Abstract Syntax Trees (AST) in Millisekunden parsen können. Diese Leistung brachte eine neue Idee hervor: _Warum verwalten wir Schlüssel manuell? Warum kann der Compiler nicht einfach den Text "Hello World" sehen und für uns austauschen?_
|
|
44
|
+
|
|
45
|
+
So wurde die compilerbasierte i18n geboren.
|
|
46
|
+
|
|
47
|
+
> **Beispiel für compiler-basierte i18n:**
|
|
48
|
+
>
|
|
49
|
+
> - Paraglide (Tree-shaken-Module, die jede Nachricht in eine kleine ESM-Funktion kompilieren, sodass Bundler ungenutzte Sprachen und Schlüssel automatisch entfernen können. Du importierst Nachrichten als Funktionen, anstatt String-Schlüssel nachzuschlagen.)
|
|
50
|
+
> - LinguiJS (Macro-zu-Funktion-Compiler, der Nachrichten-Makros wie `<Trans>` zur Build-Zeit in einfache JS-Funktionsaufrufe umschreibt. Du erhältst ICU/MessageFormat-Syntax mit einem sehr kleinen Laufzeit-Footprint.)
|
|
51
|
+
> - Lingo.dev (Konzentriert sich auf die Automatisierung der Lokalisierungspipeline, indem übersetzte Inhalte direkt während des Builds deiner React-Anwendung injiziert werden. Es kann Übersetzungen mithilfe von KI automatisch generieren und sich direkt in CI/CD integrieren.)
|
|
52
|
+
> - Wuchale (Svelte-first Preprocessor, der Inline-Text in .svelte-Dateien extrahiert und in Wrapper-freie Übersetzungsfunktionen kompiliert. Er vermeidet String-Schlüssel und trennt die Logik der Inhaltsextraktion vollständig vom Hauptanwendungs-Laufzeitumfeld.)
|
|
53
|
+
> - Intlayer (Compiler / Extract CLI, der deine Komponenten parst, typisierte Wörterbücher generiert und optional den Code umschreiben kann, um expliziten Intlayer-Inhalt zu verwenden. Das Ziel ist es, den Compiler für Geschwindigkeit zu nutzen und gleichzeitig einen deklarativen, framework-agnostischen Kern beizubehalten.)
|
|
54
|
+
|
|
55
|
+
> **Beispiel für deklarative i18n:**
|
|
56
|
+
>
|
|
57
|
+
> - i18next / react-i18next / next-i18next (Der ausgereifte Industriestandard, der zur Laufzeit JSON-Wörterbücher und ein umfangreiches Plugin-Ökosystem verwendet)
|
|
58
|
+
> - react-intl (Teil der FormatJS-Bibliothek, die sich auf die standardisierte ICU-Nachrichtensyntax und strikte Datenformatierung konzentriert)
|
|
59
|
+
> - next-intl (Speziell für Next.js optimiert mit Integration für den App Router und React Server Components)
|
|
60
|
+
> - vue-i18n / @nuxt/i18n (Die Standardlösung im Vue-Ökosystem, die Übersetzungsblöcke auf Komponentenebene und eine enge Reaktivitätsintegration bietet)
|
|
61
|
+
> - svelte-i18n (Ein leichter Wrapper um Svelte Stores für reaktive, zur Laufzeit stattfindende Übersetzungen)
|
|
62
|
+
> - angular-translate (Die veraltete dynamische Übersetzungsbibliothek, die auf Laufzeit-Schlüsselabfragen statt auf Build-Zeit-Zusammenführung setzt)
|
|
63
|
+
> - angular-i18n (Angulards native Ahead-of-Time-Methode, die XLIFF-Dateien direkt während des Builds in Templates zusammenführt)
|
|
64
|
+
> - Tolgee (Kombiniert deklarativen Code mit einem In-Context-SDK für „Click-to-Translate“-Bearbeitung direkt in der UI)
|
|
65
|
+
> - Intlayer (Komponentenbasierter Ansatz, der Content-Declaration-Dateien verwendet und so natives Tree-Shaking sowie TypeScript-Validierung ermöglicht)
|
|
66
|
+
|
|
67
|
+
## Der Intlayer Compiler
|
|
68
|
+
|
|
69
|
+
Obwohl **Intlayer** eine Lösung ist, die grundsätzlich einen **deklarativen Ansatz** für Ihre Inhalte fördert, beinhaltet sie einen Compiler, der die Entwicklung beschleunigen oder schnelles Prototyping erleichtern soll.
|
|
38
70
|
|
|
39
|
-
|
|
71
|
+
Der Intlayer Compiler durchläuft den AST (Abstract Syntax Tree) Ihrer React-, Vue- oder Svelte-Komponenten sowie anderer JavaScript/TypeScript-Dateien. Seine Aufgabe ist es, hartkodierte Strings zu erkennen und in dedizierte `.content`-Deklarationen zu extrahieren.
|
|
40
72
|
|
|
41
|
-
|
|
73
|
+
> Für weitere Details siehe die Dokumentation: [Intlayer Compiler Docs](https://github.com/aymericzip/intlayer/blob/main/docs/docs/de/compiler.md)
|
|
42
74
|
|
|
43
75
|
## Der Reiz des Compilers (Der "Magische" Ansatz)
|
|
44
76
|
|
|
@@ -46,92 +78,143 @@ Es gibt einen Grund, warum dieser neue Ansatz im Trend liegt. Für einen Entwick
|
|
|
46
78
|
|
|
47
79
|
### 1. Geschwindigkeit und "Flow"
|
|
48
80
|
|
|
49
|
-
Wenn man im Flow ist, unterbricht das Nachdenken über einen Variablennamen (`home_hero_title_v2`) den Arbeitsfluss. Mit einem Compiler-Ansatz tippt man einfach `<p>Welcome back</p>` und macht weiter. Die Reibung ist null.
|
|
81
|
+
Wenn man im Flow ist, unterbricht das Nachdenken über einen semantischen Variablennamen (`home_hero_title_v2`) den Arbeitsfluss. Mit einem Compiler-Ansatz tippt man einfach `<p>Welcome back</p>` und macht weiter. Die Reibung ist null.
|
|
50
82
|
|
|
51
|
-
### 2. Die Rettungsmission für
|
|
83
|
+
### 2. Die Rettungsmission für Legacy-Code
|
|
52
84
|
|
|
53
|
-
Stellen Sie sich vor, Sie erben eine riesige Codebasis mit 5.000 Komponenten und
|
|
85
|
+
Stellen Sie sich vor, Sie erben eine riesige Codebasis mit 5.000 Komponenten und keinen Übersetzungen. Diese nachträglich mit einem manuellen schlüsselbasierten System auszustatten, ist ein monatelanger Albtraum. Ein compilerbasiertes Tool fungiert als Rettungsstrategie, indem es sofort Tausende von Strings extrahiert, ohne dass Sie eine einzige Datei manuell anfassen müssen.
|
|
54
86
|
|
|
55
87
|
### 3. Das KI-Zeitalter
|
|
56
88
|
|
|
57
|
-
Dies ist ein moderner Vorteil, den wir nicht übersehen sollten. KI-Coding-Assistenten (wie Copilot oder ChatGPT) erzeugen
|
|
89
|
+
Dies ist ein moderner Vorteil, den wir nicht übersehen sollten. KI-Coding-Assistenten (wie Copilot oder ChatGPT) erzeugen natürlich standardmäßiges JSX/HTML. Sie kennen Ihr spezifisches Übersetzungsschlüsselschema nicht.
|
|
58
90
|
|
|
59
91
|
- **Deklarativ:** Sie müssen die Ausgabe der KI umschreiben, um Text durch Schlüssel zu ersetzen.
|
|
60
|
-
- **Compiler:** Sie kopieren den Code der KI
|
|
92
|
+
- **Compiler:** Sie kopieren den Code der KI und es funktioniert einfach.
|
|
61
93
|
|
|
62
|
-
##
|
|
94
|
+
## Der Realitätscheck: Warum „Magie“ gefährlich ist
|
|
63
95
|
|
|
64
|
-
|
|
96
|
+
Während die „Magie“ verlockend ist, treten Abstraktionslecks auf. Sich darauf zu verlassen, dass ein Build-Tool die menschliche Absicht versteht, führt zu architektonischer Fragilität.
|
|
65
97
|
|
|
66
|
-
###
|
|
98
|
+
### Heuristische Fragilität (Das Ratespiel)
|
|
67
99
|
|
|
68
|
-
Der Compiler muss erraten, was Inhalt und was Code ist.
|
|
100
|
+
Der Compiler muss erraten, was Inhalt und was Code ist. Das führt zu Randfällen, bei denen man am Ende gegen das Tool „kämpft“.
|
|
69
101
|
|
|
70
|
-
|
|
71
|
-
- Wird `status="pending"` übersetzt?
|
|
72
|
-
- Wird `<MyComponent errorMessage="An error occurred" />` übersetzt?
|
|
73
|
-
- Wird eine Produkt-ID wie `"AX-99"` übersetzt?
|
|
102
|
+
Betrachten Sie diese Szenarien:
|
|
74
103
|
|
|
75
|
-
|
|
104
|
+
- Wird `<span className="active"></span>` extrahiert? (Es ist ein String, aber wahrscheinlich eine Klasse).
|
|
105
|
+
- Wird `<span status="pending"></span>` extrahiert? (Es ist ein Prop-Wert).
|
|
106
|
+
- Wird `<span>{"Hello World"}</span>` extrahiert? (Es ist ein JS-Ausdruck).
|
|
107
|
+
- Wird `<span>Hello {name}. How are you?</span>` extrahiert? (Interpolation ist komplex).
|
|
108
|
+
- Wird `<span aria-label="Image of cat"></span>` extrahiert? (Barrierefreiheitsattribute müssen übersetzt werden).
|
|
109
|
+
- Wird `<span data-testid="my-element"></span>` extrahiert? (Test-IDs sollten NICHT übersetzt werden).
|
|
110
|
+
- Wird `<MyComponent errorMessage="An error occurred" />` extrahiert?
|
|
111
|
+
- Wird `<p>This is a paragraph{" "}\n containing multiple lines</p>` extrahiert?
|
|
112
|
+
- Wird das Ergebnis der Funktion `<p>{getStatusMessage()}</p>` extrahiert?
|
|
113
|
+
- Wird `<div>{isLoading ? "The page is loading" : <MyComponent/>} </div>` extrahiert?
|
|
114
|
+
- Wird eine Produkt-ID wie `<span>AX-99</span>` extrahiert?
|
|
76
115
|
|
|
77
|
-
|
|
116
|
+
Unweigerlich fügen Sie spezifische Kommentare hinzu (wie `// ignore-translation` oder spezifische Props wie `data-compiler-ignore="true"`), um zu verhindern, dass die Anwendung logik bricht.
|
|
117
|
+
|
|
118
|
+
### Wie geht Intlayer mit dieser Komplexität um?
|
|
119
|
+
|
|
120
|
+
Intlayer verwendet einen gemischten Ansatz, um zu erkennen, ob ein Feld für die Übersetzung extrahiert werden soll, und versucht dabei, Fehlalarme zu minimieren:
|
|
121
|
+
|
|
122
|
+
1. **AST-Analyse:** Es überprüft den Elementtyp (z. B. Unterscheidung zwischen einem `reactNode`, einem `label` oder einer `title`-Prop).
|
|
123
|
+
2. **Mustererkennung:** Es erkennt, ob der String großgeschrieben ist oder Leerzeichen enthält, was darauf hindeutet, dass es sich wahrscheinlich um menschenlesbaren Text und nicht um einen Codebezeichner handelt.
|
|
124
|
+
|
|
125
|
+
### Die harte Grenze für dynamische Daten
|
|
78
126
|
|
|
79
127
|
Die Compiler-Extraktion basiert auf **statischer Analyse**. Sie muss den Literalstring in Ihrem Code sehen, um eine stabile ID zu generieren.
|
|
80
|
-
Wenn Ihre API einen Fehlercode-String wie `server_error` zurückgibt, können Sie
|
|
128
|
+
Wenn Ihre API einen Fehlercode-String wie `server_error` zurückgibt, können Sie diesen nicht mit einem Compiler übersetzen, da der Compiler zur Build-Zeit nicht weiß, dass dieser String existiert. Sie sind gezwungen, ein sekundäres "Nur-Laufzeit"-System ausschließlich für dynamische Daten zu erstellen.
|
|
129
|
+
|
|
130
|
+
### Fehlende Chunk-Aufteilung
|
|
131
|
+
|
|
132
|
+
Bestimmte Compiler teilen Übersetzungen nicht pro Seite auf. Wenn Ihr Compiler eine große JSON-Datei pro Sprache generiert (z. B. `./lang/en.json`, `./lang/fr.json` usw.), laden Sie wahrscheinlich Inhalte aller Seiten für eine einzelne besuchte Seite. Außerdem wird jede Komponente, die Ihre Inhalte verwendet, wahrscheinlich mit weit mehr Inhalt als nötig hydriert, was potenziell zu Performance-Problemen führen kann.
|
|
133
|
+
|
|
134
|
+
Seien Sie auch vorsichtig beim dynamischen Laden Ihrer Übersetzungen. Wenn dies nicht gemacht wird, laden Sie Inhalte für alle Sprachen zusätzlich zur aktuellen.
|
|
81
135
|
|
|
82
|
-
|
|
136
|
+
> Um das Problem zu veranschaulichen, betrachten Sie eine Website mit 10 Seiten und 10 Sprachen (alle zu 100 % einzigartig). Sie würden Inhalte für 99 zusätzliche Seiten laden (10 × 10 - 1).
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
### „Chunk-Explosion“ und Netzwerk-Wasserfälle
|
|
85
139
|
|
|
86
|
-
|
|
140
|
+
Um das Chunking-Problem zu lösen, bieten einige Lösungen Chunking pro Komponente oder sogar pro Schlüssel an. Doch das Problem wird nur teilweise gelöst. Das Verkaufsargument für diese Lösungen ist oft: „Ihr Inhalt wird tree-shaken.“
|
|
87
141
|
|
|
88
|
-
|
|
142
|
+
Tatsächlich, wenn Sie Inhalte statisch laden, wird Ihre Lösung ungenutzte Inhalte tree-shaken, aber Sie werden dennoch Inhalte aus allen Sprachen mit Ihrer Anwendung laden.
|
|
89
143
|
|
|
90
|
-
|
|
144
|
+
Warum also nicht dynamisch laden? Ja, in diesem Fall laden Sie mehr als den notwendigen Inhalt, aber das ist nicht ohne Kompromisse.
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
Das dynamische Laden von Inhalten isoliert jeden Inhaltsblock in einem eigenen Chunk, der nur geladen wird, wenn die Komponente gerendert wird. Das bedeutet, dass Sie für jeden Textblock eine HTTP-Anfrage stellen. 1.000 Textblöcke auf Ihrer Seite? → 1.000 HTTP-Anfragen an Ihre Server. Und um den Schaden zu begrenzen und die erste Renderzeit Ihrer Anwendung zu optimieren, müssen Sie mehrere Suspense-Grenzen oder Skeleton Loader einfügen.
|
|
147
|
+
|
|
148
|
+
> Hinweis: Selbst mit Next.js und SSR werden Ihre Komponenten nach dem Laden noch hydriert, sodass die HTTP-Anfragen weiterhin ausgeführt werden.
|
|
149
|
+
|
|
150
|
+
Die Lösung? Die Einführung einer Lösung, die es ermöglicht, scoped Content-Deklarationen zu definieren, wie es `i18next`, `next-intl` oder `intlayer` tun.
|
|
151
|
+
|
|
152
|
+
> Hinweis: `i18next` und `next-intl` erfordern, dass Sie Ihre Namespace- / Nachrichtenimporte manuell für jede Seite verwalten, um die Bundle-Größe zu optimieren. Sie sollten einen Bundle-Analyzer wie `rollup-plugin-visualizer` (vite), `@next/bundle-analyzer` (next.js) oder `webpack-bundle-analyzer` (React CRA / Angular / etc.) verwenden, um zu erkennen, ob Sie Ihr Bundle mit ungenutzten Übersetzungen belasten.
|
|
153
|
+
|
|
154
|
+
### Laufzeit-Performance-Overhead
|
|
155
|
+
|
|
156
|
+
Um Übersetzungen reaktiv zu machen (damit sie sofort aktualisiert werden, wenn Sie die Sprache wechseln), injiziert der Compiler häufig State-Management-Hooks in jede Komponente.
|
|
157
|
+
|
|
158
|
+
- **Die Kosten:** Wenn Sie eine Liste mit 5.000 Elementen rendern, initialisieren Sie 5.000 `useState`- und `useEffect`-Hooks ausschließlich für den Text. React muss alle 5.000 Verbraucher gleichzeitig identifizieren und neu rendern. Dies verursacht eine massive Blockade des "Main Thread" und friert die Benutzeroberfläche während des Wechsels ein. Dies verbraucht Speicher und CPU-Zyklen, die deklarative Bibliotheken (die typischerweise einen einzigen Context-Provider verwenden) einsparen.
|
|
159
|
+
|
|
160
|
+
> Beachten Sie, dass das Problem bei anderen Frameworks als React ähnlich ist.
|
|
93
161
|
|
|
94
162
|
## Die Falle: Vendor Lock-in
|
|
95
163
|
|
|
96
|
-
|
|
164
|
+
Seien Sie vorsichtig bei der Wahl einer i18n-Lösung, die die Extraktion oder Migration von Übersetzungsschlüsseln ermöglicht.
|
|
97
165
|
|
|
98
|
-
|
|
166
|
+
Im Fall einer deklarativen Bibliothek enthält Ihr Quellcode explizit Ihre Übersetzungsabsicht: Dies sind Ihre Schlüssel, und Sie kontrollieren sie. Wenn Sie die Bibliothek wechseln möchten, müssen Sie in der Regel nur den Import aktualisieren.
|
|
99
167
|
|
|
100
|
-
|
|
101
|
-
|
|
168
|
+
Bei einem Compiler-Ansatz besteht Ihr Quellcode möglicherweise nur aus einfachem englischem Text, ohne jegliche Übersetzungslogik: Alles ist in der Build-Tool-Konfiguration verborgen. Wenn dieses Plugin nicht mehr gepflegt wird oder Sie die Lösung wechseln möchten, könnten Sie feststecken. Es gibt keinen einfachen Weg zum „Aussteigen“: Es gibt keine verwendbaren Schlüssel in Ihrem Code, und Sie müssen möglicherweise alle Ihre Übersetzungen für eine neue Bibliothek neu generieren.
|
|
169
|
+
|
|
170
|
+
Einige Lösungen bieten auch Übersetzungsgenerierungsdienste an. Keine Credits mehr? Keine Übersetzungen mehr.
|
|
171
|
+
|
|
172
|
+
Compiler hashen oft den Text (z. B. `"Hello World"` -> `x7f2a`). Ihre Übersetzungsdateien sehen dann so aus: `{ "x7f2a": "Hola Mundo" }`. Die Falle: Wenn Sie die Bibliothek wechseln, sieht die neue Bibliothek `"Hello World"` und sucht nach diesem Schlüssel. Sie wird ihn nicht finden, weil Ihre Übersetzungsdatei voller Hashes (`x7f2a`) ist.
|
|
173
|
+
|
|
174
|
+
### Plattform-Abhängigkeit
|
|
175
|
+
|
|
176
|
+
Durch die Wahl eines compiler-basierten Ansatzes binden Sie sich an die zugrunde liegende Plattform. Beispielsweise sind bestimmte Compiler nicht für alle Bundler verfügbar (wie Vite, Turbopack oder Metro). Dies kann zukünftige Migrationen erschweren, und Sie müssen möglicherweise mehrere Lösungen einführen, um alle Ihre Anwendungen abzudecken.
|
|
102
177
|
|
|
103
178
|
## Die andere Seite: Risiken des deklarativen Ansatzes
|
|
104
179
|
|
|
105
|
-
Um fair zu sein, ist der traditionelle deklarative Weg auch nicht perfekt. Er hat seine eigenen
|
|
180
|
+
Um fair zu sein, ist der traditionelle deklarative Weg auch nicht perfekt. Er hat seine eigenen "Fallstricke".
|
|
106
181
|
|
|
107
182
|
1. **Namespace-Hölle:** Sie müssen oft manuell verwalten, welche JSON-Dateien geladen werden (`common.json`, `dashboard.json`, `footer.json`). Wenn Sie eine vergessen, sieht der Benutzer rohe Schlüssel.
|
|
108
|
-
2. **Übermäßiges Laden:** Ohne sorgfältige Konfiguration ist es sehr einfach, versehentlich _alle_ Ihre Übersetzungsschlüssel für _alle_ Seiten beim ersten Laden zu laden, was
|
|
109
|
-
3. **Synchronisationsabweichung:** Es ist üblich, dass Schlüssel lange nach der Löschung der sie verwendenden Komponente in der JSON-Datei verbleiben. Ihre Übersetzungsdateien wachsen unendlich und sind mit
|
|
183
|
+
2. **Übermäßiges Laden:** Ohne sorgfältige Konfiguration ist es sehr einfach, versehentlich _alle_ Ihre Übersetzungsschlüssel für _alle_ Seiten beim ersten Laden zu laden, was die Bundle-Größe aufbläht.
|
|
184
|
+
3. **Synchronisationsabweichung:** Es ist üblich, dass Schlüssel lange nach der Löschung der sie verwendenden Komponente in der JSON-Datei verbleiben. Ihre Übersetzungsdateien wachsen unendlich und sind mit "Zombie-Schlüsseln" gefüllt.
|
|
110
185
|
|
|
111
|
-
## Der Mittelweg
|
|
186
|
+
## Der Mittelweg von Intlayer
|
|
112
187
|
|
|
113
188
|
Hier versuchen Werkzeuge wie **Intlayer** zu innovieren. Intlayer versteht, dass Compiler zwar mächtig sind, implizite Magie jedoch gefährlich ist.
|
|
114
189
|
|
|
115
|
-
Intlayer bietet einen
|
|
190
|
+
Intlayer bietet einen gemischten Ansatz, der es Ihnen ermöglicht, von den Vorteilen beider Ansätze zu profitieren: deklaratives Content-Management, das auch mit seinem Compiler kompatibel ist, um Entwicklungszeit zu sparen.
|
|
116
191
|
|
|
117
|
-
|
|
192
|
+
Und selbst wenn Sie den Intlayer-Compiler nicht verwenden, bietet Intlayer einen `transform`-Befehl an (auch über die VSCode-Erweiterung zugänglich). Anstatt nur Magie im versteckten Build-Schritt auszuführen, kann er tatsächlich **Ihren Komponenten-Code umschreiben**. Er durchsucht Ihren Text und ersetzt ihn durch explizite Inhaltsdeklarationen in Ihrem Code-Repository.
|
|
193
|
+
|
|
194
|
+
Das gibt Ihnen das Beste aus beiden Welten:
|
|
118
195
|
|
|
119
196
|
1. **Granularität:** Sie halten Ihre Übersetzungen nah an Ihren Komponenten (verbessert Modularität und Tree-Shaking).
|
|
120
197
|
2. **Sicherheit:** Die Übersetzung wird zu explizitem Code, nicht zu versteckter Build-Zeit-Magie.
|
|
121
|
-
3. **Keine
|
|
198
|
+
3. **Keine Abhängigkeit:** Da der Code in eine deklarative Struktur innerhalb Ihres Repos umgewandelt wird, können Sie einfach Tab drücken oder den Copilot Ihres IDEs verwenden, um Ihre Inhaltsdeklarationen zu generieren; Sie verstecken keine Logik in einem Webpack-Plugin.
|
|
122
199
|
|
|
123
200
|
## Fazit
|
|
124
201
|
|
|
125
|
-
Welche
|
|
202
|
+
Welche Option sollten Sie also wählen?
|
|
203
|
+
|
|
204
|
+
**Wenn Sie ein MVP erstellen oder schnell vorankommen möchten:**
|
|
205
|
+
Der compiler-basierte Ansatz ist eine gültige Wahl. Er ermöglicht es Ihnen, unglaublich schnell zu arbeiten. Sie müssen sich nicht um Dateistrukturen oder Schlüssel kümmern. Sie bauen einfach. Die technische Schuld ist ein Problem für das „zukünftige Ich“.
|
|
206
|
+
|
|
207
|
+
**Wenn Sie ein Junior-Entwickler sind oder sich nicht um Optimierung kümmern:**
|
|
208
|
+
Wenn Sie die geringste manuelle Verwaltung wünschen, ist ein compiler-basierter Ansatz wahrscheinlich am besten. Sie müssen sich nicht selbst um Schlüssel oder Übersetzungsdateien kümmern – schreiben Sie einfach Text, und der Compiler automatisiert den Rest. Dies reduziert den Einrichtungsaufwand und häufige i18n-Fehler, die mit manuellen Schritten verbunden sind.
|
|
126
209
|
|
|
127
|
-
**Wenn Sie ein
|
|
128
|
-
|
|
210
|
+
**Wenn Sie ein bestehendes Projekt internationalisieren, das bereits Tausende von Komponenten zur Überarbeitung enthält:**
|
|
211
|
+
Ein compiler-basierter Ansatz kann hier eine pragmatische Wahl sein. Die anfängliche Extraktionsphase kann Wochen oder Monate manueller Arbeit einsparen. Erwägen Sie jedoch die Verwendung eines Tools wie den `transform`-Befehl von Intlayer, der Zeichenketten extrahieren und in explizite deklarative Inhaltsdeklarationen umwandeln kann. Dies bietet Ihnen die Geschwindigkeit der Automatisierung bei gleichzeitiger Sicherheit und Portabilität eines deklarativen Ansatzes. Sie erhalten das Beste aus beiden Welten: eine schnelle anfängliche Migration ohne langfristige architektonische Schulden.
|
|
129
212
|
|
|
130
|
-
**Wenn Sie eine professionelle, unternehmensgerechte Anwendung entwickeln:**
|
|
131
|
-
Magie ist im Allgemeinen
|
|
213
|
+
**Wenn Sie eine professionelle, unternehmensgerechte Anwendung entwickeln:**
|
|
214
|
+
Magie ist im Allgemeinen keine gute Idee. Sie benötigen Kontrolle.
|
|
132
215
|
|
|
133
216
|
- Sie müssen dynamische Daten von Backends verarbeiten.
|
|
134
217
|
- Sie müssen die Leistung auf Geräten mit geringer Leistung sicherstellen (Vermeidung von Hook-Explosionen).
|
|
135
218
|
- Sie müssen sicherstellen, dass Sie nicht für immer an ein bestimmtes Build-Tool gebunden sind.
|
|
136
219
|
|
|
137
|
-
Für professionelle Anwendungen bleibt **Deklaratives Content
|
|
220
|
+
Für professionelle Anwendungen bleibt **Deklaratives Content-Management** (wie Intlayer oder etablierte Bibliotheken) der Goldstandard. Es trennt Ihre Anliegen, hält Ihre Architektur sauber und stellt sicher, dass die Mehrsprachigkeitsfähigkeit Ihrer Anwendung nicht von einem „Black-Box“-Compiler abhängt, der Ihre Absichten errät.
|