3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】react-i18next を使った多言語対応

Posted at

はじめに

この記事では、React / TypeScript 環境で react-i18next を使った多言語対応の実装方法を記載します。

react-i18next とは

react-i18next は、React アプリケーションに国際化(i18n)機能を提供するライブラリです。

i18next エコシステムをベースにしており、以下のような特徴があります。

  • React Hooks に完全対応(useTranslation フックなど)
  • TypeScript による型安全な翻訳キーの補完
  • Trans コンポーネントによる複雑な翻訳の対応
  • プラグインによる拡張性の高さ
  • SSR(サーバーサイドレンダリング)への対応

i18next 本体は React に限定されず、Angular や Vue.js、さらには Node.js でも利用可能な汎用的な国際化フレームワークです。

react-i18next はその React バインディングとして、React の Context API や Hooks を活用した実装を提供しています。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • React 19.2.0
  • TypeScript 5.9.3
  • Vite 7.2.4
  • Node.js 24.11.1
  • npm 11.6.4
  • react-i18next 16.3.5
  • i18next 25.7.1
  • i18next-browser-languagedetector 8.2.0

インストール

まずは以下のコマンドでインストールします。

npm install react-i18next i18next --save

基本的な利用方法

i18n の初期化

src ディレクトリ配下に i18n.ts ファイルを作成し、i18next の設定を行います。

i18n.ts
import i18n from "i18next";
import { initReactI18next } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    ja: {
      translation: {
        welcome: "ようこそ",
        greeting: "こんにちは、{{name}}さん",
      },
    },
    en: {
      translation: {
        welcome: "Welcome",
        greeting: "Hello, {{name}}",
      },
    },
  },
  fallbackLng: "en",
  interpolation: {
    escapeValue: false,
  },
});

export default i18n;

アプリケーションへの適用

main.tsx で i18n をインポートします。

main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./i18n";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

useTranslation フックの利用

コンポーネント内で useTranslation フックを使って翻訳を行います。

App.tsx
import { FC } from "react";
import { useTranslation } from "react-i18next";

export const Welcome: FC = () => {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t("welcome")}</h1>
      <p>{t("greeting", { name: "太郎" })}</p>
    </div>
  );
};

動作確認をします。

初期言語設定(lng)を日本語にしているので、「ようこそ」と「こんにちは、太郎さん」が表示されます。

image.png

言語切り替え

i18n.changeLanguage を利用することで、画面上からの言語切替が可能になります。

App.tsx
import { useTranslation } from "react-i18next";

function App() {
  const { t, i18n } = useTranslation();

  const changeLanguage = (lng: string) => {
    i18n.changeLanguage(lng);
  };

  return (
    <div>
      <h1>{t("welcome")}</h1>
      <p>{t("greeting", { name: "太郎" })}</p>
      <div>
        <button onClick={() => changeLanguage("ja")}>日本語</button>
        <button onClick={() => changeLanguage("en")}>English</button>
      </div>
    </div>
  );
}

export default App;

react-i18next-languagedetector-Google-Chrome-2025-12-02-14-59-01.gif

言語設定の自動検知

言語設定を自動検知したい場合、i18next-browser-languageDetector パッケージを利用します。

npm install --save i18next-browser-languagedetector

i18next-browser-languagedetector を使うように i18n.ts を更新します。

i18n.ts
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";

i18n
  .use(LanguageDetector) // 追加
  .use(initReactI18next)
  .init({
    resources: {
      ja: {
        translation: {
          welcome: "ようこそ",
          greeting: "こんにちは、{{name}}さん",
        },
      },
      en: {
        translation: {
          welcome: "Welcome",
          greeting: "Hello, {{name}}",
        },
      },
    },
    fallbackLng: "en",
    interpolation: {
      escapeValue: false,
    },
  });

export default i18n;

この設定により、以下の順序で言語が検知されます。

  1. クエリ文字列 (?lng=ja など)
  2. Cookie
  3. localStorage
  4. sessionStorage
  5. ブラウザの navigator
  6. HTML タグ

image.png

localStorage キャッシュの有無による動作の違い

デフォルトの挙動では、上記の画面キャプチャの通り初回アクセス時の言語が localStorage に自動で保存されます。

  • メリット
    • 「このサイトでは日本語で見る」といった、サイトごとの言語設定が可能
    • 言語選択機能をつけた場合、ユーザーの言語選択が記憶される(再アクセス時に前回選択した言語を利用できる)
  • デメリット
    • 初回アクセス後、ブラウザの言語設定を変更しても、変更が反映されない
      • 初回アクセス時に localStorage へ保存された値が優先される
      • 反映させるためには、localStorage を手動で削除する必要がある

image.png

検知オプションのカスタマイズ

言語検知の動作をカスタマイズする場合は、detection オプションを指定します。

i18n.ts
i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: {
      // ...
    },
    fallbackLng: "en",
    detection: {
      order: ["navigator", "localStorage"],
      caches: ["localStorage"],
    },
    interpolation: {
      escapeValue: false,
    },
  });
  • order: 言語検知の優先順位を指定
  • caches: 検知した言語を保存する場所を指定

今回の設定では、クエリ文字列の値は反映されていません。

image.png

サポート言語の設定

アプリケーションでサポートする言語を明示的に指定することで、より適切な言語マッチングが可能になります。

翻訳ファイルの分離

翻訳データは、JSON ファイルに分離できます。

ディレクトリ構造

src/
├── locales/
│   ├── ja/
│   │   └── translation.json
│   └── en/
│       └── translation.json
├── i18n.ts
└── main.tsx

翻訳ファイルの作成

src/locales/ja/translation.json

translation.json
{
  "welcome": "ようこそ",
  "greeting": "こんにちは、{{name}}さん",
  "messages": {
    "unread": "未読メッセージが{{count}}件あります"
  }
}

src/locales/en/translation.json

translation.json
{
  "welcome": "Welcome",
  "greeting": "Hello, {{name}}",
  "messages": {
    "unread": "You have {{count}} unread message(s)"
  }
}

i18n 設定の更新

翻訳ファイルを resources で読み込みます。

import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import jaTranslation from "./locales/ja/translation.json";
import enTranslation from "./locales/en/translation.json";

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: {
      ja: { translation: jaTranslation },
      en: { translation: enTranslation },
    },
    fallbackLng: "en",
    interpolation: {
      escapeValue: false,
    },
  });

export default i18n;

Trans コンポーネントの利用

HTML タグや React コンポーネントを含む翻訳には Trans コンポーネントを使用します。

翻訳ファイル

{
  "richText": "これは<bold>太字</bold>のテキストです",
}

コンポーネント

App.tsx
import { Trans, useTranslation } from "react-i18next";

function App() {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t("welcome")}</h1>
      <p>{t("greeting", { name: "太郎" })}</p>
      <Trans i18nKey="richText" components={{ bold: <strong /> }} />
    </div>
  );
}

export default App;

image.png

TypeScript の型定義

TypeScript で翻訳キーの型安全性を確保するために、型定義を追加します。

i18next.d.ts

src ディレクトリ配下に i18next.d.ts ファイルを作成します。

import "i18next";
import jaTranslation from "./locales/ja/translation.json";

declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "translation";
    resources: {
      translation: typeof jaTranslation;
    };
  }
}

これにより、t() 関数の引数に存在しないキーを指定した場合、TypeScript のコンパイルエラーが発生するようになります。

image.png

名前空間の利用

大規模なアプリケーションでは、翻訳を複数のファイルに分割して管理できます。

ディレクトリ構造

src/
├── locales/
│   ├── ja/
│   │   ├── common.json
│   │   └── home.json
│   └── en/
│       ├── common.json
│       └── home.json

i18n 設定

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import jaCommon from "./locales/ja/common.json";
import jaHome from "./locales/ja/home.json";
import enCommon from "./locales/en/common.json";
import enHome from "./locales/en/home.json";

i18n
  .use(initReactI18next)
  .init({
    resources: {
      ja: {
        common: jaCommon,
        home: jaHome,
      },
      en: {
        common: enCommon,
        home: enHome,
      },
    },
    lng: "ja",
    fallbackLng: "en",
    defaultNS: "common",
    interpolation: {
      escapeValue: false,
    },
  });

export default i18n;

名前空間の指定

import { FC } from "react";
import { useTranslation } from "react-i18next";

export const Home: FC = () => {
  const { t } = useTranslation("home");

  return <h1>{t("title")}</h1>;
};

まとめ

react-i18next を使うことで、React / TypeScript アプリケーションに簡単に多言語対応を導入できます。

主なポイントは以下の通りです。

  • useTranslation フックを使ったシンプルな翻訳の実装
  • Trans コンポーネントによる HTML タグやコンポーネントを含む翻訳
  • TypeScript による型安全な翻訳キーの管理
  • 名前空間を使った大規模アプリケーションへの対応

i18next エコシステムには、さらに多くのプラグインや機能が用意されています。言語検出、翻訳の遅延読み込み、複数形の処理など、プロジェクトの要件に応じて柔軟にカスタマイズできます。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?