تلقي إشعارات حول الإصدارات القادمة من Intlayer
    إنشاء:2025-08-23آخر تحديث:2025-09-29

    next-i18next مقابل next-intl مقابل intlayer | التدويل في Next.js (i18n)

    لنلقي نظرة على أوجه التشابه والاختلاف بين ثلاثة خيارات للتدويل في Next.js: next-i18next، next-intl، و Intlayer.

    هذا ليس درسًا كاملاً. إنها مقارنة لمساعدتك في الاختيار.

    نركز على موجه التطبيقات في Next.js 13+ (مع مكونات خادم React) ونقيم:

    1. البنية والتنظيم المحتوى
    2. TypeScript والأمان
    3. معالجة الترجمات المفقودة
    4. التوجيه والوسيطات
    5. الأداء وسلوك التحميل
    6. تجربة المطور (DX)، الأدوات والصيانة
    7. تحسين محركات البحث (SEO) وقابلية التوسع في المشاريع الكبيرة
    ملخص: يمكن لجميع الثلاثة تعريب تطبيق Next.js. إذا كنت تريد محتوى مخصص للمكونات، أنواع TypeScript صارمة، فحوصات المفاتيح المفقودة أثناء البناء، قواميس مُحسّنة بالتخلص من الشجر غير المستخدم، وموجه تطبيقات من الدرجة الأولى + مساعدات SEO، فإن Intlayer هو الخيار الأكثر اكتمالًا وحداثة.
    من الالتباسات الشائعة بين المطورين هو الاعتقاد بأن next-intl هو نسخة Next.js من react-intl. هذا غير صحيح — فـ next-intl تتم صيانته بواسطة Amann، بينما react-intl تتم صيانته بواسطة FormatJS.

    باختصار

    • next-intl - تنسيق رسائل خفيف الوزن وبسيط مع دعم قوي لـ Next.js. الكتالوجات المركزية شائعة؛ تجربة المطور بسيطة، لكن الأمان والصيانة على نطاق واسع تبقى في الغالب مسؤوليتك.
    • next-i18next - i18next في هيئة Next.js. نظام بيئي ناضج وميزات عبر الإضافات (مثل ICU)، لكن التهيئة قد تكون مطولة وتميل الكتالوجات إلى المركزية مع نمو المشاريع.
    • Intlayer - نموذج محتوى يركز على المكونات لـ Next.js، كتابة صارمة بـ TS، فحوصات وقت البناء، إزالة الشيفرة غير المستخدمة (tree-shaking)، وسائط مدمجة ومساعدات SEO، محرر/نظام إدارة محتوى بصري اختياري، وترجمات بمساعدة الذكاء الاصطناعي.

    Library GitHub Stars Total Commits Last Commit First Version NPM Version NPM Downloads
    aymericzip/intlayer GitHub Repo stars GitHub commit activity Last Commit April 2024 npm npm downloads
    amannn/next-intl GitHub Repo stars GitHub commit activity Last Commit Nov 2020 npm npm downloads
    i18next/i18next GitHub Repo stars GitHub commit activity Last Commit Jan 2012 npm npm downloads
    i18next/next-i18next GitHub Repo stars GitHub commit activity Last Commit Nov 2018 npm npm downloads
    يتم تحديث الشارات تلقائيًا. ستختلف اللقطات مع مرور الوقت.

    مقارنة الميزات جنبًا إلى جنب (مركزة على Next.js)

    الميزة next-intlayer (Intlayer) next-intl next-i18next
    الترجمات بالقرب من المكونات ✅ نعم، المحتوى موضوع بجانب كل مكون ❌ لا ❌ لا
    تكامل TypeScript ✅ متقدم، أنواع صارمة مولدة تلقائيًا ✅ جيد ⚠️ أساسي
    كشف الترجمات المفقودة ✅ تمييز أخطاء TypeScript وتحذير/خطأ أثناء وقت البناء ⚠️ تراجع في وقت التشغيل ⚠️ تراجع في وقت التشغيل
    المحتوى الغني (JSX/Markdown/المكونات) ✅ دعم مباشر ❌ غير مصمم للعقد الغنية ⚠️ محدود
    الترجمة المدعومة بالذكاء الاصطناعي ✅ نعم، يدعم عدة مزودي ذكاء اصطناعي. يمكن استخدامه باستخدام مفاتيح API الخاصة بك. يأخذ في الاعتبار سياق تطبيقك ونطاق المحتوى ❌ لا ❌ لا
    المحرر المرئي ✅ نعم، محرر مرئي محلي + نظام إدارة محتوى اختياري؛ يمكنه إخراج محتوى قاعدة الشيفرة؛ قابل للتضمين ❌ لا / متوفر عبر منصات التوطين الخارجية ❌ لا / متوفر عبر منصات التوطين الخارجية
    التوجيه المحلي ✅ نعم، يدعم المسارات المحلية مباشرة (يعمل مع Next.js و Vite) ✅ مدمج، يدعم App Router جزء [locale] ✅ مدمج
    توليد المسارات الديناميكية ✅ نعم ✅ نعم ✅ نعم
    التعددية (جمع الكلمات) ✅ أنماط قائمة على التعداد ✅ جيد ✅ جيد
    تنسيق (التواريخ، الأرقام، العملات) ✅ منسقات محسّنة (Intl في الخلفية) ✅ جيد (مساعدات Intl) ✅ جيد (مساعدات Intl)
    تنسيق المحتوى ✅ .tsx، .ts، .js، .json، .md، .txt، (.yaml قيد العمل) ✅ .json، .js، .ts ⚠️ .json
    دعم ICU ⚠️ جاري العمل عليه ✅ نعم ⚠️ عبر الإضافة (i18next-icu)
    مساعدو تحسين محركات البحث (hreflang، خريطة الموقع) ✅ أدوات مدمجة: مساعدات لخريطة الموقع، robots.txt، البيانات الوصفية ✅ جيد ✅ جيد
    النظام البيئي / المجتمع ⚠️ أصغر ولكن ينمو بسرعة ويتفاعل ✅ جيد ✅ جيد
    التصيير على جانب الخادم ومكونات الخادم ✅ نعم، مُبسّط للتصيير على جانب الخادم / مكونات خادم React ⚠️ مدعوم على مستوى الصفحة ولكن يحتاج إلى تمرير دوال t على شجرة المكونات لمكونات الخادم الفرعية ⚠️ مدعوم على مستوى الصفحة ولكن يحتاج إلى تمرير دوال t على شجرة المكونات لمكونات الخادم الفرعية
    إزالة الشيفرة غير المستخدمة (تحميل المحتوى المستخدم فقط) ✅ نعم، لكل مكون أثناء وقت البناء عبر إضافات Babel/SWC ⚠️ جزئي ⚠️ جزئي
    التحميل الكسول ✅ نعم، لكل لغة / لكل قاموس ✅ نعم (لكل مسار/لكل لغة)، يحتاج إلى إدارة مساحة الأسماء ✅ نعم (لكل مسار/لكل لغة)، يحتاج إلى إدارة مساحة الأسماء
    تنظيف المحتوى غير المستخدم ✅ نعم، لكل قاموس أثناء وقت البناء ❌ لا، يمكن إدارته يدويًا باستخدام إدارة المساحات الاسمية ❌ لا، يمكن إدارته يدويًا باستخدام إدارة المساحات الاسمية
    إدارة المشاريع الكبيرة ✅ يشجع على التصميم المعياري، مناسب لأنظمة التصميم ✅ معياري مع الإعداد ✅ معياري مع الإعداد
    اختبار الترجمات المفقودة (CLI/CI) ✅ CLI: npx intlayer content test (تدقيق مناسب لـ CI) ⚠️ غير مدمج؛ الوثائق تقترح npx @lingual/i18n-check ⚠️ غير مدمج؛ يعتمد على أدوات i18next / وقت التشغيل saveMissing

    المقدمة

    يوفر Next.js دعمًا مدمجًا للتوجيه الدولي (مثل مقاطع اللغة). لكن هذه الميزة لا تقوم بالترجمة بمفردها. لا يزال يتعين عليك استخدام مكتبة لعرض المحتوى المحلي للمستخدمين.

    توجد العديد من مكتبات i18n، ولكن في عالم Next.js اليوم، هناك ثلاث مكتبات تكتسب شعبية: next-i18next، next-intl، و Intlayer.


    الهندسة والقابلية للتوسع

    • next-intl / next-i18next: تعتمد بشكل افتراضي على كتالوجات مركزية لكل لغة (بالإضافة إلى مساحات الأسماء في i18next). تعمل بشكل جيد في البداية، لكنها غالبًا ما تصبح مساحة مشتركة كبيرة مع زيادة الترابط وتغير المفاتيح.
    • Intlayer: تشجع على استخدام قواميس لكل مكون (أو لكل ميزة) متمركزة مع الكود الذي تخدمه. هذا يقلل من العبء المعرفي، ويسهل تكرار/ترحيل أجزاء واجهة المستخدم، ويقلل من النزاعات بين الفرق. المحتوى غير المستخدم يكون أسهل في الاكتشاف والحذف بشكل طبيعي.

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


    أحجام الحزم والاعتمادات

    بعد بناء التطبيق، الحزمة هي جافا سكريبت التي سيقوم المتصفح بتحميلها لعرض الصفحة. لذلك، حجم الحزمة مهم لأداء التطبيق.

    هناك مكونان مهمان في سياق حزمة تطبيق متعدد اللغات:

    • كود التطبيق
    • المحتوى الذي يتم تحميله بواسطة المتصفح

    كود التطبيق

    أهمية كود التطبيق ضئيلة في هذه الحالة. جميع الحلول الثلاثة تدعم تقنية tree-shaking، مما يعني أن الأجزاء غير المستخدمة من الكود لا تُدرج في الحزمة.

    إليك مقارنة لحجم حزمة جافا سكريبت التي يتم تحميلها بواسطة المتصفح لتطبيق متعدد اللغات مع الحلول الثلاثة.

    إذا لم نحتاج إلى أي مُنسق في التطبيق، فإن قائمة الدوال المُصدرة بعد تطبيق tree-shaking ستكون:

    • next-intlayer: useIntlayer, useLocale, NextIntlClientProvider، (حجم الحزمة هو 180.6 كيلوبايت -> 78.6 كيلوبايت (gzip))
    • next-intl: useTranslations, useLocale, NextIntlClientProvider، (حجم الحزمة هو 101.3 كيلوبايت -> 31.4 كيلوبايت (gzip))
    • next-i18next: useTranslation, useI18n, I18nextProvider، (حجم الحزمة هو 80.7 كيلوبايت -> 25.5 كيلوبايت (gzip))

    هذه الدوال هي مجرد أغلفة حول سياق/حالة React، لذا فإن التأثير الكلي لمكتبة i18n على حجم الحزمة هو ضئيل.

    Intlayer أكبر قليلاً من next-intl و next-i18next لأنه يتضمن منطقًا أكثر في دالة useIntlayer. هذا مرتبط بالتكامل مع markdown و intlayer-editor.

    المحتوى والترجمات

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

    المستخدم الذي يرغب في زيارة صفحة /fr/about سيقوم بتحميل محتوى صفحة واحدة بلغة معينة. تجاهل تحسين المحتوى يعني تحميل 8200% ((1 + (((10 صفحات - 1) × (10 لغات - 1)))) × 100) من محتوى التطبيق بشكل غير ضروري. هل ترى المشكلة؟ حتى لو كان هذا المحتوى نصًا فقط، وبينما من المحتمل أنك تفضل التفكير في تحسين صور موقعك، فإنك ترسل محتوى غير مفيد عبر العالم وتجعل أجهزة المستخدمين تعالجه دون فائدة.

    مسألتان مهمتان:

    • التقسيم حسب المسار:

      إذا كنت في صفحة /about، لا أريد تحميل محتوى صفحة /home
    • التقسيم حسب اللغة:

      إذا كنت في صفحة /fr/about، لا أريد تحميل محتوى صفحة /en/about

    مرة أخرى، كل الحلول الثلاثة تدرك هذه القضايا وتسمح بإدارة هذه التحسينات. الفرق بين الحلول الثلاثة هو تجربة المطور (DX).

    يستخدم كل من next-intl و next-i18next نهجًا مركزيًا لإدارة الترجمات، مما يسمح بتقسيم ملفات JSON حسب اللغة وحسب الملفات الفرعية. في next-i18next، نسمي ملفات JSON "مساحات الأسماء" (namespaces)؛ بينما يسمح next-intl بإعلان الرسائل. في intlayer، نسمي ملفات JSON "القواميس" (dictionaries).

    • في حالة next-intl، مثل next-i18next، يتم تحميل المحتوى على مستوى الصفحة/التخطيط، ثم يتم تحميل هذا المحتوى في مزود السياق. هذا يعني أن المطور يجب أن يدير ملفات JSON التي سيتم تحميلها لكل صفحة يدويًا.
    في الممارسة العملية، هذا يعني أن المطورين غالبًا ما يتخطون هذا التحسين، مفضلين تحميل كل المحتوى في مزود سياق الصفحة من أجل البساطة.
    • في حالة intlayer، يتم تحميل كل المحتوى في التطبيق. ثم يتولى مكون إضافي (@intlayer/babel / @intlayer/swc) مهمة تحسين الحزمة عن طريق تحميل المحتوى المستخدم فقط في الصفحة. لذلك لا يحتاج المطور إلى إدارة القواميس التي سيتم تحميلها يدويًا. هذا يسمح بتحسين أفضل، وصيانة أفضل، ويقلل من وقت التطوير.

    مع نمو التطبيق (خاصة عندما يعمل عدة مطورين على التطبيق)، من الشائع نسيان إزالة المحتوى الذي لم يعد مستخدمًا من ملفات JSON.

    لاحظ أن جميع ملفات JSON يتم تحميلها في جميع الحالات (next-intl، next-i18next، intlayer).

    لهذا السبب، فإن نهج Intlayer أكثر كفاءة: إذا لم يعد يتم استخدام مكون ما، فلن يتم تحميل قاموسه في الحزمة.

    كيفية تعامل المكتبة مع الاستبدالات (fallbacks) أمر مهم أيضًا. لنفترض أن التطبيق باللغة الإنجليزية بشكل افتراضي، وزار المستخدم صفحة /fr/about. إذا كانت الترجمات مفقودة بالفرنسية، فسنعتبر الاستبدال باللغة الإنجليزية.

    في حالة next-intl و next-i18next، تتطلب المكتبة تحميل ملفات JSON المتعلقة باللغة الحالية، ولكن أيضًا لغة التراجع (fallback). وبالتالي، مع افتراض أن كل المحتوى قد تُرجم، ستقوم كل صفحة بتحميل محتوى غير ضروري بنسبة 100%. بالمقارنة، تقوم intlayer بمعالجة التراجع أثناء وقت بناء القاموس. لذا، ستقوم كل صفحة بتحميل المحتوى المستخدم فقط.

    فيما يلي مثال على تأثير تحسين حجم الحزمة باستخدام intlayer في تطبيق vite + react:

    الحزمة المحسنة الحزمة غير المحسنة
    حزمة محسنة حزمة غير محسنة

    تايب سكريبت والسلامة

    next-intl

    • دعم قوي لـ TypeScript، لكن المفاتيح ليست مُعرفة بدقة بشكل افتراضي؛ ستحتاج للحفاظ على أنماط الأمان يدويًا.

    next-i18next

    • تعريفات أساسية للهوكس؛ التعريف الصارم للمفاتيح يتطلب أدوات/تكوين إضافي.

    intlayer

    • ينشئ أنواعًا صارمة من المحتوى الخاص بك. الإكمال التلقائي في بيئة التطوير وأخطاء وقت الترجمة تكتشف الأخطاء الإملائية والمفاتيح المفقودة قبل النشر.

    لماذا هذا مهم: التحقق الصارم من الأنواع ينقل الأخطاء إلى اليسار (التكامل المستمر/البناء) بدلاً من اليمين (وقت التشغيل).


    التعامل مع الترجمات المفقودة

    next-intl

    • يعتمد على الاستعادات أثناء وقت التشغيل (مثل عرض المفتاح أو اللغة الافتراضية). البناء لا يفشل.

    next-i18next

    • يعتمد على الاستعادات أثناء وقت التشغيل (مثل عرض المفتاح أو اللغة الافتراضية). البناء لا يفشل.

    intlayer

    • الكشف أثناء وقت البناء مع تحذيرات/أخطاء للمواقع أو المفاتيح المفقودة.

    لماذا هذا مهم: اكتشاف الفجوات أثناء البناء يمنع ظهور "سلاسل غامضة" في الإنتاج ويتماشى مع قواعد الإصدار الصارمة.


    التوجيه، الوسيط واستراتيجية عناوين URL

    next-intl

    • يعمل مع توجيه Next.js المحلي على App Router.

    next-i18next

    • يعمل مع توجيه Next.js المحلي على App Router.

    intlayer

    • كل ما سبق، بالإضافة إلى وسيط i18n (اكتشاف اللغة عبر الرؤوس/الكوكيز) ومساعدين لإنشاء عناوين URL محلية ووسوم <link rel="alternate" hreflang="…">.

    لماذا هذا مهم: تقليل طبقات الربط المخصصة؛ تجربة مستخدم متسقة وتحسين SEO نظيف عبر اللغات.


    توافق مكونات الخادم (RSC)

    next-intl

    • يدعم Next.js 13+. غالبًا ما يتطلب تمرير دوال الترجمة/المنسقات عبر شجرة المكونات في الإعدادات المختلطة.

    next-i18next

    • يدعم Next.js 13+. قيود مماثلة مع تمرير أدوات الترجمة عبر الحدود.

    intlayer

    • يدعم Next.js 13+ ويسهل الحد الفاصل بين الخادم/العميل من خلال واجهة برمجة تطبيقات متسقة ومزودين موجهين لـ RSC، متجنبًا نقل أدوات التنسيق أو دوال الترجمة.

    لماذا هذا مهم: نموذج ذهني أنظف وحالات حافة أقل في الأشجار الهجينة.


    تجربة المطور، الأدوات والصيانة

    next-intl

    • غالبًا ما يُستخدم مع منصات التوطين الخارجية وسير العمل التحريري.

    next-i18next

    • غالبًا ما يُستخدم مع منصات التوطين الخارجية وسير العمل التحريري.

    intlayer

    • يوفر محررًا بصريًا مجانيًا ونظام إدارة محتوى اختياري (متوافق مع Git أو خارجي)، بالإضافة إلى امتداد VSCode وترجمات بمساعدة الذكاء الاصطناعي باستخدام مفاتيح المزود الخاصة بك.

    لماذا هذا مهم: يقلل من تكلفة العمليات ويقصر دورة التواصل بين المطورين ومؤلفي المحتوى.

    التكامل مع منصات الترجمة (TMS)

    تعتمد المؤسسات الكبيرة غالبًا على أنظمة إدارة الترجمة (TMS) مثل Crowdin، Phrase، Lokalise، Localizely، أو Localazy.

    • لماذا تهتم الشركات

      • التعاون والأدوار: يشارك عدة أطراف: المطورون، مدراء المنتجات، المترجمون، المراجعون، فرق التسويق.
      • الحجم والكفاءة: الترجمة المستمرة، والمراجعة في السياق.
    • next-intl / next-i18next

      • عادةً ما تستخدم كتالوجات JSON مركزية، لذا فإن التصدير/الاستيراد مع أنظمة إدارة الترجمة (TMS) يكون بسيطًا.
      • أنظمة بيئية ناضجة وأمثلة/تكاملات للمنصات المذكورة أعلاه.
    • Intlayer

      • يشجع على القواميس اللامركزية لكل مكون ويدعم محتوى TypeScript/TSX/JS/JSON/MD.
      • هذا يحسن من التجزئة في الكود، لكنه قد يجعل تكامل أنظمة إدارة الترجمة (TMS) السهل الاستخدام أكثر صعوبة عندما يتوقع الأداة ملفات JSON مركزية ومسطحة.
      • يوفر Intlayer بدائل: ترجمات بمساعدة الذكاء الاصطناعي (باستخدام مفاتيح المزود الخاصة بك)، ومحرر مرئي/نظام إدارة محتوى، وعمليات CLI/CI لالتقاط وملء الفجوات.
    ملاحظة: next-intl و i18next يقبلان أيضًا كتالوجات TypeScript. إذا كان فريقك يخزن الرسائل في ملفات .ts أو يوزعها حسب الميزة، فقد تواجه احتكاكًا مشابهًا مع نظام إدارة الترجمة (TMS). ومع ذلك، تبقى العديد من إعدادات next-intl مركزية في مجلد locales/، مما يجعل إعادة هيكلتها إلى JSON لـ TMS أسهل قليلاً.

    تجربة المطور

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

    هيكل التطبيق

    هيكل التطبيق مهم لضمان سهولة صيانة قاعدة الشيفرة الخاصة بك.

    .├── i18n.ts├── locales│   ├── en│   │  ├── home.json│   │  └── navbar.json│   ├── fr│   │  ├── home.json│   │  └── navbar.json│   └── es│      ├── home.json│      └── navbar.json└── src    ├── middleware.ts    ├── app    │   ├── i18n    │   │   └── server.ts    │   └── [locale]    │       └── home.tsx    └── components        └── Navbar            └── index.tsx

    المقارنة

    • next-intl / next-i18next: كتالوجات مركزية (JSON؛ مساحات الأسماء/الرسائل). هيكل واضح، يتكامل جيدًا مع منصات الترجمة، لكنه قد يؤدي إلى المزيد من التعديلات عبر الملفات مع نمو التطبيقات.
    • Intlayer: قواميس .content.{ts|js|json} لكل مكون متواجدة بجانب المكونات. يسهل إعادة استخدام المكونات والتفكير المحلي؛ يضيف ملفات ويعتمد على أدوات وقت البناء.

    الإعداد وتحميل المحتوى

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

    src/i18n.ts
    import { getRequestConfig } from "next-intl/server";import { notFound } from "next/navigation";export const locales = ["en", "fr", "es"] as const;export const defaultLocale = "en" as const;async function loadMessages(locale: string) {  // Load only the namespaces your layout/pages need  const [common, about] = await Promise.all([    import(`../locales/${locale}/common.json`).then((m) => m.default),    import(`../locales/${locale}/about.json`).then((m) => m.default),  ]);  return { common, about } as const;}export default getRequestConfig(async ({ locale }) => {  if (!locales.includes(locale as any)) notFound();  return {    messages: await loadMessages(locale),  };});
    src/app/[locale]/layout.tsx
    import type { ReactNode } from "react";import { locales } from "@/i18n";import {  getLocaleDirection,  unstable_setRequestLocale,} from "next-intl/server";export const dynamic = "force-static";export function generateStaticParams() {  return locales.map((locale) => ({ locale }));}export default async function LocaleLayout({  children,  params,}: {  children: ReactNode;  params: Promise<{ locale: string }>;}) {  const { locale } = await params;  // Set the active request locale for this server render (RSC)  unstable_setRequestLocale(locale);  const dir = getLocaleDirection(locale);  return (    <html lang={locale} dir={dir}>      <body>{children}</body>    </html>  );}
    src/app/[locale]/about/page.tsx
    import { getTranslations, getMessages, getFormatter } from "next-intl/server";import { NextIntlClientProvider } from "next-intl";import pick from "lodash/pick";import ServerComponent from "@/components/ServerComponent";import ClientComponentExample from "@/components/ClientComponentExample";export const dynamic = "force-static";export default async function AboutPage({  params,}: {  params: Promise<{ locale: string }>;}) {  const { locale } = await params;  // Messages are loaded server-side. Push only what's needed to the client.  const messages = await getMessages();  const clientMessages = pick(messages, ["common", "about"]);  // Strictly server-side translations/formatting  const tAbout = await getTranslations("about");  const tCounter = await getTranslations("about.counter");  const format = await getFormatter();  const initialFormattedCount = format.number(0);  return (    <NextIntlClientProvider locale={locale} messages={clientMessages}>      <main>        <h1>{tAbout("title")}</h1>        <ClientComponentExample />        <ServerComponent          formattedCount={initialFormattedCount}          label={tCounter("label")}          increment={tCounter("increment")}        />      </main>    </NextIntlClientProvider>  );}

    مقارنة

    جميع الثلاثة تدعم تحميل المحتوى حسب اللغة والمزودين.

    • مع next-intl/next-i18next، عادةً ما تقوم بتحميل الرسائل/المساحات المختارة لكل مسار وتضع الموفرين حيثما دعت الحاجة.

    • مع Intlayer، يتم إضافة تحليل وقت البناء لاستنتاج الاستخدام، مما يمكن أن يقلل من التوصيل اليدوي وقد يسمح بموفر جذر واحد.

    اختر بين التحكم الصريح والأتمتة بناءً على تفضيل الفريق.

    الاستخدام في مكون العميل

    لنأخذ مثالاً على مكون عميل يعرض عدادًا.

    الترجمات (shape reused; load them into next-intl messages as you prefer)

    locales/en/about.json
    {  "counter": {    "label": "Counter",    "increment": "Increment"  }}
    locales/fr/about.json
    {  "counter": {    "label": "Compteur",    "increment": "Incrémenter"  }}

    مكون العميل

    src/components/ClientComponentExample.tsx
    "use client";import React, { useState } from "react";import { useTranslations, useFormatter } from "next-intl";const ClientComponentExample = () => {  // نطاق مباشر للكائن المتداخل  const t = useTranslations("about.counter");  const format = useFormatter();  const [count, setCount] = useState(0);  return (    <div>      <p>{format.number(count)}</p>      <button        aria-label={t("label")}        onClick={() => setCount((count) => count + 1)}      >        {t("increment")}      </button>    </div>  );};
    Don't forget to add "about" message on the page client message

    المقارنة

    • تنسيق الأرقام

      • next-i18next: لا يوجد useNumber؛ يستخدم Intl.NumberFormat (أو i18next-icu).
      • next-intl: useFormatter().number(value).
      • Intlayer: useNumber() مدمج.
    • المفاتيح

      • احتفظ ببنية متداخلة (about.counter.label) وحدد نطاق الخطاف الخاص بك وفقًا لذلك (useTranslation("about") + t("counter.label") أو useTranslations("about.counter") + t("label")).
    • مواقع الملفات

      • next-i18next expects JSON in public/locales/{lng}/{ns}.json.
      • next-intl is flexible; load messages however you configure.
      • Intlayer stores content in TS/JS dictionaries and resolves by key.

    الاستخدام في مكون الخادم

    We will take the case of a UI component. This component is a server component, and should be able to be inserted as a child of a client component. (page (server component) -> client component -> server component). As this component can be inserted as a child of a client component, it cannot be async.

    src/components/ServerComponent.tsx
    type ServerComponentProps = {  formattedCount: string;  label: string;  increment: string;};const ServerComponent = ({  formattedCount,  label,  increment,}: ServerComponentProps) => {  return (    <div>      <p>{formattedCount}</p>      <button aria-label={label}>{increment}</button>    </div>  );};export default ServerComponent;

    As the server component cannot be async, you need to pass the translations and formatter function as props.

    In your page / layout:

    • import { getTranslations, getFormatter } from "next-intl/server";
    • const t = await getTranslations("about.counter");
    • const formatter = await getFormatter().then((formatter) => formatter.number());
    Intlayer exposes server-safe hooks via next-intlayer/server. To work, useIntlayer and useNumber use hooks-like syntax, similar to the client hooks, but depend under the hood on the server context (IntlayerServerProvider).

    البيانات الوصفية / خريطة الموقع / روبوتات البحث

    ترجمة المحتوى أمر رائع. لكن الناس عادةً ما ينسون أن الهدف الرئيسي من التدويل هو جعل موقعك الإلكتروني أكثر ظهورًا للعالم. التدويل هو رافعة مذهلة لتحسين ظهور موقعك الإلكتروني.

    Here's a list of good practices regarding multilingual SEO.

    • set hreflang meta tags in the <head> tag > It helps search engines to understand what languages are available on the page
    • list all pages translations in the sitemap.xml using http://www.w3.org/1999/xhtml XML schema >
    • do not forget to exclude prefixed pages from the robots.txt (e.g. /dashboard, and /fr/dashboard, /es/dashboard) >
    • use custom Link component to redirect to the most localized page (e.g. in french <a href="/fr/about">A propos</a> ) >

    Developers often forget to properly reference their pages across locales.

    src/app/[locale]/about/layout.tsx
    import type { Metadata } from "next";import { locales, defaultLocale } from "@/i18n";import { getTranslations } from "next-intl/server";function localizedPath(locale: string, path: string) {  return locale === defaultLocale ? path : "/" + locale + path;}export async function generateMetadata({  params,}: {  params: { locale: string };}): Promise<Metadata> {  const { locale } = params;  const t = await getTranslations({ locale, namespace: "about" });  const url = "/about";  const languages = Object.fromEntries(    locales.map((locale) => [locale, localizedPath(locale, url)])  );  return {    title: t("title"),    description: t("description"),    alternates: {      canonical: localizedPath(locale, url),      languages: { ...languages, "x-default": url },    },  };}// ... Rest of the page code
    src/app/sitemap.ts
    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const formatterLocalizedPath = (locale: string, path: string) =>  locale === defaultLocale ? origin + path : origin + "/" + locale + path;export default function sitemap(): MetadataRoute.Sitemap {  const aboutLanguages = Object.fromEntries(    locales.map((l) => [l, formatterLocalizedPath(l, "/about")])  );  return [    {      url: formatterLocalizedPath(defaultLocale, "/about"),      lastModified: new Date(),      changeFrequency: "monthly",      priority: 0.7,      alternates: { languages: aboutLanguages },    },  ];}
    src/app/robots.ts
    import type { MetadataRoute } from "next";import { locales, defaultLocale } from "@/i18n";const origin = "https://example.com";const withAllLocales = (path: string) => [  path,  ...locales    .filter((locale) => locale !== defaultLocale)    .map((locale) => "/" + locale + path),];export default function robots(): MetadataRoute.Robots {  const disallow = [    ...withAllLocales("/dashboard"),    ...withAllLocales("/admin"),  ];  return {    rules: { userAgent: "*", allow: ["/"], disallow },    host: origin,    sitemap: origin + "/sitemap.xml",  };}
    Intlayer provides a getMultilingualUrls function to generate multilingual URLs for your sitemap.

    Middleware for locale routing

    Add a middleware to handle locale detection and routing:

    src/middleware.ts
    import createMiddleware from "next-intl/middleware";import { locales, defaultLocale } from "@/i18n";export default createMiddleware({  locales: [...locales],  defaultLocale,  localeDetection: true,});export const config = {  // Skip API, Next internals and static assets  matcher: ["/((?!api|_next|.*\\..*).*)"],};

    والفائز هو…

    ليس الأمر بسيطًا. كل خيار له مزاياه وعيوبه. إليك كيف أراه:

    next-intl

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

    next-i18next

    • ناضج، مليء بالميزات، يحتوي على العديد من الإضافات المجتمعية، لكن تكلفة الإعداد أعلى. إذا كنت تحتاج إلى نظام إضافات i18next (مثل قواعد ICU المتقدمة عبر الإضافات) وكان فريقك يعرف i18next بالفعل، مع قبول المزيد من التكوين من أجل المرونة.

    Intlayer

    • مبني لـ Next.js الحديث، مع محتوى معياري، أمان نوعي، أدوات، وتقليل الكود المكرر. إذا كنت تقدر المحتوى المخصص للمكونات، TypeScript الصارم، ضمانات وقت البناء، tree-shaking، وأدوات التوجيه/SEO/المحرر المدمجة - خاصة لـ Next.js App Router، أنظمة التصميم وقواعد الشيفرة الكبيرة والمعيارية.

    إذا كنت تفضل إعدادًا بسيطًا وتقبل بعض التوصيلات اليدوية، فإن next-intl خيار جيد. إذا كنت تحتاج كل الميزات ولا تمانع التعقيد، فإن next-i18next يعمل بشكل جيد. ولكن إذا كنت تريد حلاً حديثًا وقابلًا للتوسع وذو محتوى معياري مع أدوات مدمجة، فإن Intlayer تهدف إلى تقديم ذلك لك مباشرةً من الصندوق.

    بديل لفرق المؤسسات: إذا كنت بحاجة إلى حل مثبت يعمل بشكل مثالي مع منصات التوطين المعروفة مثل Crowdin، Phrase، أو أنظمة إدارة الترجمة الاحترافية الأخرى، فكر في استخدام next-intl أو next-i18next لنظامهم البيئي الناضج والتكاملات المثبتة.
    خارطة الطريق المستقبلية: تخطط Intlayer أيضًا لتطوير إضافات تعمل فوق حلول i18next و next-intl. هذا سيمنحك مزايا Intlayer في الأتمتة، والبنية النحوية، وإدارة المحتوى مع الحفاظ على الأمان والاستقرار الذي توفره هذه الحلول المعروفة في كود التطبيق الخاص بك.

    نجوم GitHub

    نجوم GitHub هي مؤشر قوي على شعبية المشروع، وثقة المجتمع، وأهميته على المدى الطويل. وعلى الرغم من أنها ليست مقياسًا مباشرًا للجودة التقنية، إلا أنها تعكس عدد المطورين الذين يجدون المشروع مفيدًا، ويتابعون تقدمه، ومن المحتمل أن يتبنوه. لتقدير قيمة المشروع، تساعد النجوم في مقارنة الجذب بين البدائل وتوفر رؤى حول نمو النظام البيئي.

    مخطط تاريخ النجوم


    الخلاصة

    تنجح المكتبات الثلاث جميعها في التوطين الأساسي. الفرق هو كمية العمل التي يجب عليك القيام بها لتحقيق إعداد قوي وقابل للتوسع في Next.js الحديثة:

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

    راجع وثيقة "لماذا Intlayer؟" لمزيد من التفاصيل.