Skip to main content

الدليل الكامل لتدويل React

من الصفر إلى تعدد اللغات: أعد إعداد i18n في تطبيق React، ثم أتمت الترجمات بالذكاء الاصطناعي.

1

تثبيت الحِزم

تحتاج إلى ثلاث حِزم: react-i18next (روابط React)، و i18next (المكتبة الأساسية)، وبشكل اختياري i18next-browser-languagedetector لاكتشاف المحلية تلقائياً.

يوفّر react-i18next hooks ومكوّنات لـ React. أمّا i18next فهو المحرك الأساسي الذي يتعامل مع تحميل الترجمات، والاستيفاء، وصيغ الجمع. وتقرأ إضافة اكتشاف اللغة تفضيل لغة المتصفح تلقائياً.
Terminal
npm install react-i18next i18next i18next-browser-languagedetector i18next-http-backend
2

تهيئة مثيل i18n

أنشئ ملف تهيئة i18n يهيّئ i18next بلغتك الافتراضية، وموارد الترجمة، وسلسلة الإضافات. يجب استيراد هذا الملف في نقطة دخول تطبيقك قبل أن يُعرَض أي مكوّن.

src/i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)  // Must come before .init()
  .init({
    fallbackLng: 'en',
    debug: process.env.NODE_ENV === 'development',
    interpolation: {
      escapeValue: false,  // React already escapes
    },
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
    },
  });

export default i18n;
"ستحتاج إلى تمرير مثيل i18next باستخدام initReactI18next" — يعني هذا الخطأ أنك نسيت استدعاء i18n.use(initReactI18next) قبل i18n.init(). يجب أن يأتي استدعاء .use() قبل .init().
3

لفّ تطبيقك بـ I18nextProvider

استورد ملف تهيئة i18n في جذر التطبيق ولفّ شجرة المكوّنات بـ I18nextProvider. بدون ذلك، تُرجِع useTranslation() مفاتيح خاماً بدلاً من النص المترجم.

src/main.tsx
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';  // Import your config
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Suspense fallback={<div>Loading...</div>}>
      <I18nextProvider i18n={i18n}>
        <App />
      </I18nextProvider>
    </Suspense>
  </React.StrictMode>
);
إذا ظهرت مفاتيح خام مثل "welcome" بدلاً من "Welcome to our app"، فالسبب الأكثر شيوعاً هو غياب I18nextProvider أو عدم استيراد ملف تهيئة i18n.
4

إنشاء ملفات الترجمة

أنشئ ملف JSON واحداً لكل لغة. استخدم مفاتيح متداخلة لتنظيم السلاسل حسب الميزة أو الصفحة. احتفِظ بلغة المصدر (عادةً الإنجليزية) باعتبارها المصدر الوحيد للحقيقة.

public/locales/en/translation.json
// public/locales/en/translation.json
{
  "nav": {
    "home": "Home",
    "about": "About",
    "settings": "Settings"
  },
  "greeting": "Hello, {{name}}!",
  "cart": {
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
  }
}

// public/locales/de/translation.json
{
  "nav": {
    "home": "Startseite",
    "about": "Über uns",
    "settings": "Einstellungen"
  },
  "greeting": "Hallo, {{name}}!",
  "cart": {
    "itemCount_one": "{{count}} Artikel",
    "itemCount_other": "{{count}} Artikel"
  }
}
سمِّ المفاتيح بحسب ما تصفه، لا بحسب مكان ظهوره: "cart.itemCount" أفضل من "homepageCartLabel". يجب أن تصمد المفاتيح أمام إعادة تصميم واجهة المستخدم.
5

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

استدعِ useTranslation() في أي مكوّن للحصول على الدالة t(). استخدمها للسلاسل البسيطة، والمتغيرات المُستوفاة، والترجمات المُضمّنة في JSX باستخدام المكوّن Trans.

Greeting.tsx
import { useTranslation } from 'react-i18next';

function Greeting({ userName }: { userName: string }) {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('greeting', { name: userName })}</h1>
      <nav>
        <a href="/">{t('nav.home')}</a>
        <a href="/about">{t('nav.about')}</a>
      </nav>
    </div>
  );
}
Trans component for JSX
import { Trans, useTranslation } from 'react-i18next';

// For JSX inside translations:
// "terms": "By signing up, you agree to our <link>Terms</link>."

function SignUp() {
  const { t } = useTranslation();
  return (
    <Trans i18nKey="terms" components={{
      link: <a href="/terms" className="underline" />
    }} />
  );
}
المفاتيح الديناميكية مثل t(`error.$'{code}'`) تعمل وقت التشغيل، لكنها لا تُستخرج بشكل ثابت بواسطة أدوات مثل i18next-scanner. إذا كنت تستخدم أدوات الاستخراج، فأدرِج المفاتيح الديناميكية صراحةً أو استخدم تلميحاً عبر تعليق.
6

التعامل مع صيغ الجمع والمتغيرات

يتعامل i18next مع صيغ الجمع باستخدام قواعد CLDR، وليس فقط مفرداً وجمعاً. للعربية 6 صيغ (zero و one و two و few و many و other). ولليابانية صيغة واحدة (other). عرّف جميع الصيغ المطلوبة في ملفات الترجمة، وسيختار i18next الصيغة الصحيحة تلقائياً.

Plural forms by language
// English: 2 forms (one, other)
{
  "itemCount_one": "{{count}} item",
  "itemCount_other": "{{count}} items"
}

// Arabic: 6 forms (zero, one, two, few, many, other)
{
  "itemCount_zero": "لا عناصر",
  "itemCount_one": "عنصر واحد",
  "itemCount_two": "عنصران",
  "itemCount_few": "{{count}} عناصر",
  "itemCount_many": "{{count}} عنصرًا",
  "itemCount_other": "{{count}} عنصر"
}

// Japanese: 1 form (other)
{
  "itemCount_other": "{{count}}個のアイテム"
}
لا تضع شرطاً ثابتاً count === 1 لاكتشاف المفرد. تتعامل لغات مثل الفرنسية مع 0 على أنه مفرد. وتملك الروسية والعربية والبولندية صيغاً لا توجد في الإنجليزية. دع i18next يتولى قواعد صيغ الجمع.
7

إضافة تبديل اللغة والاكتشاف

ابنِ محدِّد لغة يستدعي i18n.changeLanguage(). واجمعه مع كاشف لغة المتصفح لاكتشاف لغة المستخدم المفضلة تلقائياً عند الزيارة الأولى، ثم ثبّت اختياره الصريح.

LanguageSwitcher.tsx
import { useTranslation } from 'react-i18next';

const LANGUAGES = [
  { code: 'en', label: 'English' },
  { code: 'de', label: 'Deutsch' },
  { code: 'ja', label: '日本語' },
  { code: 'es', label: 'Español' },
];

function LanguageSwitcher() {
  const { i18n } = useTranslation();

  return (
    <select
      value={i18n.language}
      onChange={(e) => i18n.changeLanguage(e.target.value)}
    >
      {LANGUAGES.map(({ code, label }) => (
        <option key={code} value={code}>{label}</option>
      ))}
    </select>
  );
}
إذا كنت تستخدم SSR (Next.js، Remix)، فقد يكتشف الخادم لغةً مختلفةً عن العميل (لأن الخادم لا يملك تفضيلات المتصفح). يؤدي ذلك إلى عدم تطابق في hydration. الحل: مرّر المحلية المكتشفة من الخادم إلى العميل عبر prop أو cookie، بحيث يعرض الاثنان اللغة نفسها.
8

أتمتة الترجمات

بعد اكتمال إعداد i18n، ترجم ملفات المحلية باستخدام الذكاء الاصطناعي. في IDE، اطلب من مساعدك بالذكاء الاصطناعي ترجمة ملف المصدر، أو استخدم i18n Agent CLI ضمن مسار CI/CD.

Terminal
# In your IDE, ask your AI assistant:
> Translate public/locales/en/translation.json to German, Japanese, and Spanish

✓ de/translation.json created (1.2s)
✓ ja/translation.json created (1.5s)
✓ es/translation.json created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate public/locales/en/translation.json --lang de,ja,es
ترجم تدريجياً؛ فعندما تضيف مفاتيح جديدة إلى ملف المصدر، ترجم الفرق فقط بدلاً من إعادة توليد جميع الملفات. يحافظ ذلك على أي ترجمات تمت مراجعتها بشرياً.

أتمتة جودة الترجمة

اكتشف المفاتيح المفقودة والعناصر النائبة المعطلة قبل الإصدار باستخدام i18n-validate. واختبر واجهة المستخدم بترجمات زائفة باستخدام i18n-pseudo قبل وصول الترجمات الحقيقية.

الأخطاء الشائعة

تُعرَض مفاتيح خام بدلاً من الترجمات

الأسباب: غياب I18nextProvider، أو عدم استيراد تهيئة i18n في جذر التطبيق، أو عدم تحميل مساحة الأسماء، أو أن الترجمات ما تزال تُحمّل بشكل غير متزامن. راجع وحدة تحكّم المتصفح مع debug: true للحصول على مؤشرات.

خطأ Suspense بدون Fallback

"A component suspended while responding to synchronous input" — أضف حد '&lt;Suspense&gt;' حول تطبيقك، أو اضبط useSuspense: false في تهيئة i18next init.

عدم تطابق hydration في SSR

يعرض الخادم محليةً واحدة، ثم يقوم العميل بعملية hydration باستخدام محلية أخرى. تأكد من استخدامهما لمصدر المحلية نفسه؛ مرّرها كـ prop من الخادم، ولا تعتمد على اكتشاف المتصفح وحده.

لا يوجد إكمال تلقائي لمفاتيح الترجمة

وسّع وحدة i18next بنوع الموارد لديك: declare module 'i18next' '{ interface CustomTypeOptions { resources: typeof resources } }'. يمنحك ذلك استدعاءات t() آمنة من حيث الأنواع مع إكمال تلقائي.

بنية الملفات الموصى بها

Project Structure
my-react-app/
├── public/
│   └── locales/
│       ├── en/
│       │   ├── translation.json    # Default namespace
│       │   ├── common.json         # Shared strings
│       │   └── dashboard.json      # Feature namespace
│       ├── de/
│       │   ├── translation.json
│       │   ├── common.json
│       │   └── dashboard.json
│       └── ja/
│           └── ...
├── src/
│   ├── i18n.ts                     # i18n configuration
│   ├── main.tsx                    # App entry with Provider
│   ├── App.tsx
│   └── components/
│       └── LanguageSwitcher.tsx
└── package.json

جرّب i18n Agent الآن

أفلت ملف الترجمة هنا

JSON, YAML, PO, XML, CSV, Markdown, Properties

أو انقر للاستعراض

اللغات المستهدفة

لا حاجة إلى التسجيلتقدير فوري

الأسئلة الشائعة