Skip to main content

دليل react-intl: إعداد التدويل في React

اضبط FormatJS react-intl في تطبيق React لديك باستخدام IntlProvider وFormattedMessage وuseIntl وICU message format والترجمات المؤتمتة.

هل تستخدم react-i18next بدلاً من ذلك؟ اطّلع على دليل react-i18next لدينا

1

تثبيت react-intl

react-intl جزء من مشروع FormatJS. يوفّر مكوّنات وخطافات React لتنسيق السلاسل النصية والأرقام والتواريخ وصيغ الجمع باستخدام معيار ICU MessageFormat.

لا يملك react-intl أي تبعيات وقت تشغيل خارج React. يستخدم API ‏Intl المدمجة في المتصفح لتنسيق الأرقام والتواريخ، ويضم محلل ICU MessageFormat خاصاً به لصيغ الجمع وselect والنص الغني.
Terminal
npm install react-intl
2

تهيئة IntlProvider

غلِّف تطبيقك بـ IntlProvider عند الجذر. مرِّر اللغة النشطة وكائن رسائل مسطّحاً. عندها يمكن لكل مكوّن في الأسفل الوصول إلى الترجمات عبر FormattedMessage أو useIntl.

src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { IntlProvider } from 'react-intl';
import App from './App';
import enMessages from './messages/en.json';
import deMessages from './messages/de.json';

const messages: Record<string, Record<string, string>> = {
  en: enMessages,
  de: deMessages,
};

// Detect locale from browser or your routing layer
const locale = navigator.language.split('-')[0] || 'en';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <IntlProvider locale={locale} messages={messages[locale] || messages.en}>
      <App />
    </IntlProvider>
  </React.StrictMode>
);
يتطلب IntlProvider كائن رسائل مسطّحاً من نوع مفتاح-قيمة (مثل: { "app.greeting": "Hello" }). يجب تسطيح JSON المتداخل قبل تمريره إلى IntlProvider، أو استخدام أداة مثل flat لتحويل البنى المتداخلة.

ملفات الرسائل

أنشئ ملف JSON واحداً لكل لغة. يستخدم react-intl صياغة ICU MessageFormat بشكل أصيل؛ إذ تُكتب صيغ الجمع وselect والمتغيرات كلها مباشرةً داخل سلاسل الرسائل.

messages/en.json & messages/de.json
// messages/en.json
{
  "app.greeting": "Hello, {name}!",
  "nav.home": "Home",
  "nav.about": "About",
  "nav.settings": "Settings",
  "cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart"
}

// messages/de.json
{
  "app.greeting": "Hallo, {name}!",
  "nav.home": "Startseite",
  "nav.about": "Über uns",
  "nav.settings": "Einstellungen",
  "cart.itemCount": "{count, plural, one {# Artikel} other {# Artikel}} in Ihrem Warenkorb"
}
استخدم معرّفات مفصولة بنقطة مثل "nav.home" للتنظيم. بخلاف react-i18next، يتوقع react-intl كائن رسائل مسطّحاً؛ أي إنك تُسطّح المفاتيح لا البنية.
3

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

يقدّم react-intl واجهتَي API أساسيتين: مكوّن FormattedMessage لعرض JSX مترجماً، وخطاف useIntl للوصول الإجرائي (placeholders وaria labels والتنسيق البرنامجي).

مكوّن FormattedMessage

استخدم FormattedMessage للترجمات التصريحية في JSX. مرِّر معرّف الرسالة وأي قيم استبدال. وسيعرض السلسلة المترجمة مباشرةً.

Greeting.tsx
import { FormattedMessage } from 'react-intl';

function Greeting({ userName }: { userName: string }) {
  return (
    <div>
      <h1>
        <FormattedMessage
          id="app.greeting"
          values={{ name: userName }}
        />
      </h1>
      <nav>
        <a href="/"><FormattedMessage id="nav.home" /></a>
        <a href="/about"><FormattedMessage id="nav.about" /></a>
      </nav>
    </div>
  );
}

خطاف useIntl

استخدم useIntl() عندما تحتاج إلى السلسلة المترجمة كقيمة عادية؛ مثل placeholders لحقول الإدخال وaria-labels وdocument.title، أو عند تمرير سلاسل نصية إلى API غير تابعة لـ React. كما يوفّر formatNumber وformatDate وformatRelativeTime.

SearchBar.tsx
import { useIntl } from 'react-intl';

function SearchBar() {
  const intl = useIntl();

  return (
    <input
      type="search"
      placeholder={intl.formatMessage({ id: 'search.placeholder' })}
      aria-label={intl.formatMessage({ id: 'search.ariaLabel' })}
    />
  );
}

// useIntl also gives you formatNumber, formatDate, formatRelativeTime:
function PriceTag({ amount, currency }: { amount: number; currency: string }) {
  const intl = useIntl();
  return (
    <span>{intl.formatNumber(amount, { style: 'currency', currency })}</span>
  );
}

النص الغني (HTML في الترجمات)

ضمّن JSX داخل الترجمات باستخدام وسوم شبيهة بـ XML ضمن سلاسل الرسائل. مرِّر معالجات الوسوم عبر الخاصية values لعرض الروابط أو النص العريض أو أي مكوّن React داخل رسالة مترجمة.

SignUp.tsx
import { FormattedMessage } from 'react-intl';

// Message: "By signing up, you agree to our <link>Terms</link>."
// Key: "signup.terms"
// Value: "By signing up, you agree to our <link>Terms</link>."

function SignUp() {
  return (
    <FormattedMessage
      id="signup.terms"
      values={{
        link: (chunks) => <a href="/terms" className="underline">{chunks}</a>,
      }}
    />
  );
}
يعرض FormattedMessage ‏React Fragment افتراضياً. إذا كنت بحاجة إلى عنصر غلاف محدد، فمرِّر الخاصية textComponent إلى IntlProvider أو غلِّف FormattedMessage بعنصر من إنشائك.

استخراج الرسائل باستخدام @formatjs/cli

يوفّر FormatJS أداة CLI لاستخراج معرّفات الرسائل تلقائياً من شفرتك المصدرية إلى ملف JSON. يضمن ذلك بقاء ملف الرسائل متزامناً مع مكوّناتك دون متابعة يدوية.

Terminal
# Install the CLI
npm install -g @formatjs/cli

# Extract messages from source code into a JSON file
formatjs extract 'src/**/*.tsx' --out-file messages/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'

# Or use explicit IDs (recommended):
formatjs extract 'src/**/*.tsx' --out-file messages/en.json

# Compile messages for production (optional, improves perf)
formatjs compile messages/en.json --out-file compiled/en.json
formatjs compile messages/de.json --out-file compiled/de.json
4

صيغ الجمع وICU Select

يستخدم react-intl صياغة ICU MessageFormat بشكل أصيل. تُعبَّر صيغ الجمع وselect القائم على النوع والتنسيق المتداخل مباشرةً داخل سلاسل الرسائل؛ ولا حاجة إلى اصطلاحات لواحق أو مفاتيح منفصلة.

ICU plural syntax by language
// ICU MessageFormat syntax — react-intl uses this natively
// English
{
  "cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart",
  "inbox.unread": "You have {count, plural, =0 {no unread messages} one {# unread message} other {# unread messages}}"
}

// Arabic — 6 plural forms
{
  "cart.itemCount": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}} في سلتك"
}

// Japanese — 1 form (other)
{
  "cart.itemCount": "カートに{count}個の商品があります"
}
لا تُضمِّن منطق الجمع في JavaScript يدوياً مطلقاً. فلغات مثل العربية لديها 6 صيغ للجمع، وتتعامل الفرنسية مع 0 كمفرد، ولا تمتلك اليابانية تمييزاً للجمع. دع ICU MessageFormat يتولى القواعد؛ ما عليك إلا تمرير قيمة count.

ICU Select للنوع والأدوار

استخدم صياغة ICU select للترجمات المعتمدة على السياق مثل النوع وأدوار المستخدم أو قيم الحالة. يختار تعبير select المتغير الصحيح بناءً على القيمة المقدَّمة.

ICU select syntax
// Gender-dependent messages using ICU select
{
  "user.greeting": "{gender, select, male {He} female {She} other {They}} liked your post.",
  "user.invitation": "{role, select, admin {You can manage all settings.} editor {You can edit content.} other {You can view content.}}"
}

// Usage:
<FormattedMessage
  id="user.greeting"
  values={{ gender: user.gender }}
/>

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

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

المزالق الشائعة

الاعتماد المفرط على defaultMessage

يُعد defaultMessage خيار رجوع أثناء التطوير، وليس استراتيجية ترجمة. إذا استخدمت defaultMessage لجميع السلاسل، فسيحتوي ناتج استخراج الرسائل على النص الإنجليزي، لكن قد يفوّت المترجمون مفاتيح جديدة. احرص دائماً على استخراج ملف لغة مصدر كامل وصيانته.

كائنات متداخلة بدلاً من مفاتيح مسطّحة

يتوقع IntlProvider قيمة messages على شكل Record&lt;string, string&gt; مسطّح. إذا مرّرت JSON متداخلاً مثل { nav: { home: "Home" } }, فلن يعثر react-intl على المفتاح "nav.home". سطّح رسائلك قبل تمريرها، أو استخدم مكتبة مثل flat.

IntlProvider يسبّب إعادة العرض

إذا أنشأت كائن messages داخل دالة render، فسيتلقى IntlProvider مرجع كائن جديداً عند كل إعادة عرض، ما يؤدي إلى إعادة عرض جميع المستهلكين. استخدم useMemo لتثبيت messages أو عرّفها خارج المكوّن.

غياب IntlProvider في الاختبارات

ستُطلق المكوّنات التي تستخدم FormattedMessage أو useIntl خطأً إذا عُرضت دون وجود IntlProvider في السلسلة العليا. في الاختبارات، غلِّف مكوّنك بـ IntlProvider مع locale="en" وكائن messages فارغ أو minimal.

هيكل الملفات الموصى به

Project Structure
my-react-app/
├── messages/
│   ├── en.json              # Source of truth (English)
│   ├── de.json              # German
│   ├── ja.json              # Japanese
│   └── es.json              # Spanish
├── compiled/                # Optional: compiled messages for prod
│   ├── en.json
│   └── ...
├── src/
│   ├── main.tsx             # App entry with IntlProvider
│   ├── App.tsx
│   └── components/
│       ├── Greeting.tsx      # Uses FormattedMessage
│       └── SearchBar.tsx     # Uses useIntl
└── package.json

جرّب i18n Agent الآن

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

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

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

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

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

الرجوع الاحتياطي للغة باستخدام react-intl-locale-chain

عندما يكون مفتاح ترجمة مفقوداً في لغة إقليمية مثل pt-BR، ينتقل react-intl مباشرةً إلى اللغة الافتراضية بدلاً من التحقق أولاً من اللغة الأم pt.

Terminal
npm install react-intl-locale-chain
Configuration
<LocaleChainProvider
  fallbacks={{
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  }}
  defaultLocale="en"
>
  <App />
</LocaleChainProvider>

اطّلع على دليل الرجوع الاحتياطي للغة لدينا للاطلاع على القائمة الكاملة للأُطر المدعومة و75 سلسلة مدمجة. Learn more →

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