Skip to main content

O guia completo da internacionalização em React

De um idioma a vários: configure i18n na sua aplicação React e automatize as traduções com IA.

1

Instalar os pacotes

Precisa de três pacotes: react-i18next —as associações React—, i18next —a biblioteca principal— e, opcionalmente, i18next-browser-languagedetector para detetar automaticamente a região.

react-i18next fornece hooks e componentes React. i18next é o motor principal que trata do carregamento das traduções, da interpolação e da pluralização. O plugin de deteção lê automaticamente a preferência de idioma do navegador.
Terminal
npm install react-i18next i18next i18next-browser-languagedetector i18next-http-backend
2

Configurar a instância de i18n

Crie um ficheiro de configuração de i18n que inicialize i18next com o idioma predefinido, os recursos de tradução e a cadeia de plugins. Este ficheiro tem de ser importado no ponto de entrada da aplicação antes de qualquer componente ser apresentado.

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»: este erro significa que se esqueceu de chamar i18n.use(initReactI18next) antes de i18n.init(). A chamada .use() tem de preceder .init().
3

Envolver a aplicação com I18nextProvider

Importe o ficheiro de configuração de i18n na raiz da aplicação e envolva a árvore de componentes com I18nextProvider. Sem isto, useTranslation() devolve chaves em bruto em vez de texto traduzido.

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>
);
Se as traduções mostrarem chaves em bruto, como «welcome», em vez de «Welcome to our app», a causa mais frequente é a ausência de I18nextProvider ou a falta de importação do ficheiro de configuração de i18n.
4

Criar ficheiros de tradução

Crie um ficheiro JSON por idioma. Utilize chaves aninhadas para organizar as cadeias por funcionalidade ou página. Mantenha o idioma de origem —normalmente inglês— como única fonte de referência.

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"
  }
}
Dê às chaves nomes que descrevam o conteúdo, não o local onde aparece: «cart.itemCount» é melhor do que «homepageCartLabel». As chaves devem sobreviver a alterações na interface.
5

Utilizar traduções nos componentes

Chame useTranslation() em qualquer componente para obter a função t(). Utilize-a para cadeias simples, variáveis interpoladas e traduções com JSX incorporado através do componente 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" />
    }} />
  );
}
As chaves dinâmicas como t(`error.$'{code}'`) funcionam durante a execução, mas ferramentas como i18next-scanner não conseguem extraí-las estaticamente. Se utilizar ferramentas de extração, indique explicitamente as chaves dinâmicas ou acrescente uma sugestão num comentário.
6

Tratar plurais e variáveis

i18next trata os plurais segundo as regras CLDR, não apenas singular e plural. O árabe tem 6 formas —zero, one, two, few, many e other— e o japonês tem 1 —other—. Defina todas as formas necessárias nos ficheiros de tradução e i18next seleciona automaticamente a correta.

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}}個のアイテム"
}
Nunca codifique diretamente count === 1 para detetar o singular. Idiomas como o francês consideram 0 singular. O russo, o árabe e o polaco têm formas inexistentes em inglês. Deixe i18next tratar as regras de plural.
7

Adicionar seleção e deteção do idioma

Crie um seletor de idioma que chame i18n.changeLanguage(). Combine-o com o detetor do navegador para identificar automaticamente o idioma preferido do utilizador na primeira visita e guardar depois a escolha explícita.

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>
  );
}
Se utilizar SSR —Next.js ou Remix—, o servidor pode detetar um idioma diferente do cliente, pois não tem acesso às preferências do navegador. Isto provoca uma incompatibilidade de hidratação. Solução: passe a região detetada do servidor para o cliente como propriedade ou cookie, para ambos apresentarem o mesmo idioma.
8

Automatizar as traduções

Depois de concluir a configuração de i18n, traduza os ficheiros regionais com IA. No IDE, peça ao assistente para traduzir o ficheiro de origem ou utilize a CLI do i18n Agent no seu pipeline de 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
Traduza de forma incremental: quando adicionar novas chaves ao ficheiro de origem, traduza apenas as diferenças em vez de gerar novamente todos os ficheiros. Assim preserva as traduções revistas por pessoas.

Automatizar a qualidade das traduções

Detete chaves em falta e marcadores danificados antes da publicação com i18n-validate. Teste a interface com traduções simuladas através de i18n-pseudo antes de chegarem as traduções reais.

Erros frequentes

As traduções mostram chaves em bruto

Causas: falta I18nextProvider, a configuração de i18n não foi importada na raiz da aplicação, o espaço de nomes não foi carregado ou as traduções ainda estão a carregar assincronamente. Procure pistas na consola do navegador com debug: true.

Erro de Suspense sem alternativa

«A component suspended while responding to synchronous input»: adicione um limite '&lt;Suspense&gt;' em torno da aplicação ou defina useSuspense: false na configuração de init de i18next.

Incompatibilidade da hidratação SSR

O servidor apresenta uma região e o cliente hidrata noutra. Garanta que ambos utilizam a mesma origem regional: passe-a como propriedade do servidor e não dependa apenas da deteção no navegador.

Sem conclusão automática das chaves de tradução

Amplie o módulo i18next com o tipo do seu recurso: declare module 'i18next' '{ interface CustomTypeOptions { resources: typeof resources } }'. Assim, as chamadas t() ficam seguras quanto ao tipo e com conclusão automática.

Estrutura de ficheiros recomendada

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

Experimente já o i18n Agent

Largue aqui o seu ficheiro de tradução

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

ou clique para selecionar

Idiomas de destino

Sem registoEstimativa imediata

Perguntas frequentes