انتقل إلى المقال
Aniq-UI

Learnioاللغات

اللغات

كيف يختار Learnio اللغة، وأين توجد كل ترجمة، وكيف تغيّر نصًا أو تضيف لغة جديدة إلى كل تطبيق.

لحزمة الحزمة الكاملة

اللغات المتوفرة

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

التطبيقملفات الترجمةالملفات لكل لغة
موقع الطلابfrontend/messages/<namespace>/<locale>.json22
لوحة الإدارةadmin-dashboard/messages/<namespace>/<locale>.json24
APIback-end/src/i18n/translations/<locale>/<namespace>.json18

مساحة الأسماء (namespace) هي جزء واحد من التطبيق، مثل layouts أو auth أو courses. بعضها مجلدات متداخلة، مثل messages/dashboard/courses/en.json.

كيف تُختار اللغة

اللغة هي الجزء الأول من العنوان: /en/courses أو /ar/courses. لا يوجد ملف تعريف ارتباط (cookie) للغة ولا اكتشاف تلقائي من المتصفح.

  • يُعاد توجيه العنوان الذي لا يتضمن لغة إلى اللغة الافتراضية، الإنجليزية: /courses يذهب إلى /en/courses. وفي لوحة الإدارة، / يذهب إلى /en/dashboard.
  • يفتح مبدّل اللغة الصفحة نفسها تحت البادئة الأخرى.
  • يحمل كل طلب إلى واجهة API لغة الصفحة في الترويسة Accept-Language، فتجيب واجهة API بها.

لجعل الفتح بالعربية افتراضيًا، اضبط defaultLocale على "ar" في src/config/locales.ts في موقع الطلاب، وفي src/proxy.ts في لوحة الإدارة.

غيّر نصًا

كل كلمة على الشاشة تأتي من ملف رسائل. ابحث عن النص الذي تراه لتجد مفتاحه، ثم غيّره في كل لغة.

الطرفيةفي frontend
grep -rn "All rights reserved" messages

يعثر هذا على سطر حقوق النشر في التذييل، وهو المفتاح footer.copyright في messages/layouts/en.json. غيّر المفتاح نفسه في ar.json:

frontend/messages/layouts/en.json
"footer": {
  "copyright": "© {year} Learnio. All rights reserved."
}
  • أبقِ العناصر النائبة مثل {year} والوسوم مثل <brand> كما هي تمامًا. تملؤها الشيفرة.
  • غيّر المفتاح في كل ملف لغة. المفتاح المفقود من إحدى اللغات يُظهر مساره بدلًا من النص.
  • يلتقط yarn dev التغيير. أما بناء الإنتاج فيتضمن الرسائل، لذا أعد البناء.

الإشعارات كذلك: تحفظ واجهة API نوع الإشعار فقط، مثل enrollment_created، ويصوغه كل تطبيق من ملفاته الخاصة. في لوحة الإدارة توجد تحت header.notifications.types في messages/dashboard/<locale>.json؛ وفي موقع الطلاب تحت notifications.types في الملف نفسه.

الدورات والمقالات وسائر المحتوى

النصوص التي تكتبها في لوحة الإدارة، مثل عناوين الدورات والدروس والفئات ومقالات المدونة وملفات المدرّسين، تُحفظ مرة واحدة باللغتين معًا، كقيمة JSON فيها مفتاح en ومفتاح ar:

اسم فئة في قاعدة البيانات
{ "en": "Project Management", "ar": "إدارة المشاريع" }
  • تعرض نماذج لوحة الإدارة تبويبًا للإنجليزية وآخر للعربية لكل حقل من هذه الحقول.
  • تُرجع واجهة API القيمتين، وتعرض كل واجهة أمامية القيمة الخاصة بلغة الصفحة. وإذا كانت فارغة، تعرض الأخرى، فلا تبقى أي دورة بلا اسم.
  • تأتي نتائج البحث محسومة اللغة من واجهة API، بناءً على الترويسة Accept-Language.
  • في البيانات التجريبية التي ينشئها yarn seed، تحمل الفئات ومقالات المدونة وملفات المدرّسين والاختبارات وعناوين أقسام الدورات نصوصًا عربية. أما عناوين الدورات وأوصافها وعناوين الدروس فتحمل النص الإنجليزي تحت المفتاحين، لذا ترجمها في لوحة الإدارة.

للمحتوى لغتان فقط

يتوقع التحقق في واجهة API قيمة en وقيمة ar في هذه الحقول ويرفض أي مفتاح آخر، ولمحررات لوحة الإدارة تبويبان. إضافة لغة ثالثة للمحتوى تعني تغيير الكيانات وكائنات DTO في واجهة API، وحقول الإدخال متعددة اللغات في لوحة الإدارة والدالة المساعدة localizedText فيها. أما localizedText في موقع الطلاب فتقرأ بالفعل المفتاح المطابق للغة الصفحة. ومن دون هذه التغييرات، تعرض الصفحة بلغة واجهة جديدة المحتوى الإنجليزي.

ما تترجمه واجهة API

  • رسائل الاستجابة، مثل نصوص النجاح والخطأ التي تعرضها لوحة الإدارة في تنبيهاتها، تأتي من src/i18n/translations/<locale>/<namespace>.json عبر I18nService في src/i18n/i18n.service.ts.
  • رسائل البريد الإلكتروني مصاغة في mail.json. تستخدم رسائل التحقق وإعادة تعيين كلمة المرور لغة الطلب. وتستخدم الإيصالات وتأكيدات التسجيل اللغة التي قُدّم بها الطلب. وتُعرض الرسائل العربية من اليمين إلى اليسار.
  • أسماء الدول موجودة في countries.json.

تُؤخذ اللغة من ترويسة Accept-Language. والرمز الإقليمي مثل ar-SA يُحسب ar. الطلب الذي لا يحمل ترويسة، أو يحمل لغة لا تدعمها واجهة API، يحصل على اللغة الافتراضية. والمفتاح الناقص في لغة ما يعود إلى نصه في اللغة الافتراضية، ثم إلى المفتاح نفسه.

  • اللغة الافتراضية هي العنصر Default Language (default_locale) في تبويب App Settings ضمن Settings في لوحة الإدارة، وقيمتها en بعد البذر. يُطبَّق أي تغيير على الطلب التالي دون إعادة تشغيل. وترفض واجهة API أي قيمة ليست من لغاتها، فلا يمكن لخطأ مطبعي أن يجعلها تجيب بلغة لا ترجمات لها.
  • تقرأ واجهة API ملفات ترجمتها مرة واحدة عند بدء تشغيلها: أعد تشغيلها بعد تعديل أي منها. وينسخها yarn build إلى dist/.

أضف لغة إلى موقع الطلاب

تستخدم الخطوات الفرنسية، fr، مثالًا. استخدم رمزًا من حرفين صغيرين: فعدة دوال مساعدة تتعرّف على اللغة بوصفها مقطعًا أول من حرفين في العنوان. المسارات داخل frontend/.

  1. أضف الرمز إلى قائمة اللغات

    src/config/locales.ts هو القائمة الوحيدة التي يقرؤها موقع الطلاب: المسارات، وإعادة التوجيه، ومحمّل الرسائل، والسكربت الذي يضبط lang وdir قبل أول رسم، ومبدّل اللغة، وطلبات واجهة API، وإعادة التوجيه بعد تسجيل الدخول، والبيانات الوصفية للصفحات، وخريطة الموقع، وكل رقم وتاريخ ينسّقه. أضف الرمز إلى locales، ثم أعطه مدخلًا في الخرائط الثلاث المجاورة. يشير المترجم إلى أي منها فاتك.

    frontend/src/config/locales.ts
    export const locales = ["en", "ar", "fr"] as const;
    
    export const OG_LOCALES: Record<Locale, string> = { en: "en_US", ar: "ar_AE", fr: "fr_FR" };
    export const LOCALE_FLAGS: Record<Locale, FlagIconCode> = { en: "US", ar: "AE", fr: "FR" };
    export const LOCALE_FORMAT_TAGS: Record<Locale, string> = { en: "en-US", ar: "ar-EG", fr: "fr-FR" };
    المدخلما يضبطه
    OG_LOCALESلغة بطاقة المشاركة للصفحة (og:locale)
    LOCALE_FLAGSالعلم الذي يعرضه مبدّل اللغة، كرمز دولة
    LOCALE_FORMAT_TAGSطريقة كتابة الأرقام والتواريخ. استخدم وسمًا يتضمن المنطقة، مثل fr-FR، كي لا تعتمد الأرقام وأسماء الأشهر على المتصفح.
    RTL_LOCALESأضف الرمز للغة تُكتب من اليمين إلى اليسار.
    JOINING_SCRIPT_LOCALESأضف الرمز لكتابة تتصل حروفها، كما في العربية. عندها يُرسم شعار الصفحة الرئيسية النصي كمسارات، لأن Safari يترك هذه الحروف منفصلة في نص SVG.
  2. أنشئ ملفات الرسائل

    انسخ كل ملف إنجليزي بجوار نفسه تحت الرمز الجديد، ثم ترجم القيم. أبقِ المفاتيح كما هي.

    الطرفيةفي frontend
    find messages -name en.json -exec sh -c 'cp "$1" "$(dirname "$1")/fr.json"' _ {} \;

    في PowerShell:

    الطرفيةفي frontend
    Get-ChildItem messages -Recurse -Filter en.json | ForEach-Object { Copy-Item $_.FullName (Join-Path $_.DirectoryName 'fr.json') }
  3. تحقق من الخطوط

    يُحمَّل خط Inter بالمجموعة الفرعية latin في src/app/layout.tsx، وهي تغطي الفرنسية والإسبانية والألمانية. أضف latin-ext للغات مثل البولندية والتشيكية والتركية. ولنظام كتابة آخر، حمّل خطًا له هناك وأضف قاعدة للخاصية lang الخاصة به في src/styles/base.css، كما في القاعدة العربية.

  4. افتح اللغة الجديدة

    أعد تشغيل yarn dev وافتح localhost:3030/frمحلي.

    النتيجة المتوقعة: تعرض الصفحة نصك المترجم، ويسرد المبدّل اللغة الجديدة، وتذكرها كل صفحة في روابط hreflang البديلة وفي خريطة الموقع.

تحتاج صفحة الدفع إلى أن تعرف واجهة API اللغة

يرسل الدفع لغة الصفحة مع الطلب، ولا تقبل واجهة API هناك إلا اللغات الموجودة في قائمتها. وإلى أن يُضاف الرمز إلى واجهة API أيضًا (إضافة لغة إلى واجهة API)، تُرفض عملية الشراء من صفحة باللغة الجديدة.

أضف لغة إلى لوحة الإدارة

تحتفظ لوحة الإدارة بقائمة لغاتها في ثلاثة ملفات. تستخدم الخطوات fr؛ والتزم برمز من حرفين صغيرين. المسارات داخل admin-dashboard/.

  1. أضف الرمز إلى القوائم الثلاث

    • locales في src/config/i18n.ts، الذي يحمّل الرسائل.
    • locales في src/proxy.ts، الذي يعيد توجيه العناوين التي لا تتضمن لغة.
    • locales في src/app/[locale]/layout.tsx، الذي يحدد العناوين الموجودة.
  2. أنشئ ملفات الرسائل

    انسخ كل ملف إنجليزي تحت الرمز الجديد، ثم ترجم القيم.

    الطرفيةفي admin-dashboard
    find messages -name en.json -exec sh -c 'cp "$1" "$(dirname "$1")/fr.json"' _ {} \;
  3. حدّث الدوال المساعدة

    • يقبل src/hooks/locale/useLocale.ts اللغات en وfr وes وar. أضف رمزك إن لم يكن منها.
    • يعامل src/hooks/locale/useDirection.ts اللغة ar وحدها على أنها من اليمين إلى اليسار. وسّع الشرط للغة أخرى تُكتب من اليمين إلى اليسار.
    • لا يتعرّف src/lib/api/client-utils/locale.ts وsrc/lib/api/client-utils/auth.ts في العنوان إلا على en وar. أضف رمز لغتك.
  4. أضفها إلى مبدّل اللغة

    في src/components/LanguageSwitcher.tsx، استورد العلم من country-flag-icons/react/3x2 وأضف عنصرًا إلى languages.

    admin-dashboard/src/components/LanguageSwitcher.tsx
    import { US, SA, FR } from "country-flag-icons/react/3x2";
    
    const languages = [
      { code: "en", country: "US" as const, Flag: US },
      { code: "ar", country: "SA" as const, Flag: SA },
      { code: "fr", country: "FR" as const, Flag: FR },
    ];
  5. تحقق من الخطوط

    تُحمَّل الخطوط في src/app/layout.tsx، ويبدّل src/styles/base.css إلى الخط العربي مع html[lang="ar"]. تحتاج اللغة المكتوبة بنظام كتابة آخر إلى خطها الخاص وقاعدة مطابقة.

لأسماء العلامة التجارية في src/config/brand.config.ts قيمتان فقط، en وar، وتُعرض القيمة الإنجليزية لأي لغة أخرى.

أضف لغة إلى واجهة API

المسارات داخل back-end/.

  1. انسخ مجلد الترجمة

    ثم ترجم الملفات الثمانية عشر الموجودة فيه.

    الطرفيةفي back-end
    cp -R src/i18n/translations/en src/i18n/translations/fr

    في PowerShell:

    الطرفيةفي back-end
    Copy-Item -Recurse src/i18n/translations/en src/i18n/translations/fr
  2. أضف الرمز إلى قائمة اللغات المدعومة

    SUPPORTED_LOCALES في src/i18n/locales.ts هي القائمة الوحيدة في واجهة API. تقرؤها الترجمات، والتحقق في صفحة الدفع، واللغة المثبّتة على كل طلب، وصفحات الدفع، والرسائل وروابطها إلى الواجهتين. وإلى أن يُضاف الرمز هناك، تحصل الطلبات باللغة الجديدة على اللغة الافتراضية.

    back-end/src/i18n/locales.ts
    export const SUPPORTED_LOCALES = ['en', 'ar', 'fr'] as const;
  3. تحقّق من الموضعين اللذين يختبران العربية

    يجعل src/modules/mail/templates/layout.ts اتجاه الرسالة من اليمين إلى اليسار لـ ar فقط؛ وسّعه ليشمل لغة أخرى تُكتب من اليمين إلى اليسار. أما البحثان، src/modules/search/search.service.ts وsrc/modules/public/student-search.service.ts، فيقرآن العنوان المخزّن بالعربية أو الإنجليزية فقط، لأن للمحتوى لغتين. اعرضهما:

    الطرفيةفي back-end
    grep -rn "=== 'ar'" src
  4. أعد تشغيل واجهة API

    تقرأ ملفات الترجمة عند بدء التشغيل. وفي بيئة الإنتاج، ينسخها yarn build إلى dist/.

توقفت عند خطوة؟

ابحث عن الحل قبل أن تبدأ من جديد.

حل المشكلات

تفضيلات ملفات تعريف الارتباط

نستخدم ملفات تعريف الارتباط لتعزيز تجربة التصفح الخاصة بك وتحليل حركة المرور على الموقع وتخصيص المحتوى. بالنقر على "قبول الكل"، فإنك توافق على استخدامنا لملفات تعريف الارتباط للتحليلات والإعلانات المخصصة.