Skip to main content

Пълното ръководство за интернационализация на React

От нулата до многоезично приложение: настройте i18n във Вашето React приложение и автоматизирайте преводите с ИИ.

1

Инсталирайте пакетите

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

react-i18next предоставя React hooks и компоненти. 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", най-честата причина е липсващ 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 или бисквитка, така че и двата да визуализират един и същ език.
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 без резервно съдържание

"A component suspended while responding to synchronous input" — добавете граница '&lt;Suspense&gt;' около приложението си или задайте useSuspense: false в конфигурацията за инициализация на 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

или натиснете, за да изберете файл

Целеви езици

Не се изисква регистрацияНезабавна оценка

Често задавани въпроси