🌍

React の多言語化対応を簡単に:react-i18next 導入

2024/09/07に公開

react-i18next は、多言語化のためのライブラリである i18next の React 用ライブラリで、React アプリケーションを簡単に多言語化対応できます。
この記事では、react-i18next の基本的な使い方を紹介します。

インストール

まず、必要なパッケージをインストールしましょう。

npm install react-i18next i18next i18next-http-backend i18next-browser-languagedetector
各パッケージの説明
  • i18next : 多言語化のためのライブラリ
  • react-i18next : i18next の React 向け公式拡張機能
  • i18next-http-backend : 翻訳ファイルを非同期に読み込むためのライブラリ
  • i18next-browser-languagedetector : ブラウザの言語を検出するためのライブラリ

セットアップ

まず、設定ファイルを作成します。

// src/i18n/config.ts

import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
import { initReactI18next } from "react-i18next";

// サポートする言語をオブジェクトで定義しています。
// ユーザーが言語を手動で切り替える場合に使用するためのものです。
export const supportedLngs = {
  en: "English",
  ja: "日本語",
};

i18n
  .use(HttpApi) // 翻訳ファイルを非同期に読み込むため
  .use(LanguageDetector) // ユーザーの言語設定を検知するため
  .use(initReactI18next) // i18next インスタンスを初期化
  .init({
    fallbackLng: "ja", // フォールバック言語。指定された言語ファイルがない場合などにこの言語が使用される
    returnEmptyString: false, // 空文字での定義を許可に
    supportedLngs: Object.keys(supportedLngs),
    debug: true, // true にすると開発コンソールに i18next が正しく初期化されたことを示す出力が表示される

    // デフォルトは`escapeValue: true`
    // 18next が翻訳メッセージ内のコードをエスケープし、XSS 攻撃から保護するためのもの
    // React がこのエスケープを行ってくれるので、今回はこれをオフにする
    interpolation: {
      escapeValue: false,
    },
  });

export default i18n;

その他の設定は公式ドキュメントに記載されています。

翻訳ファイルの作成

設定ファイルで使用したi18next-http-backend は、デフォルトでは Web サイトのルートを基準としたパブリック URL で翻訳ファイルを探し、非同期で翻訳ファイルを読み込んでくれます。
例:http://example.com/locales/ja/translation.json

i18next-http-backend が期待する場所に翻訳ファイルを追加しましょう。

// public/locales/ja/translation.json
{
  "welcome": "ようこそ、私たちのアプリに!",
  "home": {
    "title": "ホーム"
  }
}
// public/locales/en/translation.json
{
  "welcome": "Welcome to our app",
  "home": {
    "title": "Home"
  }
}

ちなみに、翻訳ファイルのパスを変更することもできます。
方法は i18next-http-backendREADMEを参照してください。

設定ファイルをインポート

設定ファイルをアプリのエントリポイント(main.tsx)にインポートします。

  // src/main.tsx

  import React from "react";
  import ReactDOM from "react-dom/client";
  import App from "./App.tsx";
+ import "./i18n/config.ts";
  import "./index.css";

  ReactDOM.createRoot(document.getElementById("root")!).render(
    <React.Suspense fallback={<div>Loading...</div>}>
      <App />
    </React.StrictMode>,
  );

Suspense を使用して、翻訳ファイルのダウンロード中にLoading... が表示されるようにしています。

ブラウザのコンソールに以下の画像のような出力が表示されていれば、i18n のセットアップが成功しています。この出力は、config ファイルでdebug: true に設定しているため、出力されています。
デバッグ

実際に翻訳

翻訳ファイルを使用するには、useTranslation フックを使用します。
翻訳ファイルのキーをt関数に渡します。これでブラウザの言語に応じてテキストが切り替わるはずです。

// src/App.tsx

import { useTranslation } from "react-i18next";

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

  return (
    <div className="...">
      <h2>{t("welcome")}</h2>
    </div>
  );
}

export default App;

言語の自動検出

i18next-browser-languagedetector を使用すると、ブラウザの言語設定を検出できます。
設定ファイルでuse(LanguageDetector)を設定しているので、ユーザーのブラウザの言語設定を検出できています。

言語の手動で切り替え

ユーザーが言語を切り替えるための Select コンポーネントを作成します。
設定ファイルで定義した supportedLngs をインポートして、対応言語の選択肢として使用します。
なお、UI には shadcn/ui を使用しています。
作成するパスはどこでも良いかと思います。


// src/i18n/LocaleSwitcher.tsx

import { useTranslation } from "react-i18next";

import { supportedLngs } from "./config";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

export default function LocaleSwitcher() {
  const { i18n } = useTranslation();

  return (
    <Select
      value={i18n.resolvedLanguage}
      onValueChange={(value) => i18n.changeLanguage(value)}
    >
      <SelectTrigger className="w-40">
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        {Object.entries(supportedLngs).map(([code, name]) => (
          <SelectItem value={code} key={code}>
            {name}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
  • i18n.resolvedLanguage

    • 実際に使用されている言語を表します。ブラウザの言語検出やi18n.changeLanguage()で設定された言語を考慮し、利用可能な翻訳ファイルに基づいて解決された言語コードを返します。例えば、「en」が選択されても、その翻訳ファイルがない場合「ja」にフォールバックすることがあります
  • i18n.changeLanguage()

    • 言語を手動で変更するためのメソッドです。言語コード(例:'en'、'ja')を引数として受け取り、指定された言語に切り替えます。アプリケーション全体の翻訳が更新され、指定言語の翻訳ファイルがない場合はフォールバック言語が使用されます

作成したコンポーネントを追加すると、以下のように言語切り替えができるようになります。
言語切り替え

翻訳で動的な値を扱う

実行時に動的に翻訳メッセージに挿入したい場合も多いと思います。その場合は以下のようにします。

// public/locales/ja/translation.json
{
  "welcome": "ようこそ、私たちのアプリに!",
  "home": {
    "title": "ホーム"
  },
+ "greeting": "こんにちは、{{name}}さん!"
}
// public/locales/en/translation.json
{
  "welcome": "Welcome to our app",
  "home": {
    "title": "Home"
  },
+ "greeting": "Hello, {{name}}!"
}
// src/App.tsx

import { useTranslation } from "react-i18next";

// ユーザーを取得する仮の関数
import { getLoggedInUser } from "...";

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

  const user = getLoggedInUser();

  return (
    <div className="...">
      <h2>{t("welcome")}</h2>
      <p>{t("greeting", { name: user.name })}</p>
    </div>
  );
}

export default App;

終わりに

導入自体は簡単にできました。翻訳ファイルの作成が少し面倒です。
本記事では、手っ取り早く多言語化したかったので最低限で進めています。翻訳ファイルの管理や作成、運用などはやり方がいろいろあるようなので、そちらも調べてみるといいと思います。

参考

https://phrase.com/blog/posts/localizing-react-apps-with-i18next/

https://github.com/i18next/i18next-http-backend

Discussion