Skip to main content

react-intl ガイド:React 国際化設定

IntlProvider、FormattedMessage、useIntl、ICU メッセージ形式、自動翻訳を使用して、React アプリに FormatJS react-intl を設定します。

react-i18next をお使いですか? react-i18next ガイドを見る

1

react-intl のインストール

react-intl は FormatJS プロジェクトの一部です。ICU MessageFormat 標準を使用し、文字列、数値、日付、複数形を書式設定する React コンポーネントとフックを提供します。

react-intl は React 以外の実行時依存関係がありません。数値と日付の書式設定にはブラウザー組み込みの Intl API を使用し、複数形、select、リッチテキスト向けの独自 ICU MessageFormat パーサーを同梱しています。
Terminal
npm install react-intl
2

IntlProvider の設定

アプリのルートを IntlProvider でラップします。有効なロケールとフラットな messages オブジェクトを渡すと、配下のすべてのコンポーネントが FormattedMessage または 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 には、フラットなキーと値の messages オブジェクト(例:{ "app.greeting": "Hello" })が必要です。ネストした JSON は IntlProvider に渡す前にフラット化するか、flat のようなユーティリティで変換してください。

メッセージファイル

ロケールごとに JSON ファイルを 1 つ作成します。react-intl は ICU MessageFormat 構文を標準で使用し、複数形、select、変数をすべてメッセージ文字列内に記述します。

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"
}
整理には「nav.home」のようにドットで区切った ID を使用してください。react-i18next と異なり、react-intl はフラットな messages オブジェクトを前提とするため、構造ではなくキーをフラット化します。
3

コンポーネントでの翻訳の使用

react-intl には主に 2 つの API があります。翻訳済み JSX をレンダリングする FormattedMessage コンポーネントと、命令的にアクセスする useIntl フックです。後者はプレースホルダー、aria ラベル、プログラムによる書式設定に使用します。

FormattedMessage コンポーネント

JSX で宣言的に翻訳するには FormattedMessage を使用します。メッセージ ID と補間値を渡すと、翻訳文字列が直接レンダリングされます。

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

useIntl フック

入力プレースホルダー、aria-label、document.title、React 以外の API に渡す文字列など、翻訳文字列を単純な値として必要とする場合は useIntl() を使用します。formatNumber、formatDate、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>
  );
}

リッチテキスト(翻訳内の HTML)

メッセージ文字列に XML 形式のタグを使用し、翻訳内に JSX を埋め込みます。values prop でタグハンドラーを渡すことで、翻訳メッセージ内にリンク、太字テキスト、任意の React コンポーネントをレンダリングできます。

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 はデフォルトで React Fragment をレンダリングします。特定のラッパー要素が必要な場合は、IntlProvider に textComponent prop を渡すか、FormattedMessage を独自の要素でラップしてください。

@formatjs/cli によるメッセージ抽出

FormatJS は、ソースコードからメッセージ ID を JSON ファイルへ自動抽出する CLI を提供します。手動で管理しなくても、メッセージファイルをコンポーネントと同期できます。

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

複数形と ICU select

react-intl は ICU MessageFormat を標準で使用します。複数形、性別に基づく select、ネストした書式設定をすべてメッセージ文字列内に直接記述でき、サフィックス規則や個別のキーは不要です。

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}個の商品があります"
}
JavaScript に複数形ロジックをハードコードしないでください。アラビア語には 6 つの複数形があり、フランス語では 0 を単数として扱い、日本語には単数と複数の区別がありません。count 値だけを渡し、規則の処理は ICU MessageFormat に任せてください。

性別とロールに対応する ICU select

性別、ユーザーロール、ステータス値など、文脈に応じた翻訳には ICU select 構文を使用します。select 式が指定値に基づいて適切なバリエーションを選択します。

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

翻訳品質の自動管理

i18n-validate を使用すると、リリース前に欠落キーや壊れたプレースホルダーを検出できます。実際の翻訳が届く前に、i18n-pseudo の疑似翻訳で UI をテストしてください。

よくある問題

defaultMessage への過度な依存

defaultMessage は開発用のフォールバックであり、翻訳戦略ではありません。すべての文字列に defaultMessage を使用すると、メッセージ抽出の出力には英語テキストが含まれますが、翻訳者が新しいキーを見落とす可能性があります。完全なソースロケールファイルを必ず抽出し、管理してください。

フラットなキーではなくネストしたオブジェクトを使用する

IntlProvider の messages には、フラットな Record&lt;string, string&gt; が必要です。{ nav: { home: "Home" } } のようにネストした JSON を渡すと、react-intl はキー「nav.home」を見つけられません。渡す前にメッセージをフラット化するか、flat のようなライブラリを使用してください。

IntlProvider による再レンダリング

render 関数内で messages オブジェクトをインライン作成すると、IntlProvider はレンダリングのたびに新しいオブジェクト参照を受け取り、すべてのコンシューマーが再レンダリングされます。useMemo で messages をメモ化するか、コンポーネントの外で定義してください。

テストに IntlProvider がない

FormattedMessage または useIntl を使用するコンポーネントは、上位に IntlProvider がない状態でレンダリングすると例外をスローします。テストでは、locale="en" と空または最小限の messages オブジェクトを指定した IntlProvider でコンポーネントをラップしてください。

推奨ファイル構成

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

i18n Agent を今すぐ試す

翻訳ファイルをここにドロップ

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

またはクリックしてファイルを選択

翻訳先言語

登録不要すぐに見積もり

react-intl-locale-chain によるロケールフォールバック

pt-BR のような地域ロケールに翻訳キーがない場合、react-intl は親ロケール 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>

対応フレームワークの全一覧と 75 の組み込みチェーンについては、ロケールフォールバックガイドをご覧ください。 Learn more →

よくある質問