👏

Next.jsのexport(SSG)してi18n(国際化)実装を行いたい時のススメ

2022/12/29に公開

方針

Next.jsには、標準でi18n設定ができる機能がついています。next.configで設定すれば、ささっとi18n実装ができます

https://nextjs.org/docs/advanced-features/i18n-routing

しかし、上の機能Next.jsをサーバーとして利用している時しか使えないです。
Next.jsでbuild & exportしたものを他のWebサーバーなどに渡すときはNext.js標準の機能が使えないです
e.g. Next.jsでexportしたファイルをNestJSを使って配信したい

そこでフロントエンドのみでi18nを実装する必要があります。
今回はreact-i18next i18nextのライブラリを用いて実装します。
初回レンダリング時にブラウザの言語情報(Navigator)を取得して、localStorageで言語情報を持つ方法で実装します。

別の方法で

があるが、ディレクトリの構造を変えたり、URLにクエリを生やして言語切り替えを行なっています。今回実装する方がシンプルな気がするのですが、知見者の方メリットデメリット教えてください。

実装

成果物

今回作成したリポジトリとサイトのURLを貼っておきます。
作ったサイト(初回レンダリング時にブラウザの情報を読み込んでlocalStorageを見て言語の切り替えを行なっている)
https://github.com/Kisukeyas/i18n-next-export-demo

実装手順

  1. まず、ライブラリをインストールします。
npm install react-i18next i18next --save 

or

yarn add react-i18next i18next

ブラウザの言語情報を取ってきてくれるライブラリも入れます。

npm install i18next-browser-languagedetector
  1. Next.jsのrootにi18n用のフォルダを作成します。(pageディレクトリ以外だと任意のディレクトリでも可)
  2. 下記ファイルを作成します。
i18n.ts
import type { InitOptions } from "i18next";
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";

import enCommon from "../public/locales/en/common.json";
import jaCommon from "../public/locales/ja/common.json";
import enTest from "../public/locales/en/test.json";
import jaTest from "../public/locales/ja/test.json";

const detector = new LanguageDetector(null, {
  order : ['navigator', 'localStorage']
})

const option: InitOptions = {
  resources: {
    en: {
      Common: enCommon,
      Test: enTest,
    },
    ja: {
      Common: jaCommon,
      Test: jaTest,
    },
  },
};

i18next.use(detector).use(initReactI18next).init(option);

export default i18next;

detectorを設定することで、ブラウザの言語設定を読み取ってlocalStorageに言語情報を入れてくれています。

_app.tsx
import type { AppProps } from "next/app";
import "../i18n/i18n";

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}
index.tsx
import { useTranslation } from "react-i18next";
import i18n from "i18next";
import Link from "next/link";

export default function Home() {
  const { t } = useTranslation("Common");
  return (
    <>
      <h1>{t("test1")}</h1>
      <button onClick={() => i18n.changeLanguage("ja")}>日本語</button>
      <button onClick={() => i18n.changeLanguage("en")}>英語</button>
      <Link href={'/test'}>テストページへ</Link>
    </>
  );
}

Next.jsの_app.tsxで初回レンダリング時にi18n.tsをインポートしています。
しi18n.tsをインポートすることによって言語情報を設定し、翻訳済みのjsonファイルを読み込んでいます。
そうすることで、index.tsxでuseTranslationが使えます。

もっと改善の余地ありそうですが、最小限で実装を行いました。i18n.init(option)の設定でもっとカスタマイズできそうです。

所感

jsonファイルが増えてくると初回レンダリング時に重くなりそうです。(知見のある方教えてください)

今回のi18n実装を行うとNext.jsを使うメリットが見出せ内容な気がします。
Next.jsを使うときはVercelにデプロイしてアプリケーションサーバーとして使う方が使える機能もありますしオススメです。
折角標準で用意してあるものは使いたいですね。。。。

FYI
https://nextjs.org/docs/advanced-features/i18n-routing

https://nextjs.org/docs/advanced-features/static-html-export#unsupported-features

Discussion