Skip to main content

Повний посібник з інтернаціоналізації React

Від початку до багатомовності: налаштуйте i18n у своєму застосунку React, а потім автоматизуйте переклад за допомогою ШІ.

1

Встановити пакети

Вам потрібні три пакети: react-i18next (прив’язки React), i18next (основна бібліотека) і, за бажанням, i18next-browser-languagedetector для автоматичного визначення локалі.

react-i18next надає хуки та компоненти 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;
"You will need to pass in an i18next instance by using 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 to our app" у перекладі відображається необроблений ключ на кшталт "welcome", найчастіше причина полягає у відсутності 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). У японській — 1 (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), сервер може визначити іншу мову, ніж клієнт, адже сервер не має доступу до налаштувань браузера. Це спричиняє невідповідність під час гідратації. Виправлення: передайте визначену локаль із сервера клієнту як prop або cookie, щоб обидві сторони відтворювали ту саму мову.
8

Автоматизувати переклад

Завершивши налаштування i18n, перекладіть файли локалізації за допомогою ШІ. У своїй IDE попросіть ШІ-асистента перекласти вихідний файл або використовуйте CLI i18n Agent у pipeline 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 без резервного вмісту

"A component suspended while responding to synchronous input" — додайте межу '&lt;Suspense&gt;' навколо застосунку або задайте useSuspense: false у налаштуваннях init для i18next.

Невідповідність гідратації SSR

Сервер відтворює вміст однією локаллю, а клієнт гідратує його іншою. Переконайтеся, що обидві сторони використовують те саме джерело локалі: передайте її із сервера як 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

або натисніть, щоб вибрати

Цільові мови

Реєстрація не потрібнаМиттєвий розрахунок

Поширені запитання