---
createdAt: 2025-11-24
updatedAt: 2025-11-24
title: المترجم مقابل التدوين التصريحي للتدويل
description: استكشاف التنازلات المعمارية بين التدويل "السحري" المعتمد على المترجم وإدارة المحتوى التصريحية الصريحة.
keywords:
  - Intlayer
  - التدويل
  - مدونة
  - Next.js
  - JavaScript
  - React
  - i18n
  - المترجم
  - تصريحي
slugs:
  - blog
  - compiler-vs-declarative-i18n
---

# الحجج المؤيدة والمعارضة للتدويل المعتمد على المترجم

إذا كنت تبني تطبيقات ويب لأكثر من عقد من الزمن، فأنت تعلم أن التدويل (i18n) كان دائمًا نقطة احتكاك. غالبًا ما تكون مهمة لا يرغب أحد في القيام بها - استخراج النصوص، إدارة ملفات JSON، والقلق بشأن قواعد الجمع.

مؤخرًا، ظهرت موجة جديدة من أدوات التدويل **المعتمدة على المترجم**، والتي تعد بجعل هذه المعاناة تختفي. العرض مغرٍ: **فقط اكتب النصوص في مكوناتك، ودع أداة البناء تتولى الباقي.** لا مفاتيح، لا استيرادات، فقط سحر.

ولكن كما هو الحال مع جميع التجريدات في هندسة البرمجيات، يأتي السحر بثمن.

في هذه التدوينة، سوف نستكشف التحول من المكتبات التصريحية إلى النهج المعتمد على المترجم، والديون المعمارية الخفية التي يقدمونها، ولماذا قد تظل الطريقة "المملة" هي الأفضل للتطبيقات المهنية.

## جدول المحتويات

<TOC/>

## لمحة تاريخية عن التدويل

لفهم مكاننا الحالي، يجب أن ننظر إلى الوراء حيث بدأنا.

في الفترة ما بين 2011 و2012، كان مشهد جافا سكريبت مختلفًا تمامًا. لم تكن أدوات التجميع كما نعرفها اليوم (Webpack، Vite) موجودة أو كانت في مراحلها الأولى. كنا نلصق السكريبتات معًا في المتصفح. في هذه الحقبة، وُلدت مكتبات مثل **i18next**.

لقد حلت المشكلة بالطريقة الوحيدة الممكنة في ذلك الوقت: **القواميس أثناء وقت التشغيل**. كنت تقوم بتحميل كائن JSON ضخم في الذاكرة، وكانت دالة تبحث عن المفاتيح أثناء التنفيذ. كانت طريقة موثوقة وصريحة وتعمل في كل مكان.

تقدم سريعًا إلى اليوم. لدينا مترجمات قوية (SWC، أدوات تجميع مبنية على Rust) يمكنها تحليل أشجار البنية المجردة (AST) في غضون ميلي ثانية. هذه القوة ولدت فكرة جديدة: _لماذا ندير المفاتيح يدويًا؟ لماذا لا يستطيع المترجم فقط رؤية النص "Hello World" واستبداله لنا؟_

وهكذا وُلد التدويل المعتمد على المترجم.

> **مثال على التدويل المعتمد على المترجم:**
>
> - Paraglide (وحدات تم تقليلها باستخدام tree-shaking تقوم بترجمة كل رسالة إلى دالة ESM صغيرة بحيث يمكن لأدوات التجميع حذف اللغات والمفاتيح غير المستخدمة تلقائيًا. تقوم باستيراد الرسائل كدوال بدلاً من البحث عن المفاتيح كنصوص.)
> - LinguiJS (مترجم من الماكرو إلى الدالة يعيد كتابة ماكرو الرسائل مثل `<Trans>` إلى استدعاءات دوال جافاسكريبت عادية أثناء وقت البناء. تحصل على صيغة ICU/MessageFormat مع بصمة تشغيل صغيرة جدًا.)
> - Lingo.dev (يركز على أتمتة خط أنابيب التوطين عن طريق حقن المحتوى المترجم مباشرة أثناء بناء تطبيق React الخاص بك. يمكنه توليد الترجمات تلقائيًا باستخدام الذكاء الاصطناعي والتكامل مباشرة في CI/CD.)
> - Wuchale (معالج مسبق يركز على Svelte يقوم باستخراج النصوص المضمنة في ملفات .svelte ويحولها إلى دوال ترجمة بدون تغليف. يتجنب استخدام مفاتيح نصية، ويفصل منطق استخراج المحتوى تمامًا عن وقت تشغيل التطبيق الرئيسي.)
> - Intlayer (مترجم / أداة CLI للاستخراج تقوم بتحليل مكوناتك، وتوليد قواميس ذات أنواع، ويمكنها اختياريًا إعادة كتابة الكود لاستخدام محتوى Intlayer صريح. الهدف هو استخدام المترجم للسرعة مع الحفاظ على جوهر إعلاني مستقل عن الإطار.)

> **مثال على التوطين الإعلاني:**
>
> - i18next / react-i18next / next-i18next (المعيار الصناعي الناضج الذي يستخدم قواميس JSON وقت التشغيل ونظام إضافات واسع)
> - react-intl (جزء من مكتبة FormatJS، يركز على صياغة رسائل ICU القياسية وتنسيق البيانات الصارم)
> - next-intl (محسّن خصيصًا لـ Next.js مع تكامل مع App Router ومكونات React Server)
> - vue-i18n / @nuxt/i18n (الحل القياسي في نظام Vue البيئي الذي يقدم كتل ترجمة على مستوى المكونات وتكامل تفاعلي محكم)
> - svelte-i18n (غلاف خفيف حول مخازن Svelte للترجمات التفاعلية وقت التشغيل)
> - angular-translate (مكتبة الترجمة الديناميكية القديمة التي تعتمد على البحث عن المفاتيح وقت التشغيل بدلاً من الدمج أثناء البناء)
> - angular-i18n (النهج الأصلي لـ Angular المسبق للوقت الذي يدمج ملفات XLIFF مباشرة في القوالب أثناء البناء)
> - Tolgee (يجمع بين الكود التصريحي وSDK ضمن السياق لتحرير "انقر للترجمة" مباشرة في واجهة المستخدم)
> - Intlayer (نهج لكل مكون، يستخدم ملفات إعلانات المحتوى التي تمكّن من tree-shaking أصلي والتحقق من TypeScript)

## مترجم Intlayer

على الرغم من أن **Intlayer** هو حل يشجع أساسًا على **النهج التصريحي** لمحتواك، إلا أنه يتضمن مترجمًا للمساعدة في تسريع التطوير أو تسهيل النماذج الأولية السريعة.

يقوم مترجم Intlayer بتصفح شجرة البنية المجردة (AST) لمكونات React أو Vue أو Svelte الخاصة بك، بالإضافة إلى ملفات JavaScript/TypeScript الأخرى. دوره هو اكتشاف السلاسل النصية المضمنة واستخراجها إلى إعلانات `.content` مخصصة.

> لمزيد من التفاصيل، اطلع على الوثائق: [وثائق مترجم Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/compiler.md)

## جاذبية المترجم (النهج "السحري")

هناك سبب يجعل هذا النهج الجديد شائعًا. بالنسبة للمطور، التجربة مذهلة.

### 1. السرعة و"التدفق"

عندما تكون في حالة تركيز، التوقف للتفكير في اسم متغير دلالي (`home_hero_title_v2`) يكسر تدفقك. مع نهج المترجم، تكتب `<p>Welcome back</p>` وتستمر في العمل. الاحتكاك معدوم.

### 2. مهمة إنقاذ التراث

تخيل أنك ترث قاعدة كود ضخمة تحتوي على 5000 مكون وبدون أي ترجمات. إعادة تجهيز هذا النظام باستخدام نظام مفاتيح يدوي هو كابوس يستمر لأشهر. أداة تعتمد على المترجم تعمل كاستراتيجية إنقاذ، حيث تستخرج آلاف السلاسل النصية فورًا دون الحاجة إلى لمس أي ملف يدويًا.

### 3. عصر الذكاء الاصطناعي

هذه ميزة حديثة لا ينبغي تجاهلها. مساعدو البرمجة بالذكاء الاصطناعي (مثل Copilot أو ChatGPT) يولدون بشكل طبيعي JSX/HTML قياسي. هم لا يعرفون مخطط مفاتيح الترجمة الخاص بك.

- **إعلاني:** عليك إعادة كتابة مخرجات الذكاء الاصطناعي لاستبدال النص بالمفاتيح.
- **المترجم:** تقوم بنسخ ولصق كود الذكاء الاصطناعي، ويعمل مباشرة.

## التحقق من الواقع: لماذا "السحر" خطير

بينما تبدو "السحرية" جذابة، إلا أن التجريد يتسرب. الاعتماد على أداة بناء لفهم نية الإنسان يُدخل هشاشة معمارية.

### هشاشة الاستدلال (لعبة التخمين)

يجب على المترجم أن يخمن ما هو المحتوى وما هو الكود. هذا يؤدي إلى حالات حافة حيث ينتهي بك الأمر إلى "مقاتلة" الأداة.

ضع في اعتبارك هذه السيناريوهات:

- هل يتم استخراج `<span className="active"></span>`؟ (إنها سلسلة نصية، لكنها على الأرجح فئة).
- هل يتم استخراج `<span status="pending"></span>`؟ (إنها قيمة خاصية).
- هل يتم استخراج `<span>{"Hello World"}</span>`؟ (إنها تعبير جافاسكريبت).
- هل يتم استخراج `<span>Hello {name}. How are you?</span>`؟ (التضمين معقد).
- هل يتم استخراج `<span aria-label="Image of cat"></span>`؟ (سمات الوصول تحتاج إلى ترجمة).
- هل يتم استخراج `<span data-testid="my-element"></span>`؟ (يجب عدم ترجمة معرفات الاختبار).
- هل يتم استخراج `<MyComponent errorMessage="An error occurred" />`؟
- هل يتم استخراج `<p>This is a paragraph{" "}\n containing multiple lines</p>`؟
- هل يتم استخراج نتيجة الدالة `<p>{getStatusMessage()}</p>`؟
- هل يتم استخراج `<div>{isLoading ? "The page is loading" : <MyComponent/>} </div>`؟
- هل يتم استخراج معرف منتج مثل `<span>AX-99</span>`؟

في النهاية، ستضطر إلى إضافة تعليقات محددة (مثل `// ignore-translation`، أو خصائص محددة مثل `data-compiler-ignore="true"`) لمنع ذلك من كسر منطق تطبيقك.

### كيف يتعامل Intlayer مع هذه التعقيدات؟

تستخدم Intlayer نهجًا مختلطًا لاكتشاف ما إذا كان يجب استخراج حقل للترجمة، مع محاولة تقليل الإيجابيات الكاذبة:

1.  **تحليل AST:** يتحقق من نوع العنصر (مثل التمييز بين `reactNode` أو `label` أو خاصية `title`).
2.  **التعرف على الأنماط:** يكتشف ما إذا كانت السلسلة تبدأ بحرف كبير أو تحتوي على مسافات، مما يشير إلى أنها على الأرجح نص قابل للقراءة من قبل الإنسان بدلاً من معرف كود.

### الحد الصعب للبيانات الديناميكية

يعتمد استخراج المترجم على **التحليل الثابت**. يجب أن يرى السلسلة الحرفية في الكود الخاص بك لتوليد معرف ثابت.
إذا كانت واجهة برمجة التطبيقات (API) الخاصة بك تُرجع سلسلة رمز خطأ مثل `server_error`، فلا يمكنك ترجمتها باستخدام المترجم (compiler) لأن المترجم لا يعرف بوجود هذه السلسلة أثناء وقت البناء. ستضطر إلى بناء نظام ثانوي "للوقت التشغيلي فقط" خصيصًا للبيانات الديناميكية.

### نقص التجزئة (chunking)

بعض المترجمات لا تقوم بتجزئة الترجمات حسب الصفحة. إذا كان المترجم الخاص بك يُنتج ملف JSON كبير لكل لغة (مثل `./lang/en.json`، `./lang/fr.json`، إلخ)، فمن المحتمل أن ينتهي بك الأمر بتحميل محتوى من جميع صفحاتك لصفحة واحدة فقط يتم زيارتها. أيضًا، من المحتمل أن يتم تهيئة كل مكون يستخدم المحتوى الخاص بك بمحتوى أكثر بكثير مما هو ضروري، مما قد يسبب مشاكل في الأداء.

كن حذرًا أيضًا بشأن تحميل ترجماتك بشكل ديناميكي. إذا لم يتم ذلك، فستقوم بتحميل محتوى لجميع اللغات بالإضافة إلى اللغة الحالية.

> لتوضيح المشكلة، تخيل موقعًا يحتوي على 10 صفحات و10 لغات (جميعها فريدة بنسبة 100%). ستقوم بتحميل محتوى لـ 99 صفحة إضافية (10 × 10 - 1).

### "انفجار القطع" وشلالات الشبكة

لحل مشكلة تقسيم القطع، تقدم بعض الحلول تقسيمًا حسب المكون، أو حتى حسب المفتاح. ومع ذلك، فإن المشكلة تُحل جزئيًا فقط. النقطة التسويقية لهذه الحلول غالبًا ما تكون "محتواك يتم تنظيفه من غير المستخدم."

في الواقع، إذا قمت بتحميل المحتوى بشكل ثابت، فإن حلك سيقوم بتنظيف المحتوى غير المستخدم، لكنك ستظل تحصل على محتوى من جميع اللغات محمّلًا مع تطبيقك.

فلماذا لا تقوم بتحميله ديناميكيًا؟ نعم، في هذه الحالة ستقوم بتحميل أكثر من المحتوى الضروري، لكن هذا ليس بدون مقايضات.

تحميل المحتوى ديناميكيًا يعزل كل قطعة من المحتوى في جزء خاص بها، والذي سيتم تحميله فقط عند عرض المكون. هذا يعني أنك ستقوم بعمل طلب HTTP واحد لكل كتلة نصية. هل لديك 1000 كتلة نصية في صفحتك؟ → 1000 طلب HTTP إلى خوادمك. وللحد من الضرر وتحسين وقت العرض الأول لتطبيقك، ستحتاج إلى إدخال عدة حدود Suspense أو محملات Skeleton.

> ملاحظة: حتى مع Next.js و SSR، ستظل مكوناتك مروية (hydrated) بعد التحميل، لذا ستظل طلبات HTTP تتم.

الحل؟ اعتماد حل يسمح بالإعلان عن محتوى محدود النطاق، كما يفعل `i18next`، `next-intl`، أو `intlayer`.

> ملاحظة: يتطلب `i18next` و `next-intl` منك إدارة استيراد مساحة الأسماء / الرسائل يدويًا لكل صفحة لتحسين حجم الحزمة الخاصة بك. يجب عليك استخدام محلل الحزم مثل `rollup-plugin-visualizer` (vite)، `@next/bundle-analyzer` (next.js)، أو `webpack-bundle-analyzer` (React CRA / Angular / إلخ) لاكتشاف ما إذا كنت تلوث حزمة التطبيق بترجمات غير مستخدمة.

### العبء على أداء وقت التشغيل

لجعل الترجمات تفاعلية (حتى يتم تحديثها فورًا عند تبديل اللغات)، غالبًا ما يقوم المترجم بحقن خطاطيف إدارة الحالة في كل مكون.

- **التكلفة:** إذا قمت بعرض قائمة تحتوي على 5000 عنصر، فأنت تقوم بتهيئة 5000 خطاف `useState` و `useEffect` فقط للنصوص. يجب على React التعرف على جميع المستهلكين الخمسة آلاف وإعادة عرضهم في نفس الوقت. هذا يسبب حظرًا كبيرًا في "الخيط الرئيسي"، مما يؤدي إلى تجميد واجهة المستخدم أثناء التبديل. هذا يستهلك الذاكرة ودورات وحدة المعالجة المركزية التي توفرها المكتبات التصريحية (التي تستخدم عادة مزود Context واحد).

> لاحظ أن المشكلة مشابهة في أطر عمل أخرى غير React.

## الفخ: القفل مع البائع

كن حذرًا عند اختيار حل i18n يسمح باستخراج أو ترحيل مفاتيح الترجمة.

في حالة استخدام مكتبة تصريحية، يحتوي كود المصدر الخاص بك صراحةً على نية الترجمة الخاصة بك: هذه هي المفاتيح الخاصة بك، وأنت تتحكم بها. إذا أردت تغيير المكتبات، فعادةً ما تحتاج فقط إلى تحديث الاستيراد.

مع نهج المترجم، قد يكون كود المصدر الخاص بك مجرد نص إنجليزي عادي، بدون أي أثر لمنطق الترجمة: كل شيء مخفي في تكوين أداة البناء. إذا أصبح ذلك المكون الإضافي غير مدعوم أو أردت تغيير الحلول، قد تجد نفسك عالقًا. لا توجد طريقة سهلة لـ "الإخراج": لا توجد مفاتيح قابلة للاستخدام في كودك، وقد تحتاج إلى إعادة توليد جميع ترجماتك لمكتبة جديدة.

بعض الحلول تقدم أيضًا خدمات توليد الترجمة. لا مزيد من الرصيد؟ لا مزيد من الترجمات.

يقوم المترجمون غالبًا بتجزئة النص (على سبيل المثال، `"Hello World"` -> `x7f2a`). تبدو ملفات الترجمة الخاصة بك مثل `{ "x7f2a": "Hola Mundo" }`. الفخ: إذا قمت بتغيير المكتبات، فإن المكتبة الجديدة ترى `"Hello World"` وتبحث عن هذا المفتاح. لن تجده لأن ملف الترجمة الخاص بك مليء بالتجزئات (`x7f2a`).

### القفل على المنصة

من خلال اختيار نهج قائم على المترجم، تقيد نفسك بالمنصة الأساسية. على سبيل المثال، بعض المترجمين غير متاحين لجميع أدوات الحزم (مثل Vite أو Turbopack أو Metro). يمكن أن يجعل هذا عمليات النقل المستقبلية صعبة، وقد تحتاج إلى اعتماد حلول متعددة لتغطية جميع تطبيقاتك.

## الجانب الآخر: مخاطر النهج التصريحي

للنزاهة، الطريقة التصريحية التقليدية ليست مثالية أيضًا. لديها مجموعة من "الأخطاء الشائعة".

1.  **جحيم المساحات الاسمية:** غالبًا ما يتعين عليك إدارة ملفات JSON التي يجب تحميلها يدويًا (`common.json`، `dashboard.json`، `footer.json`). إذا نسيت واحدًا، يرى المستخدم المفاتيح الخام.
2.  **التحميل الزائد:** بدون تكوين دقيق، من السهل جدًا تحميل _جميع_ مفاتيح الترجمة الخاصة بك لجميع الصفحات عند التحميل الأولي، مما يؤدي إلى تضخم حجم الحزمة الخاصة بك.
3.  **انحراف التزامن:** من الشائع أن تبقى المفاتيح في ملف JSON لفترة طويلة بعد حذف المكون الذي يستخدمها. تنمو ملفات الترجمة الخاصة بك بلا حدود، مليئة بـ "مفاتيح الزومبي".

## الحل الوسيط من Intlayer

هنا تحاول أدوات مثل **Intlayer** الابتكار. يفهم Intlayer أنه بينما المجمعات قوية، فإن السحر الضمني خطير.

يقدم Intlayer نهجًا مختلطًا، يتيح لك الاستفادة من مزايا كلا النهجين: إدارة المحتوى التصريحية، والمتوافقة أيضًا مع المجمع الخاص به لتوفير وقت التطوير.

وحتى إذا لم تستخدم مترجم Intlayer، فإن Intlayer يقدم أمر `transform` (يمكن الوصول إليه أيضًا باستخدام امتداد VSCode). بدلاً من القيام بالسحر فقط في خطوة البناء المخفية، يمكنه فعليًا **إعادة كتابة كود المكون الخاص بك**. يقوم بمسح نصك ويستبدله بإعلانات محتوى صريحة في قاعدة الكود الخاصة بك.

هذا يمنحك أفضل ما في العالمين:

1.  **الدقة:** تحتفظ بترجماتك قريبة من مكوناتك (مما يحسن من التجزئة وإزالة الشجر غير المستخدم).
2.  **الأمان:** تصبح الترجمة كودًا صريحًا، وليس سحرًا مخفيًا في وقت البناء.
3.  **عدم القفل:** نظرًا لأن الكود يتم تحويله إلى هيكل إعلاني داخل مستودعك، يمكنك بسهولة الضغط على Tab، أو استخدام مساعد IDE الخاص بك (copilot)، لتوليد إعلانات المحتوى الخاصة بك، أنت لا تخفي المنطق في مكون إضافي لـ webpack.

## الخلاصة

فأي خيار يجب أن تختار؟

**إذا كنت تبني MVP، أو تريد التحرك بسرعة:**
النهج المعتمد على المترجم هو خيار صالح. يسمح لك بالتحرك بسرعة كبيرة. لا تحتاج للقلق بشأن هيكل الملفات أو المفاتيح. فقط قم بالبناء. الدين الفني سيكون مشكلة لـ "أنت في المستقبل".

**إذا كنت مطورًا مبتدئًا، أو لا تهتم بالتحسين:**
إذا كنت تريد أقل إدارة يدوية، فمن المحتمل أن يكون النهج المعتمد على المترجم هو الأفضل. لن تحتاج إلى التعامل مع المفاتيح أو ملفات الترجمة بنفسك - فقط اكتب النص، والمترجم يقوم بالباقي تلقائيًا. هذا يقلل من جهد الإعداد والأخطاء الشائعة في التدويل المرتبطة بالخطوات اليدوية.

**إذا كنت تقوم بتدويل مشروع قائم يحتوي بالفعل على آلاف المكونات التي تحتاج لإعادة هيكلة:**
يمكن أن يكون النهج القائم على المترجم خيارًا عمليًا هنا. يمكن لمرحلة الاستخراج الأولية أن توفر أسابيع أو شهورًا من العمل اليدوي. ومع ذلك، فكر في استخدام أداة مثل أمر `transform` في Intlayer، والتي يمكنها استخراج السلاسل النصية وتحويلها إلى إعلانات محتوى صريحة وتصريحية. هذا يمنحك سرعة الأتمتة مع الحفاظ على أمان وقابلية نقل النهج التصريحي. تحصل على أفضل ما في العالمين: هجرة أولية سريعة دون ديون معمارية طويلة الأمد.

**إذا كنت تبني تطبيقًا احترافيًا من الدرجة المؤسسية:**
السحر عادةً ما يكون فكرة سيئة. أنت بحاجة إلى التحكم.

- تحتاج إلى التعامل مع البيانات الديناميكية من الخلفيات.
- تحتاج إلى ضمان الأداء على الأجهزة منخفضة المواصفات (تجنب انفجارات الـ hook).
- تحتاج إلى التأكد من أنك لست مقيدًا بأداة بناء معينة إلى الأبد.

بالنسبة للتطبيقات المهنية، تظل **إدارة المحتوى التصريحية** (مثل Intlayer أو المكتبات المعروفة) هي المعيار الذهبي. فهي تفصل بين اهتماماتك، وتحافظ على نظافة هيكلك المعماري، وتضمن أن قدرة تطبيقك على التحدث بعدة لغات لا تعتمد على "صندوق أسود" يقوم المترجم بتخمين نواياك.
