Getting Started Internationalizing (i18n) مع Intlayer و Vite و React

    ما هو Intlayer؟

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

    مع Intlayer، يمكنك:

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

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

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

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

    bash
    npm install intlayer react-intlayer vite-intlayer
    • intlayer

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

    • react-intlayer الحزمة التي تدمج Intlayer مع تطبيق React. توفر موفري السياق والركائز لنقل التدويل في React. بالإضافة إلى ذلك، تتضمن الملحق Vite لدمج Intlayer مع حزمة Vite، بالإضافة إلى الوسيط لاكتشاف تفضيلات اللغة للمستخدم، وإدارة ملفات تعريف الارتباط، والتعامل مع إعادة توجيه URL.

    الخطوة 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;

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

    الخطوة 3: دمج Intlayer في إعداد Vite الخاص بك

    أضف ملحق intlayer إلى إعدادك.

    vite.config.ts
    import { defineConfig } from "vite";import react from "@vitejs/plugin-react-swc";import { intlayerPlugin } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [react(), intlayerPlugin()],});

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

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

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

    src/app.content.tsx
    import { t, type DeclarationContent } from "intlayer";import type { ReactNode } from "react";const appContent = {  key: "app",  content: {    viteLogo: t({      en: "Vite logo",      fr: "Logo Vite",      es: "Logo Vite",    }),    reactLogo: t({      en: "React logo",      fr: "Logo React",      es: "Logo React",    }),    title: "Vite + React",    count: t({      en: "count is ",      fr: "le compte est ",      es: "el recuento es ",    }),    edit: t<ReactNode>({      // تذكر استيراد React إذا كنت تستخدم عقدة React في المحتوى الخاص بك      en: (        <>          Edit <code>src/App.tsx</code> and save to test HMR        </>      ),      fr: (        <>          Éditez <code>src/App.tsx</code> et enregistrez pour tester HMR        </>      ),      es: (        <>          Edita <code>src/App.tsx</code> y guarda para probar HMR        </>      ),    }),    readTheDocs: t({      en: "Click on the Vite and React logos to learn more",      fr: "Cliquez sur les logos Vite et React pour en savoir plus",      es: "Haga clic en los logotipos de Vite y React para obtener más información",    }),  },} satisfies DeclarationContent;export default appContent;

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

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

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

    src/App.tsx
    import { useState, type FC } from "react";import reactLogo from "./assets/react.svg";import viteLogo from "/vite.svg";import "./App.css";import { IntlayerProvider, useIntlayer } from "react-intlayer";const AppContent: FC = () => {  const [count, setCount] = useState(0);  const content = useIntlayer("app");  return (    <>      <div>        <a href="https://vitejs.dev" target="_blank">          <img src={viteLogo} className="logo" alt={content.viteLogo.value} />        </a>        <a href="https://react.dev" target="_blank">          <img            src={reactLogo}            className="logo react"            alt={content.reactLogo.value}          />        </a>      </div>      <h1>{content.title}</h1>      <div className="card">        <button onClick={() => setCount((count) => count + 1)}>          {content.count}          {count}        </button>        <p>{content.edit}</p>      </div>      <p className="read-the-docs">{content.readTheDocs}</p>    </>  );};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 type { FC } from "react";import { Locales } from "intlayer";import { useLocale } from "react-intlayer";const LocaleSwitcher: FC = () => {  const { setLocale } = useLocale();  return (    <button onClick={() => setLocale(Locales.English)}>      Change Language to English    </button>  );};

    لمعرفة المزيد عن هوك useLocale، راجع الوثائق.

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

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

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

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

    vite.config.ts
    import { defineConfig } from "vite";import react from "@vitejs/plugin-react-swc";import { intlayerPlugin, intLayerMiddlewarePlugin } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [react(), intlayerPlugin(), intLayerMiddlewarePlugin()],});

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

    لتغيير URL عند تغيير اللغة، يمكنك استخدام الخاصية onLocaleChange التي يوفرها هوك useLocale. في الوقت نفسه، يمكنك استخدام هوكي useLocation و useNavigate من react-router-dom لتحديث مسار 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 location = useLocation(); // الحصول على مسار URL الحالي. مثال: /fr/about  const navigate = useNavigate();  const changeUrl = (locale: Locales) => {    // بناء URL مع اللغة المحينة    // مثال: /es/about مع تعيين اللغة إلى الإسبانية    const pathWithLocale = getLocalizedUrl(location.pathname, locale);    // تحديث مسار URL    navigate(pathWithLocale);  };  const { locale, availableLocales, setLocale } = useLocale({    onLocaleChange: changeUrl,  });  return (    <ol>      {availableLocales.map((localeItem) => (        <li key={localeItem}>          <a            href={getLocalizedUrl(location.pathname, localeItem)}            hrefLang={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={(e) => {              e.preventDefault();              setLocale(localeItem);            }}          >            <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>            <span>              {/* اللغة في لغتها الخاصة - على سبيل المثال، FR */}              {localeItem}            </span>          </a>        </li>      ))}    </ol>  );};

    مراجع الوثائق:

    تكوين TypeScript

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

    alt text

    alt text

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

    tsconfig.json
    {  // تكوينك المخصص  "include": [    "src",    "types", // <- تضمين الأنواع التي تم إنشاؤها تلقائياً  ],}

    تكوين Git

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

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

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

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

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