المؤلف:
    إنشاء:2026-09-13آخر تحديث:2026-09-13

    Lingui مقابل Intlayer | مقارنة أداء التدويل (i18n) في React وNext.js

    تعد Lingui وIntlayer المكتبتين الوحيدتين في هذا الاختبار اللتين تعتمدان على مترجم (Compiler) بدلاً من بيئة تشغيل بحتة (Pure Runtime). تستخرج Lingui الرسائل من وحدات الماكرو في وقت البناء وتقوم بتجميع الكتالوجات لكل لغة. بينما يقوم Intlayer بتجميع القواميس لكل مكون مع تقليم الشجرة (Tree-shaking) لكل لغة. نظرياً، يجب أن تكون النتائج متقاربة، لكن الأرقام توضح أين يختلفان.

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

    باختصار (tl;dr): Lingui هي الأقرب إلى Intlayer في حجم JavaScript الخام لكل صفحة: 115-120 كيلوبايت مقابل 118.6 كيلوبايت على TanStack Start بمجرد تهيئة التحميل الكسول (Lazy loading)، و148.6 كيلوبايت مقابل 141.3 كيلوبايت على Next.js. لكن الفجوة تتسع في جوانب أخرى: مكون Lingui مجمع بمعزل يزن 58-153 كيلوبايت مقابل 6-8 كيلوبايت لـ Intlayer، ويستغرق الترطيب (Hydration) مدة 28-34 مللي ثانية مقابل 11-14 مللي ثانية، كما يتسرب من لغة المصدر الاحتياطية 3-15% من نصوص en إلى صفحات fr في جميع التهيئات المحسنة. والوصول إلى هذه التهيئة المحسنة يعني استخراج الكتالوجات وتجميعها واختيارها يدوياً لكل مسار، بينما يحقق Intlayer ذلك دون أي إعدادات إضافية.

    نظرة عامة

    • Lingui - يعتمد على وحدات الماكرو ( t`...` , <Trans>, msg)، ومعيار ICU MessageFormat، وكتالوجات .po / JSON، وسير عمل lingui extract + lingui compile. يقوم بتجميع معرفات الرسائل إلى تجزئات قصيرة (hashes)، ويدعم التحميل الديناميكي للكتالوجات لكل لغة. مشروع راسخ، ومستقل عن أطر العمل، وله توافقية ممتازة مع أدوات المترجمين حول ملفات .po.
    • Intlayer - نموذج محتوى يتمحور حول المكونات. توضع قواميس .content.ts بجانب المكون الذي تخدمه، ويقوم مترجم وقت البناء بتقليم الشجرة والتحميل الكسول لكل مكون ولكل لغة، مع توليد أنواع TypeScript صارمة تلقائياً من محتواك، وفشل البناء عند فقدان أي ترجمات. يتضمن برمجيات وسيطة، ومساعدات SEO، ومحرراً مرئياً / CMS، وترجمة مدعومة بالذكاء الاصطناعي.
    المكتبةنجوم GitHubإجمالي التعديلات (Commits)آخر تعديلالإصدار الأولإصدار NPMتنزيلات NPM
    aymericzip/intlayerGitHub Repo starsGitHub commit activityLast Commitأبريل 2024npmnpm downloads
    lingui/js-linguiGitHub Repo starsGitHub commit activityLast Commitديسمبر 2016npmnpm downloads
    يتم تحديث الشارات تلقائياً. تختلف اللقطات بمرور الوقت.

    مقارنة الميزات وجهاً لوجه

    الميزةIntlayer (react-intlayer / next-intlayer)Lingui (@lingui/core / @lingui/react)
    الترجمات بجانب المكونات✅ نعم، ملف .content.ts موجود بجوار كل مكون⚠️ نصوص المصدر مضمنة داخل JSX عبر الماكرو؛ الترجمات في كتالوجات .po مركزية
    التكامل مع TypeScript✅ أنواع صارمة يتم إنشاؤها تلقائياً من المحتوى⚠️ وحدات الماكرو ذات أنواع محددة؛ لكن معرفات الرسائل والترجمات المفقودة لا يتم كشفها
    اكتشاف الترجمات المفقودة✅ خطأ TypeScript + خطأ/تحذير في وقت البناء⚠️ يعرض lingui extract إحصائيات؛ بينما تعود بيئة التشغيل إلى نص المصدر تلقائياً
    المحتوى الغني (JSX / Markdown / مكونات)✅ دعم مباشر<Trans> مع مكونات متداخلة
    دعم معيار ICU⚠️ قيد التطوير✅ نعم (وحدات ماكرو plural وselect وselectOrdinal)
    التنسيق (التواريخ، الأرقام، العملات)useNumber وuseDate وغيرها (تعتمد على Intl داخلياً)i18n.date() وi18n.number()
    التوجيه المترجم والبرمجيات الوسيطة✅ وكيل وبرمجية وسيطة مدمجة، دالة getMultilingualUrls❌ ليست جزءاً من النواة
    مساعدات تحسين محركات البحث SEO✅ مساعدات مدمجة (hreflang وsitemap وrobots)❌ يدوية
    مكونات الخادم المتزامنة (Server Components)✅ دالة useIntlayer من next-intlayer/server تعمل في أي مكون خادم فرعي⚠️ تحتاج إلى كائن I18n لكل طلب، يتم تمريره لأسفل أو تعيينه عبر setI18n
    تقليم الشجرة Tree-shaking (إرسال المحتوى المستخدم)✅ لكل مكون، ولكل لغة، وبشكل تلقائي بواسطة المترجم⚠️ لكل لغة عبر lingui compile؛ وتتطلب تقسيماً يدوياً لكل مسار
    التحميل الكسول (Lazy loading)importMode: 'dynamic' (سطر إعداد واحد)⚠️ استخدام import() يدوي للكتالوجات المجمعة + i18n.load() / i18n.activate()
    تنظيف المحتوى غير المستخدم✅ يتم التخلص من القواميس غير المستخدمة أثناء البناء✅ أمر lingui extract --clean يزيل الرسائل المهملة
    اختبار الترجمات المفقودة (CLI / CI)npx intlayer content test⚠️ إحصائيات lingui extract (لا يوجد رمز خروج بالخطأ افتراضياً)
    مسار البناء (Build pipeline)✅ إضافة واحدة (@intlayer/swc / @intlayer/babel / vite-intlayer)⚠️ إضافة ماكرو (Babel أو SWC) + خطوات extract + compile
    ترجمة مدعومة بالذكاء الاصطناعي✅ مدمجة وتستخدم مفاتيح الموفر الخاصة بك❌ لا يوجد
    محرر مرئي / CMS✅ محرر مرئي مجاني + نظام إدارة محتوى (CMS) اختياري❌ لا يوجد (ملفات .po تعمل مع أنظمة TMS خارجية)
    خادم MCP ومهارات الوكلاء (Agent Skills)✅ نعم❌ لا يوجد
    النظام البيئي والمجتمع⚠️ أصغر لكنه ينمو بسرعة✅ راسخ ومستقل عن أطر العمل

    الاختبار

    ما تم قياسه

    تبني مجموعة Benchmark Bloom التطبيق نفسه باستخدام كل مكتبة: 10 صفحات (الرئيسية، من نحن، المدونة، الوظائف، اتصل بنا، الأسئلة الشائعة، الأسعار، المنتجات، الإعدادات، الفريق)، و10 لغات (en، fr، es، de، it، pt، zh، ja، ko، ru)، مع مكونات متطابقة ومحتوى متطابق. يتم قياس الصفحات باللغتين en وfr. يتم تنفيذ كل مكتبة في ما يصل إلى أربع استراتيجيات تحميل، بدءاً من التهيئة البسيطة وحتى التهيئة المثلى:

    الاستراتيجيةالوصفمن يستخدمها
    staticيتم استيراد الكتالوج المجمع لكل لغة وتحميله مسبقاً بالكاملالنماذج الأولية السريعة، الأكواد المولدة بالذكاء
    dynamicيتم استيراد كتالوج اللغة النشطة فقط عبر import()، ولكنه يحتوي على جميع الصفحاتمعظم المشاريع
    scoped-staticكتالوج واحد لكل مسار، يتم تجميعها جميعاً مسبقاًنادرة الاستخدام
    scoped-dynamicكتالوج واحد لكل مسار + تحميل كسول عبر import(). فقط الصفحة الحالية واللغة الحاليةالتطبيقات ذات ميزانية الأداء الصارمة

    لا يحتوي Intlayer على متغير "مخصص النطاق" (scoped): يقوم المترجم بتحديد نطاق المحتوى لكل مكون تلقائياً، وبالتالي فإن صفي static وdynamic محصوران بالفعل بطبيعتهما.

    لكل بناء، تسجل المجموعة:

    • حجم المكتبة (Lib size): حجم gzip لمكون فارغ يستورد مكتبة i18n فقط. وهي التكلفة الثابتة لبيئة التشغيل.
    • حجم JS للصفحة (Page JS): متوسط حجم JavaScript بتنسيق gzip الذي تم تنزيله لكل صفحة عبر جميع الصفحات واللغات.
    • نسبة تسرب اللغة (Locale leak %): نسبة السلاسل المترجمة الموجودة في ملف JS والتي تنتمي إلى لغة لا يعرضها المستخدم (تمت المقارنة على en وfr، لذا فإن 50% تعني "اللغة الأخرى موجودة بالكامل"؛ ومع وجود 10 لغات مجمعة، يكون الهدر الفعلي أكبر بكثير).
    • نسبة تسرب الصفحة (Page leak %): نسبة السلاسل المترجمة الموجودة في ملف JS والتي تنتمي إلى صفحة لا يتصفحها المستخدم.
    • متوسط حجم المكون (Component avg): متوسط حجم gzip لكل مكون تم تجميعه بمعزل. يوضح حجم بيئة التشغيل والكتالوج الذي يجلبه مكون واحد.
    • تفاعلية E2E: الوقت المنقضي بين اختيار لغة جديدة وتحديث html[lang] في الـ DOM (اختبار Playwright، 5 تكرارات).
    • الترطيب (Hydration): مدة مرحلة ترطيب React.
    الأرقام أدناه مأخوذة من اختبار بتاريخ 2026-09-12 باستخدام @lingui/react 6.6.0 وintlayer 9.5.1. تطبيق الاختبار صغير عن قصد (بضع عشرات من النصوص لكل لغة)، لذا تصف نسب التسرب نمطاً سلوكياً: حيث تزداد مع نمو المحتوى بينما تظل تكلفة بيئة التشغيل ثابتة.

    النتائج على Next.js

    المكتبةالاستراتيجيةحجم المكتبة (gz)متوسط JS للصفحة (gz)تسرب اللغةتسرب الصفحةمتوسط المكون (gz)تفاعلية E2Eالترطيب
    base (بدون i18n)-0.0 KB141.0 KB0.0%0.0%0.9 KB13.4 ms11.8 ms
    Linguistatic11.9 KB207.4 KB50.0%90.0%73.3 KB15.3 ms15.2 ms
    Linguidynamic11.9 KB145.4 KB2.8%89.9%19.9 KB15.7 ms12.7 ms
    Linguiscoped-static11.9 KB148.2 KB2.7%89.1%20.4 KB15.1 ms13.1 ms
    Linguiscoped-dynamic11.9 KB148.6 KB14.8%0.0%152.6 KB16.1 ms14.8 ms
    next-intlayerstatic5.5 KB141.3 KB0.0%0.0%8.5 KB15.5 ms16.9 ms
    next-intlayerdynamic5.5 KB141.3 KB0.0%0.0%6.9 KB15.3 ms15.9 ms

    كيف تقرأ هذه النتائج

    • تكلفة بيئة التشغيل. يكلف المكون الفارغ 11.9 كيلوبايت مع Lingui، مقابل 5.5 كيلوبايت مع Intlayer. وفي الصفحة الكاملة، تزيد أفضل تهيئة لـ Lingui بمقدار +7.3 كيلوبايت عن Intlayer (148.6 مقابل 141.3 كيلوبايت)؛ بينما تزيد Intlayer بمقدار +0.3 كيلوبايت فقط عن التطبيق الأساسي الخالي من التدويل.
    • التهيئة البسيطة مكلفة للغاية. يؤدي تحميل كل كتالوج مجمع مسبقاً إلى 207.4 كيلوبايت لكل صفحة، أي زيادة قدرها +66 كيلوبايت عن التطبيق الأساسي. نصف النصوص تعود للغة الخاطئة، و90% منها تعود لصفحات أخرى.
    • التحميل الديناميكي يحل مشكلة اللغة لا الصفحة. مع وجود كتالوج واحد لكل لغة، يظل تسرب الصفحة عند ~90%: يتم إرسال كتالوج fr بأكمله في كل صفحة فرنسية. ويتطلب الوصول إلى تسرب 0% استخدام تهيئة scoped-dynamic: كتالوج منفصل لكل مسار، واستخراجه وتجميعه يدوياً لكل صفحة.
    • تسرب اللغة المصدرية. حتى في التهيئات المحسنة، تتسرب 3-15% من نصوص en داخل صفحات fr. تحتفظ وحدات ماكرو Lingui بالرسالة المصدرية كخيار احتياطي، مما يجعلها تستقر في الحزمة بجوار الترجمة. بينما يقوم Intlayer بحل الخيارات الاحتياطية أثناء البناء ويرسل اللغة النشطة فقط.
    • تضخم حجم المكون في scoped-dynamic. يبلغ متوسط حجم المكون المجمع بمعزل 152.6 كيلوبايت، لأن كتالوج كل مسار يصبح قابلاً للوصول من المكون الذي يستورده. في المقابل يبلغ متوسط المكون نفسه مع useIntlayer() حوالي 6.9 كيلوبايت.

    النتائج على TanStack Start

    المكتبةالاستراتيجيةحجم المكتبة (gz)متوسط JS للصفحة (gz)تسرب اللغةتسرب الصفحةمتوسط المكون (gz)تفاعلية E2Eالترطيب
    base (بدون i18n)-0.0 KB111.0 KB0.0%0.0%0.7 KB8.1 ms21.6 ms
    Linguistatic11.2 KB152.2 KB50.0%90.0%58.0 KB3.9 ms19.9 ms
    Linguidynamic11.2 KB115.2 KB9.3%0.0%85.5 KB5.9 ms28.0 ms
    Linguiscoped-static11.2 KB120.8 KB4.0%0.0%147.9 KB7.1 ms33.9 ms
    Linguiscoped-dynamic11.2 KB120.2 KB8.6%0.0%83.7 KB42.1 ms32.9 ms
    intlayerstatic5.0 KB125.8 KB50.0%0.0%8.1 KB3.2 ms11.5 ms
    intlayerdynamic5.0 KB118.6 KB0.0%0.0%6.3 KB3.6 ms14.1 ms
    @intlayer/lingui (توافق)dynamic10.3 KB137.0 KB9.9%0.0%12.8 KB2.9 ms19.7 ms

    كيف تقرأ هذه النتائج

    • في حجم JavaScript لكل صفحة، يتفوق Lingui بفارق ضئيل. يصل Lingui بنمط dynamic إلى 115.2 كيلوبايت، أي أقل بـ 3.4 كيلوبايت من Intlayer (118.6 كيلوبايت). كتالوجات Lingui المجمعة ذات المعرفات المجزأة مدمجة جداً، كما يقسم موجه TanStack Start المسارات بكفاءة كافية تجعل تسرب الصفحات 0% في نمط dynamic.
    • لكن جميع المعايير الأخرى تنقلب لصالح Intlayer. يستغرق الترطيب 28-34 مللي ثانية مع Lingui مقابل 11-14 مللي ثانية مع Intlayer: حيث يتم تشغيل i18n.load() وi18n.activate() في المتصفح قبل أن يتمكن React من إتمام الترطيب. المكونات المجمعة بمعزل تزن 58-148 كيلوبايت مقابل 6-8 كيلوبايت. ولا يصل تسرب اللغة أبداً إلى 0% (يظل بين 4-9%) بسبب نصوص اللغة المصدرية.
    • تبديل اللغة بطيء في التهيئة المحسنة. يستغرق scoped-dynamic في Lingui مدة 42 مللي ثانية لتحديث html[lang]، حيث يجب جلب كتالوج المسار الجديد وتحميله وتنشيطه قبل أن يظهر التغيير. بينما يقوم Intlayer بالتبديل في 3-4 مللي ثانية في كلا الوضعين.
    • يمتلك صف static في Intlayer نسبة تسرب 0% للصفحة تلقائياً لأنه لا يتم تضمين سوى القواميس التي تستوردها مكونات الصفحة المعنية. سطر إعداد واحد (importMode: 'dynamic') يزيل تسرب اللغة أيضاً.
    • مكتبة @intlayer/lingui تحافظ على صياغة ماكرو Lingui وتخدمها من قواميس Intlayer، مما يوفر مكونات أصغر حجماً (12.8 كيلوبايت) وترطيباً أسرع بكثير من Lingui الأصلي. إنها خطوة انتقال ممتازة وليست الوجهة النهائية.

    لماذا هذا الفارق؟ مترجمان بوحدتي عمل مختلفتين

    تعتمد كلتا المكتبتين على الترجمة البرمجية (Compilation)، لكن الفارق يكمن في ما تقومان بترجمته.

    يقوم Lingui بتجميع الكتالوجات. يتم استخراج الماكرو في الكود المصدري إلى ملف .po لكل لغة، ثم تجميعه في وحدة JS لكل لغة. وحدة العمل هنا هي اللغة. ولتقسيمها بشكل أدق، حسب المسار أو المكون، يلزم إنشاء كتالوجات متعددة وتعديل lingui.config.ts والتحميل اليدوي لكل مسار. كائن I18n عام، وكل استدعاء لـ useLingui() يربط المكون به.

    bash
    .
    ├── lingui.config.ts
    └── src
        ├── i18n.ts                          # setupI18n(), load(), activate()
        ├── locales
       ├── en
       ├── messages.po
       └── messages.mjs             # مخرجات lingui compile
       └── fr
           ├── messages.po
           └── messages.mjs
        ├── components
       └── Counter.tsx                  # const { t } = useLingui(); t`Increment`
        └── routes
            └── $locale
                └── about.tsx                # await import(`../locales/${locale}/messages.mjs`)
    

    يقوم Intlayer بتجميع القواميس. كل ملف .content.ts هو قاموس مرتبط بمفتاح محدد؛ يحدد المترجم المكونات التي تستورد كل مفتاح ويصدر، لكل قاموس ولكل لغة، كود JSON الذي يحتاجه هذا المكون فقط. وحدة العمل هنا هي المكون. وتحديد النطاق لكل مسار هو نتيجة طبيعية: تسحب الصفحة فقط قواميس المكونات التي تعرضها فعلياً.

    bash
    .
    ├── intlayer.config.ts
    └── src
        ├── components
       └── Counter
           ├── index.tsx                # useIntlayer("counter")
           └── index.content.ts
        └── routes
            └── $locale
                ├── about.tsx
                └── about.content.ts
    

    لذلك فإن نمط scoped-dynamic هو نتاج بناء تلقائي لـ Intlayer، ومشروع تهيئة يدوي معقد لـ Lingui.

    للحصول على أرقام صف dynamic، قم بضبط dictionary.importMode: 'dynamic' في ملف intlayer.config.ts. راجع دليل تحسين الحزمة.

    تجربة المطور

    الإعداد

    Lingui

    lingui.config.ts
    import { defineConfig } from "@lingui/cli";
    
    export default defineConfig({
      sourceLocale: "en",
      locales: ["en", "fr"],
      catalogs: [
        {
          path: "<rootDir>/src/locales/{locale}/messages",
          include: ["src"],
        },
      ],
    });
    
    src/i18n.ts
    import { setupI18n } from "@lingui/core";
    
    export const loadCatalog = async (locale: string) => {
      const { messages } = await import(`./locales/${locale}/messages.mjs`);
      const i18n = setupI18n();
      i18n.load(locale, messages);
      i18n.activate(locale);
      return i18n;
    };
    

    ثم إضافة @lingui/babel-plugin-lingui-macro (أو @lingui/swc-plugin) لأداة التحزيم، وتشغيل lingui extract بعد التعديل، وlingui compile قبل البناء، وتغليف الشجرة بـ <I18nProvider i18n={i18n}>.

    Intlayer

    intlayer.config.ts
    import { type IntlayerConfig, Locales } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.FRENCH],
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
    

    أضف intlayer() في vite.config.ts (أو withIntlayer() في next.config.ts) وغلف التطبيق بـ <IntlayerProvider>. لا حاجة لأي خطوة استخراج أو تجميع: تُبنى القواميس تلقائياً أثناء عمل أداة التحزيم.

    المكونات

    Lingui

    src/components/Counter.tsx
    import { useState } from "react";
    import { useLingui } from "@lingui/react/macro";
    import { Trans } from "@lingui/react/macro";
    
    export const Counter = () => {
      const { t, i18n } = useLingui();
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{i18n.number(count)}</p>
          <button aria-label={t`Counter`} onClick={() => setCount((c) => c + 1)}>
            <Trans>Increment</Trans>
          </button>
        </div>
      );
    };
    

    يعيش النص الإنجليزي في المكون؛ ويعيش الفرنسي في src/locales/fr/messages.po تحت معرف مجزأ بعد تشغيل lingui extract. نسيان تشغيله أو نسيان compile يعيد النص بصمت إلى الإنجليزية.

    Intlayer

    src/components/Counter/index.content.ts
    import { t, type Dictionary } from "intlayer";
    
    const counterContent = {
      key: "counter",
      content: {
        label: t({ en: "Counter", fr: "Compteur" }),
        increment: t({ en: "Increment", fr: "Incrémenter" }),
      },
    } satisfies Dictionary;
    
    export default counterContent;
    
    src/components/Counter/index.tsx
    import { useState } from "react";
    import { useIntlayer } from "react-intlayer";
    import { useNumber } from "react-intlayer/format";
    
    export const Counter = () => {
      const { label, increment } = useIntlayer("counter");
      const number = useNumber();
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{number(count)}</p>
          <button aria-label={label} onClick={() => setCount((c) => c + 1)}>
            {increment}
          </button>
        </div>
      );
    };
    

    توجد كلتا اللغتين في ملف واحد بجوار المكون. غياب ترجمة fr يسبب خطأ في البناء، والمفتاح الخاطئ يسبب خطأ في TypeScript.

    خارج المكونات

    البيانات الوصفية (Metadata)، والـ loaders، ودوال الخادم: أي مكان خارج شجرة React.

    Lingui

    src/routes/$locale/about.tsx
    import { setupI18n } from "@lingui/core";
    import { msg } from "@lingui/core/macro";
    
    const title = msg`About us`;
    
    export const loader = async ({ params }: { params: { locale: string } }) => {
      const { messages } = await import(
        `../../locales/${params.locale}/messages.mjs`
      );
      const i18n = setupI18n({
        locale: params.locale,
        messages: { [params.locale]: messages },
      });
    
      return { title: i18n._(title) };
    };
    

    إنشاء كائن I18n جديد لكل استدعاء، وتحميل الكتالوج يدوياً، واستخدام msg + i18n._() بدلاً من t. كما تشير ملاحظات الاختبار، معرفة متى تستخدم t أو t` ` أو i18n.t() أو msg أو <Trans> "ليس بالأمر البديهي".

    Intlayer

    src/routes/$locale/about.tsx
    import { getIntlayer } from "intlayer";
    
    export const loader = async ({ params }: { params: { locale: string } }) => {
      const { title } = getIntlayer("about-metadata", params.locale);
    
      return { title };
    };
    

    الاحتفاظ بماكرو Lingui مع قواميس Intlayer

    تعد حزمة @intlayer/lingui محولاً مباشراً لـ @lingui/core و@lingui/react. تواصل وحدات الماكرو التجميع كالمعتاد، بينما يتم توفير تنفيذ i18n._() من قواميس Intlayer، مع مزامنة ملفات .po للاحتفاظ بكتالوجاتك الحالية. تعمل خيارات وصيغ الجمع في ICU بالطريقة نفسها.

    vite.config.ts
    import { defineConfig } from "vite";
    import { lingui } from "@intlayer/lingui/plugin";
    
    export default defineConfig({
      plugins: [lingui()],
    });
    

    احتفظ بـ @lingui/babel-plugin-lingui-macro أو @lingui/swc-plugin ليعمل قبل مترجم Intlayer. راجع دليل التوافق مع Lingui.

    متى تختار أياً منهما؟

    • اختر Lingui إذا كنت بحاجة إلى ICU MessageFormat مع وحدات ماكرو نمطية، وكان المترجمون يعملون بملفات .po مع نظام TMS حالي، وتفضل وجود نصوص المصدر مضمنة داخل JSX، ولا يمانع فريقك إدارة عملية الاستخراج والتجميع وتوزيع الكتالوجات يدوياً.
    • اختر Intlayer إذا كنت تريد محتوى بنطاق المكونات، وTypeScript صارماً، وأخطاء للمفاتيح المفقودة عند البناء، وتقليماً للشجرة وتحميلاً كسولاً تلقائياً بدون إعدادات، ومكونات خفيفة، وترطيباً سريعاً، وتبديلاً فورياً للغة، وأدوات تحرير مدمجة (محرر مرئي، CMS، ترجمة بالذكاء الاصطناعي، خادم MCP).
    • اختر @intlayer/lingui إذا كنت تستخدم Lingui حالياً وتريد الانتقال تدريجياً إلى قواميس Intlayer دون تغيير صياغة وحدات الماكرو.

    مقارنات ذات صلة

    نجوم GitHub

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

    رسم بياني لتاريخ النجوم

    الخاتمة

    Lingui هي أقوى مكتبة تجمع بين بيئة التشغيل والمترجم في هذا الاختبار. تمنحها كتالوجاتها المجمعة والمجزأة حجماً صغيراً لـ JavaScript لكل صفحة يفصل بينه وبين Intlayer بضع كيلوبايت فقط، بل وتتفوق عليه قليلاً في TanStack Start. وإذا كان حجم البايتات لكل صفحة هو المعيار الوحيد، لكانت النتيجة تعادلاً.

    لكن الأمر يتجاوز ذلك. يقف مترجم Lingui عند حدود اللغة؛ وكل ما دون ذلك (الكتالوجات لكل مسار، التحميل الكسول، منع تسرب لغة المصدر الاحتياطية) يتطلب تهيئة يدوية. ويظهر الاختبار ثمن هذا الحد: مكونات أكبر بـ 10-20 ضعفاً، وترطيب أبطأ بـ 2-3 أضعاف، وتسرب للغة بنسبة 3-15% لا يختفي أبداً، وتبديل لغة يستغرق 42 مللي ثانية في التهيئة المحسنة. في المقابل يعمل مترجم Intlayer على مستوى المكون مباشرة، لتكون تلك الأرقام 6-8 كيلوبايت، و11-14 مللي ثانية، و0%، و3-4 مللي ثانية بدون أي تهيئة يدوية.

    جميع البيانات الأولية والتطبيقات وسيناريوهات الاختبار متوفرة في مستودع Benchmark Bloom. يمكنك تشغيله بنفسك.

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

    التعليقات

    لا توجد تعليقات بعد. كن أول من يشارك أفكاره.

    مقالات ذات صلة

    آخر المقالات