Skip to main content

Guia de react-intl: configurar a internacionalização em React

Configure FormatJS react-intl na sua aplicação React com IntlProvider, FormattedMessage, useIntl, formato de mensagens ICU e traduções automatizadas.

Prefere utilizar react-i18next? Consultar o nosso guia de react-i18next

1

Instalar react-intl

react-intl faz parte do projeto FormatJS. Oferece componentes e hooks React para formatar cadeias, números, datas e plurais segundo a norma ICU MessageFormat.

react-intl não tem dependências de execução além de React. Utiliza a API Intl integrada no navegador para formatar números e datas e inclui o seu próprio analisador ICU MessageFormat para plurais, select e texto rico.
Terminal
npm install react-intl
2

Configurar IntlProvider

Envolva a aplicação com IntlProvider na raiz. Passe a região ativa e um objeto simples de mensagens. Todos os componentes abaixo poderão aceder às traduções através de FormattedMessage ou 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 exige um objeto simples de mensagens com pares de chave e valor —por exemplo, { "app.greeting": "Hello" }—. O JSON aninhado tem de ser achatado antes de ser passado ou convertido através de uma ferramenta como flat.

Ficheiros de mensagens

Crie um ficheiro JSON por região. react-intl utiliza nativamente a sintaxe ICU MessageFormat: plurais, select e variáveis são expressos em linha nas cadeias das mensagens.

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"
}
Utilize ID separados por pontos, como «nav.home», para organizar. Ao contrário de react-i18next, react-intl espera um objeto simples de mensagens: achata as chaves, não a estrutura.
3

Utilizar traduções nos componentes

react-intl oferece duas API principais: o componente FormattedMessage para apresentar JSX traduzido e o hook useIntl para acesso imperativo —marcadores, etiquetas aria e formatação programática—.

Componente FormattedMessage

Utilize FormattedMessage para traduções declarativas em JSX. Passe o ID da mensagem e os valores de interpolação. O componente apresenta diretamente a cadeia traduzida.

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>
  );
}

Hook useIntl

Utilize useIntl() quando precisar da cadeia traduzida como valor simples: em marcadores de campos, aria-labels, document.title ou API fora de React. Também oferece formatNumber, formatDate e 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>
  );
}

Texto rico (HTML nas traduções)

Incorpore JSX nas traduções através de etiquetas semelhantes a XML nas cadeias. Passe processadores de etiquetas pela propriedade values para apresentar ligações, texto a negrito ou qualquer componente React numa mensagem traduzida.

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 apresenta um React Fragment por predefinição. Se precisar de um elemento envolvente específico, passe a propriedade textComponent a IntlProvider ou envolva FormattedMessage num elemento seu.

Extração de mensagens com @formatjs/cli

FormatJS oferece uma CLI que extrai automaticamente os ID das mensagens do código-fonte para um ficheiro JSON. Assim, o ficheiro de mensagens permanece sincronizado com os componentes sem controlo manual.

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

Plurais e select de ICU

react-intl utiliza ICU MessageFormat nativamente. Os plurais, select por género e formatação aninhada são expressos diretamente nas cadeias, sem convenções de sufixos nem chaves separadas.

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}個の商品があります"
}
Nunca codifique diretamente lógica de plural em JavaScript. Idiomas como o árabe têm 6 formas, o francês considera 0 singular e o japonês não distingue plurais. Deixe ICU MessageFormat tratar as regras e passe apenas o valor count.

ICU select para género e funções

Utilize a sintaxe ICU select em traduções dependentes do contexto, como género, funções dos utilizadores ou valores de estado. A expressão escolhe a variante correta com base no valor fornecido.

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 }}
/>

Automatizar a qualidade das traduções

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

Erros frequentes

Depender demasiado de defaultMessage

defaultMessage é um recurso de desenvolvimento, não uma estratégia de tradução. Se o utilizar em todas as cadeias, o resultado da extração conterá o texto em inglês, mas os tradutores podem não reparar em novas chaves. Extraia e mantenha sempre um ficheiro regional de origem completo.

Objetos aninhados em vez de chaves simples

IntlProvider espera um Record&lt;string, string&gt; simples para as mensagens. Se passar JSON aninhado, como { nav: { home: "Home" } }, react-intl não encontrará a chave «nav.home». Achate as mensagens antes de as passar ou utilize uma biblioteca como flat.

IntlProvider provoca novas renderizações

Se criar o objeto messages em linha dentro da função de apresentação, IntlProvider recebe uma nova referência em todas as renderizações e faz todos os consumidores voltarem a renderizar. Memorize messages com useMemo ou defina-o fora do componente.

IntlProvider em falta nos testes

Os componentes que utilizam FormattedMessage ou useIntl lançam um erro se forem apresentados sem um IntlProvider ascendente. Nos testes, envolva o componente em IntlProvider com locale="en" e um objeto messages vazio ou mínimo.

Estrutura de ficheiros recomendada

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

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

Recurso regional com react-intl-locale-chain

Quando falta uma chave de tradução numa região como pt-BR, react-intl passa diretamente para a região predefinida em vez de verificar primeiro a região principal 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>

Consulte o nosso guia de recurso regional para ver a lista completa de frameworks compatíveis e as 75 cadeias integradas. Learn more →

Perguntas frequentes