Skip to main content

Išsamus React internacionalizavimo vadovas

Nuo nulio iki kelių kalbų: sukonfigūruokite i18n React programoje, tada automatizuokite vertimus naudodami DI.

1

Įdiegti paketus

Reikia trijų paketų: react-i18next (React susiejimų), i18next (pagrindinės bibliotekos) ir, jei norite, i18next-browser-languagedetector automatiniam lokalių aptikimui.

react-i18next suteikia React kablius ir komponentus. i18next yra pagrindinis variklis, tvarkantis vertimų įkėlimą, interpoliavimą ir daugiskaitą. Kalbos aptikimo papildinys automatiškai nuskaito naršyklėje pasirinktą kalbą.
Terminal
npm install react-i18next i18next i18next-browser-languagedetector i18next-http-backend
2

Sukonfigūruoti i18n egzempliorių

Sukurkite i18n konfigūracijos failą, kuris inicijuoja i18next su numatytąja kalba, vertimo ištekliais ir papildinių grandine. Šį failą reikia importuoti programos įėjimo taške prieš atvaizduojant bet kurį komponentą.

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“ – ši klaida reiškia, kad prieš i18n.init() pamiršote iškviesti i18n.use(initReactI18next). .use() reikia iškviesti prieš .init().
3

Apgaubti programą I18nextProvider

Importuokite i18n konfigūracijos failą programos šaknyje ir apgaubkite komponentų medį I18nextProvider. Be jo useTranslation() grąžina ne išverstą tekstą, o neapdorotus raktus.

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>
);
Jei vietoje „Sveiki atvykę į mūsų programą“ vertimuose rodomi neapdoroti raktai, pavyzdžiui, „welcome“, dažniausiai trūksta I18nextProvider arba neimportuotas i18n konfigūracijos failas.
4

Sukurti vertimo failus

Sukurkite po vieną JSON failą kiekvienai kalbai. Eilutes pagal funkciją ar puslapį tvarkykite įdėtiniais raktais. Šaltinio kalbą (paprastai anglų) laikykite vieninteliu patikimu šaltiniu.

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"
  }
}
Raktus pavadinkite pagal tai, ką jie apibūdina, o ne kur rodomi: „cart.itemCount“ geriau nei „homepageCartLabel“. Raktai turėtų išlikti pertvarkius UI.
5

Naudoti vertimus komponentuose

Iškvieskite useTranslation() bet kuriame komponente, kad gautumėte funkciją t(). Naudokite ją paprastoms eilutėms, interpoliuojamiems kintamiesiems ir su JSX įterptiems vertimams su komponentu 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" />
    }} />
  );
}
Dinaminiai raktai, pavyzdžiui, t(`error.$'{code}'`), veikia vykdymo metu, tačiau tokie įrankiai kaip i18next-scanner negali jų statiškai išskirti. Jei naudojate išskyrimo įrankius, aiškiai išvardykite dinaminius raktus arba naudokite komentaro užuominą.
6

Apdoroti daugiskaitą ir kintamuosius

i18next daugiskaitą apdoro pagal CLDR taisykles, o ne vien pagal vienaskaitą ir daugiskaitą. Arabų kalboje yra 6 formos (zero, one, two, few, many, other), japonų – 1 (other). Vertimo failuose apibrėžkite visas būtinas formas, o i18next automatiškai parinks tinkamą.

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}}個のアイテム"
}
Niekada neįrašykite count === 1 tiesiogiai vienaskaitai aptikti. Tokiose kalbose kaip prancūzų 0 laikomas vienaskaita. Rusų, arabų ir lenkų kalbos turi anglų kalboje neegzistuojančių formų. Leiskite i18next apdoroti daugiskaitos taisykles.
7

Pridėti kalbos keitimą ir aptikimą

Sukurkite kalbos parinkiklį, kuris iškviečia i18n.changeLanguage(). Sujunkite jį su naršyklės kalbos aptikimo priemone, kad per pirmą apsilankymą automatiškai aptiktumėte naudotojo pageidaujamą kalbą, o tada įsimintumėte aiškiai pasirinktą kalbą.

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>
  );
}
Jei naudojate SSR (Next.js, Remix), serveris gali aptikti kitą kalbą nei klientas, nes serveryje nėra naršyklės nuostatų. Dėl to neatitinka hidratacija. Sprendimas: perduokite serveryje aptiktą lokalę klientui kaip ypatybę arba slapuką, kad abu atvaizduotų tą pačią kalbą.
8

Automatizuoti vertimus

Baigę i18n sąranką išverskite lokalės failus naudodami DI. IDE paprašykite DI asistento išversti šaltinio failą arba CI/CD konvejeryje naudokite i18n Agent CLI.

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
Verskite palaipsniui – pridėję naujų raktų prie šaltinio failo išverskite tik skirtumą, o ne generuokite visus failus iš naujo. Taip išsaugosite žmonių peržiūrėtus vertimus.

Automatizuoti vertimo kokybę

Naudodami i18n-validate prieš išleidimą aptikite trūkstamus raktus ir sugadintus vietos rezervavimo ženklus. Kol dar nėra tikrų vertimų, patikrinkite UI su netikrais i18n-pseudo vertimais.

Dažnos klaidos

Vertimuose rodomi neapdoroti raktai

Priežastys: trūksta I18nextProvider, programos šaknyje neimportuota i18n konfigūracija, neįkelta vardų sritis arba vertimai vis dar įkeliami asinchroniškai. Užuominų ieškokite naršyklės konsolėje įjungę debug: true.

Suspense klaida be atsarginės būsenos

„A component suspended while responding to synchronous input“ – apgaubkite programą '&lt;Suspense&gt;' riba arba i18next init konfigūracijoje nustatykite useSuspense: false.

SSR hidratacijos neatitiktis

Serveris atvaizduoja viena lokale, o klientas hidratuoja kita. Užtikrinkite, kad abu naudotų tą patį lokalės šaltinį – perduokite jį iš serverio kaip ypatybę ir nepasikliaukite vien naršyklės aptikimu.

Nėra automatinio vertimo raktų užbaigimo

Papildykite i18next modulį savo išteklių tipu: declare module 'i18next' '{ interface CustomTypeOptions { resources: typeof resources } }'. Taip t() iškvietimai bus tipų požiūriu saugūs ir automatiškai užbaigiami.

Rekomenduojama failų struktūra

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

Išbandykite i18n Agent dabar

Nuvilkite vertimo failą čia

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

arba spustelėkite norėdami pasirinkti

Tikslinės kalbos

Registruotis nereikiaMomentinis įvertis

Dažnai užduodami klausimai