البدء في التدويل (i18n) باستخدام Intlayer و React Create App

    ما هو Intlayer؟

    Intlayer هو مكتبة مفتوحة المصدر مبتكرة للتدويل (i18n) مصممة لتبسيط دعم اللغات المتعددة في تطبيقات الويب الحديثة.

    مع Intlayer، يمكنك:

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

    دليل خطوة بخطوة لإعداد Intlayer في تطبيق React

    الخطوة 1: تثبيت التبعيات

    قم بتثبيت الحزم الضرورية باستخدام npm:

    bash
    npm install intlayer react-intlayer react-scripts-intlayer
    • intlayer

      الحزمة الأساسية التي توفر أدوات التدويل لإدارة التكوين، الترجمة، إعلان المحتوى، الترجمة، وأوامر CLI.

    • react-intlayer

      الحزمة التي تدمج Intlayer مع تطبيق React. توفر موفري السياق وخطافات لتدويل React.

    • react-scripts-intlayer

      تتضمن أوامر ومكونات react-scripts-intlayer لتكامل Intlayer مع تطبيق يعتمد على Create React App. تعتمد هذه المكونات على craco وتتضمن تكوينًا إضافيًا لمجمع Webpack.

    الخطوة 2: تكوين مشروعك

    قم بإنشاء ملف تكوين لتحديد لغات تطبيقك:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // لغاتك الأخرى    ],    defaultLocale: Locales.ENGLISH,  },};export default config;

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

    الخطوة 3: دمج Intlayer في تكوين CRA الخاص بك

    قم بتغيير السكربتات لاستخدام react-intlayer

    package.json
      "scripts": {    "build": "react-scripts-intlayer build",    "start": "react-scripts-intlayer start",    "transpile": "intlayer build"  },

    تعتمد سكربتات react-scripts-intlayer على CRACO. يمكنك أيضًا تنفيذ إعدادك الخاص بناءً على مكون intlayer craco. انظر المثال هنا.

    الخطوة 4: إعلان المحتوى الخاص بك

    قم بإنشاء وإدارة إعلانات المحتوى الخاصة بك لتخزين الترجمات:

    src/app.content.tsx
    import { t, type Dictionary } from "intlayer";import React, { type ReactNode } from "react";const appContent = {  key: "app",  content: {    getStarted: t<ReactNode>({      ar: (        <>          قم بتحرير <code>src/App.tsx</code> واحفظ لإعادة التحميل        </>      ),      en: (        <>          Edit <code>src/App.tsx</code> and save to reload        </>      ),      fr: (        <>          Éditez <code>src/App.tsx</code> et enregistrez pour recharger        </>      ),      es: (        <>          Edita <code>src/App.tsx</code> y guarda para recargar        </>      ),    }),    reactLink: {      href: "https://reactjs.org",      content: t({        ar: "تعلم React",        en: "Learn React",        fr: "Apprendre React",        es: "Aprender React",      }),    },  },} satisfies Dictionary;export default appContent;

    يمكن تعريف إعلانات المحتوى الخاصة بك في أي مكان في تطبيقك طالما تم تضمينها في دليل contentDir (افتراضيًا، ./src). وتطابق امتداد ملف إعلان المحتوى (افتراضيًا، .content.{ts,tsx,js,jsx,mjs,cjs}). لمزيد من التفاصيل، راجع وثائق إعلان المحتوى. إذا كان ملف المحتوى الخاص بك يتضمن كود TSX، يجب أن تفكر في استيراد import React from "react"; في ملف المحتوى الخاص بك.

    الخطوة 5: استخدام Intlayer في الكود الخاص بك

    الوصول إلى قواميس المحتوى الخاصة بك في جميع أنحاء تطبيقك:

    src/App.tsx
    import logo from "./logo.svg";import "./App.css";import type { FC } from "react";import { IntlayerProvider, useIntlayer } from "react-intlayer";const AppContent: FC = () => {  const content = useIntlayer("app");  return (    <div className="App">      <img src={logo} className="App-logo" alt="logo" />      {content.getStarted}      <a        className="App-link"        href={content.reactLink.href.value}        target="_blank"        rel="noopener noreferrer"      >        {content.reactLink.content}      </a>    </div>  );};const App: FC = () => (  <IntlayerProvider>    <AppContent />  </IntlayerProvider>);export default App;

    ملاحظة: إذا كنت ترغب في استخدام المحتوى الخاص بك في سمة string، مثل alt، title، href، aria-label، وما إلى ذلك، يجب عليك استدعاء قيمة الوظيفة، مثل:

    jsx
    <img src={content.image.src.value} alt={content.image.value} />

    لمعرفة المزيد عن الخطاف useIntlayer، راجع التوثيق.

    (اختياري) الخطوة 6: تغيير لغة المحتوى الخاص بك

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

    src/components/LocaleSwitcher.tsx
    import { Locales } from "intlayer";import { useLocale } from "react-intlayer";const LocaleSwitcher = () => {  const { setLocale } = useLocale();  return (    <button onClick={() => setLocale(Locales.English)}>      تغيير اللغة إلى الإنجليزية    </button>  );};

    لمعرفة المزيد عن الخطاف useLocale، راجع التوثيق.

    (اختياري) الخطوة 7: إضافة التوجيه المحلي إلى تطبيقك

    الغرض من هذه الخطوة هو إنشاء مسارات فريدة لكل لغة. هذا مفيد لتحسين محركات البحث (SEO) وعناوين URL الصديقة لمحركات البحث. مثال:

    plaintext
    - https://example.com/about- https://example.com/es/about- https://example.com/fr/about

    بشكل افتراضي، لا يتم تفضيل المسارات للغة الافتراضية. إذا كنت ترغب في تفضيل اللغة الافتراضية، يمكنك تعيين الخيار middleware.prefixDefault إلى true في التكوين الخاص بك. راجع توثيق التكوين لمزيد من المعلومات.

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

    src/components/LocaleRouter.tsx
    // استيراد التبعيات والوظائف اللازمةimport { Locales, getConfiguration, getPathWithoutLocale } from "intlayer"; // وظائف وأدوات من 'intlayer'import { FC, PropsWithChildren } from "react"; // أنواع React للمكونات الوظيفية والخصائصimport { IntlayerProvider } from "react-intlayer"; // مزود لسياق التدويلimport {  BrowserRouter,  Routes,  Route,  Navigate,  useLocation,} from "react-router-dom"; // مكونات التوجيه لإدارة التنقل// استخراج التكوين من Intlayerconst { internationalization, middleware } = getConfiguration();const { locales, defaultLocale } = internationalization;/** * مكون يتعامل مع التوطين ويلتف حول الأطفال بسياق اللغة المناسب. * يدير الكشف عن اللغة المستندة إلى عنوان URL والتحقق من صحتها. */const AppLocalized: FC<PropsWithChildren<{ locale: Locales }>> = ({  children,  locale,}) => {  const { pathname, search } = useLocation(); // الحصول على مسار URL الحالي  // تحديد اللغة الحالية، مع الرجوع إلى الافتراضية إذا لم يتم توفيرها  const currentLocale = locale ?? defaultLocale;  // إزالة بادئة اللغة من المسار لإنشاء مسار أساسي  const pathWithoutLocale = getPathWithoutLocale(    pathname // مسار URL الحالي  );  /**   * إذا كانت middleware.prefixDefault تساوي true، يجب دائمًا تفضيل اللغة الافتراضية.   */  if (middleware.prefixDefault) {    // التحقق من صحة اللغة    if (!locale || !locales.includes(locale)) {      // إعادة التوجيه إلى اللغة الافتراضية مع المسار المحدث      return (        <Navigate          to={`/${defaultLocale}/${pathWithoutLocale}${search}`}          replace // استبدال الإدخال الحالي في السجل بالإدخال الجديد        />      );    }    // التفاف الأطفال مع IntlayerProvider وتعيين اللغة الحالية    return (      <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>    );  } else {    /**     * عندما تكون middleware.prefixDefault تساوي false، لا يتم تفضيل اللغة الافتراضية.     * تأكد من أن اللغة الحالية صالحة وليست اللغة الافتراضية.     */    if (      currentLocale.toString() !== defaultLocale.toString() &&      !locales        .filter(          (locale) => locale.toString() !== defaultLocale.toString() // استبعاد اللغة الافتراضية        )        .includes(currentLocale) // التحقق مما إذا كانت اللغة الحالية موجودة في قائمة اللغات الصالحة    ) {      // إعادة التوجيه إلى المسار بدون بادئة اللغة      return <Navigate to={`${pathWithoutLocale}${search}`} replace />;    }    // التفاف الأطفال مع IntlayerProvider وتعيين اللغة الحالية    return (      <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>    );  }};/** * مكون التوجيه الذي يقوم بإعداد المسارات الخاصة باللغة. * يستخدم React Router لإدارة التنقل وعرض المكونات المحلية. */export const LocaleRouter: FC<PropsWithChildren> = ({ children }) => (  <BrowserRouter>    <Routes>      {locales        .filter(          (locale) => middleware.prefixDefault || locale !== defaultLocale        )        .map((locale) => (          <Route            // نمط المسار لالتقاط اللغة (مثل /en/، /fr/) ومطابقة جميع المسارات اللاحقة            path={`/${locale}/*`}            key={locale}            element={<AppLocalized locale={locale}>{children}</AppLocalized>} // يلتف حول الأطفال مع إدارة اللغة          />        ))}      {        // إذا تم تعطيل تفضيل اللغة الافتراضية، قم بعرض الأطفال مباشرة في المسار الجذر        !middleware.prefixDefault && (          <Route            path="*"            element={              <AppLocalized locale={defaultLocale}>{children}</AppLocalized>            } // يلتف حول الأطفال مع إدارة اللغة          />        )      }    </Routes>  </BrowserRouter>);

    ثم يمكنك استخدام مكون LocaleRouter في تطبيقك:

    src/App.tsx
    import { LocaleRouter } from "./components/LocaleRouter";import { FC } from "react";// ... مكون AppContent الخاص بكconst App: FC = () => (  <LocaleRouter>    <AppContent />  </LocaleRouter>);

    (اختياري) الخطوة 8: تغيير عنوان URL عند تغيير اللغة

    src/components/LocaleSwitcher.tsx
    import { useLocation, useNavigate } from "react-router-dom";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "react-intlayer";import { type FC } from "react";const LocaleSwitcher: FC = () => {  const { pathname, search } = useLocation(); // الحصول على مسار URL الحالي. مثال: /fr/about?foo=bar  const navigate = useNavigate();  const { availableLocales, setLocale } = useLocale({    onLocaleChange: (locale) => {      // إنشاء عنوان URL مع اللغة المحلية المحدثة      // مثال: /es/about?foo=bar      const pathWithLocale = getLocalizedUrl(`${pathname}${search}`, locale);      // تحديث مسار URL      navigate(pathWithLocale);    },  });  return (    <div>      <button popoverTarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <a            href={getLocalizedUrl(location.pathname, localeItem)}            hrefLang={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={(e) => {              e.preventDefault();              setLocale(localeItem);            }}            key={localeItem}          >            <span>              {/* اللغة المحلية - مثال: FR */}              {localeItem}            </span>            <span>              {/* اللغة في لغتها المحلية - مثال: Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* اللغة في اللغة الحالية - مثال: Francés مع اللغة الحالية المحددة إلى Locales.SPANISH */}              {getLocaleName(localeItem)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* اللغة بالإنجليزية - مثال: French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>          </a>        ))}      </div>    </div>  );};

    مراجع التوثيق:

    (اختياري) الخطوة 9: تغيير سمات اللغة والاتجاه في HTML

    عندما تدعم تطبيقك لغات متعددة، من الضروري تحديث سمات lang وdir في علامة <html> لتتوافق مع اللغة المحلية الحالية. يضمن ذلك:

    • إمكانية الوصول: تعتمد قارئات الشاشة والتقنيات المساعدة على السمة الصحيحة lang لنطق وتفسير المحتوى بدقة.

    من خلال تحديث هذه السمات ديناميكيًا عند تغيير اللغة، تضمن تجربة متسقة وسهلة الوصول للمستخدمين عبر جميع اللغات المدعومة.

    تنفيذ الخطاف

    قم بإنشاء خطاف مخصص لإدارة سمات HTML. يستمع الخطاف لتغييرات اللغة ويقوم بتحديث السمات وفقًا لذلك:

    src/hooks/useI18nHTMLAttributes.tsx
    import { useEffect } from "react";import { useLocale } from "react-intlayer";import { getHTMLTextDir } from "intlayer";/** * يقوم بتحديث سمات `lang` و `dir` لعنصر HTML <html> بناءً على اللغة الحالية. * - `lang`: يُعلم المتصفحات ومحركات البحث بلغة الصفحة. * - `dir`: يضمن ترتيب القراءة الصحيح (مثل 'ltr' للإنجليزية، 'rtl' للعربية). * * هذا التحديث الديناميكي ضروري لعرض النصوص بشكل صحيح، وسهولة الوصول، وتحسين محركات البحث. */export const useI18nHTMLAttributes = () => {  const { locale } = useLocale();  useEffect(() => {    // تحديث سمة اللغة إلى اللغة الحالية.    document.documentElement.lang = locale;    // تعيين اتجاه النص بناءً على اللغة الحالية.    document.documentElement.dir = getHTMLTextDir(locale);  }, [locale]);};

    استخدام الخطاف في تطبيقك

    قم بدمج الخطاف في المكون الرئيسي الخاص بك بحيث يتم تحديث سمات HTML كلما تغيرت اللغة:

    src/App.tsx
    import { FC } from "react";import { IntlayerProvider, useIntlayer } from "react-intlayer";import { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";import "./App.css";const AppContent: FC = () => {  // تطبيق الخطاف لتحديث سمات lang و dir لعلامة <html> بناءً على اللغة.  useI18nHTMLAttributes();  // ... بقية المكون الخاص بك};const App: FC = () => (  <IntlayerProvider>    <AppContent />  </IntlayerProvider>);export default App;

    من خلال تطبيق هذه التغييرات، سيقوم تطبيقك بـ:

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

    إعداد TypeScript

    يستخدم Intlayer توسيع الوحدة للاستفادة من TypeScript وجعل قاعدة الكود الخاصة بك أقوى.

    alt text

    alt text

    تأكد من أن إعدادات TypeScript الخاصة بك تتضمن الأنواع التي يتم إنشاؤها تلقائيًا.

    tsconfig.json
    {  // ... إعدادات TypeScript الحالية الخاصة بك  "include": [    // ... إعدادات TypeScript الحالية الخاصة بك    ".intlayer/**/*.ts", // تضمين الأنواع التي يتم إنشاؤها تلقائيًا  ],}

    إعداد Git

    يوصى بتجاهل الملفات التي يتم إنشاؤها بواسطة Intlayer. يتيح لك ذلك تجنب إضافتها إلى مستودع Git الخاص بك.

    للقيام بذلك، يمكنك إضافة التعليمات التالية إلى ملف .gitignore الخاص بك:

    .gitignore
    # تجاهل الملفات التي يتم إنشاؤها بواسطة Intlayer.intlayer

    التعمق أكثر

    للتعمق أكثر، يمكنك تنفيذ المحرر المرئي أو نقل المحتوى الخاص بك باستخدام CMS.

    إذا كان لديك فكرة لتحسين هذه الوثيقة، فلا تتردد في المساهمة من خلال تقديم طلب سحب على GitHub.

    رابط GitHub للتوثيق