Skip to main content

Guida a react-intl: configurazione dell'internazionalizzazione React

Configuri FormatJS react-intl nell'app React con IntlProvider, FormattedMessage, useIntl, il formato dei messaggi ICU e traduzioni automatizzate.

Preferisce react-i18next? Consulti la guida a react-i18next

1

Installare react-intl

react-intl fa parte del progetto FormatJS. Offre componenti e hook React per formattare stringhe, numeri, date e plurali secondo lo standard ICU MessageFormat.

Oltre a React, react-intl non ha dipendenze di runtime. Usa l'API Intl integrata nel browser per formattare numeri e date e include un proprio parser ICU MessageFormat per plurali, select e testo avanzato.
Terminal
npm install react-intl
2

Configurare IntlProvider

Racchiuda l'app con IntlProvider nella radice. Passi la lingua attiva e un oggetto semplice messages. Ogni componente sottostante potrà quindi accedere alle traduzioni tramite FormattedMessage o 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 richiede un oggetto messages semplice con coppie chiave-valore (ad esempio, { "app.greeting": "Hello" }). Il JSON annidato deve essere appiattito prima di essere passato a IntlProvider; in alternativa, usi uno strumento come flat per convertire le strutture annidate.

File dei messaggi

Crei un file JSON per ogni lingua. react-intl usa in modo nativo la sintassi ICU MessageFormat: plurali, select e variabili vengono espressi direttamente nelle stringhe dei messaggi.

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"
}
Per organizzare i messaggi, usi ID separati da punti come "nav.home". A differenza di react-i18next, react-intl richiede un oggetto messages semplice: vengono appiattite le chiavi, non la struttura.
3

Usare le traduzioni nei componenti

react-intl offre due API principali: il componente FormattedMessage per visualizzare JSX tradotto e l'hook useIntl per l'accesso imperativo, ad esempio segnaposto, etichette aria e formattazione programmatica.

Componente FormattedMessage

Usi FormattedMessage per le traduzioni dichiarative in JSX. Passi l'ID del messaggio e gli eventuali valori di interpolazione. Il componente visualizza direttamente la stringa tradotta.

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

Usi useIntl() quando Le serve la stringa tradotta come valore semplice, ad esempio per segnaposto degli input, aria-label, document.title o per passare stringhe ad API non React. Fornisce inoltre 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>
  );
}

Testo avanzato (HTML nelle traduzioni)

Incorpori JSX nelle traduzioni usando tag simili a XML nelle stringhe dei messaggi. Passi i gestori dei tag tramite la proprietà values per visualizzare link, testo in grassetto o qualsiasi componente React in un messaggio tradotto.

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>,
      }}
    />
  );
}
Per impostazione predefinita, FormattedMessage visualizza un frammento React. Se Le serve un elemento contenitore specifico, passi la proprietà textComponent a IntlProvider oppure racchiuda FormattedMessage in un elemento personalizzato.

Estrazione dei messaggi con @formatjs/cli

FormatJS offre una CLI che estrae automaticamente dal codice sorgente gli ID dei messaggi in un file JSON. In questo modo, il file dei messaggi rimane sincronizzato con i componenti senza operazioni manuali di registrazione.

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

Plurali e select ICU

react-intl usa in modo nativo ICU MessageFormat. Plurali, select in base al genere e formattazione annidata vengono espressi direttamente nelle stringhe dei messaggi: non servono convenzioni per i suffissi né chiavi separate.

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}個の商品があります"
}
Non codifichi mai direttamente in JavaScript la logica del plurale. Lingue come l'arabo hanno 6 forme plurali, il francese considera 0 singolare e il giapponese non distingue il plurale. Lasci che ICU MessageFormat gestisca le regole: passi soltanto il valore del conteggio.

Select ICU per genere e ruoli

Usi la sintassi select ICU per traduzioni che dipendono dal contesto, ad esempio genere, ruoli utente o valori di stato. L'espressione select sceglie la variante corretta in base al valore fornito.

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

Automatizzare la qualità

Con i18n-validate, rilevi chiavi mancanti e segnaposto non validi prima del rilascio. Testi l'interfaccia con le pseudotraduzioni di i18n-pseudo prima che arrivino le traduzioni reali.

Problemi comuni

Dipendenza eccessiva da defaultMessage

defaultMessage è un fallback di sviluppo, non una strategia di traduzione. Se usa defaultMessage per tutte le stringhe, l'output di estrazione dei messaggi conterrà il testo inglese, ma i traduttori potrebbero non notare le nuove chiavi. Estragga e mantenga sempre un file completo della lingua di origine.

Oggetti annidati anziché chiavi semplici

IntlProvider richiede per messages un Record&lt;string, string&gt; semplice. Se passa un JSON annidato come { nav: { home: "Home" } }, react-intl non troverà la chiave "nav.home". Appiattisca i messaggi prima di passarli oppure usi una biblioteca come flat.

IntlProvider causa nuovi rendering

Se crea l'oggetto messages direttamente nella funzione di rendering, IntlProvider riceve un nuovo riferimento a ogni rendering, causando un nuovo rendering per tutti i componenti che lo usano. Memorizzi messages con useMemo oppure lo definisca fuori dal componente.

IntlProvider mancante nei test

I componenti che usano FormattedMessage o useIntl generano un'eccezione se vengono visualizzati senza un elemento IntlProvider precedente. Nei test, racchiuda il componente in IntlProvider con locale="en" e un oggetto messages vuoto o minimo.

Struttura dei file consigliata

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

Provi subito i18n Agent

Trascinare qui il file di traduzione

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

oppure fare clic per selezionarlo

Lingue di destinazione

Nessuna registrazione richiestaPreventivo immediato

Fallback della lingua con react-intl-locale-chain

Quando manca una chiave di traduzione in una lingua regionale come pt-BR, react-intl passa direttamente alla lingua predefinita anziché controllare prima la lingua principale 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>

Consultare la Guida al fallback delle lingue per l'elenco completo dei framework supportati e delle 75 catene integrate. Learn more →

Domande frequenti