はじめに
みなさまはNext.jsで静的に生成するHTMLファイルを国際化したくありませんか? Next.jsに組み込みのi18n routingはStatic HTML Exportに対応していないので、別の手を考える必要があります。
結論から言うと、以下の記事にやり方が書いてあります。
この記事では、Next.jsでStatic HTML Exportで言語ごとのHTMLファイルを生成する方法と、ハマったところを簡単にまとめます。
手順
翻訳データを用意する
public/locales/(言語)/common.json
に翻訳データを用意します。ラベル→文言というJSONを置けばよいです。
{ "hello": "こんにちは" }
next-i18nextをインストールする
Next.jsでi18next (react-i18next) を使えるようにするライブラリです。i18next, react-i18nextのインストールは不要でnext-i18nextだけ入れれば動きます。useTranslation
関数もnext-i18nextからimportします。
$ yarn add next-i18next
next-i18nextの設定を書く
リポジトリルートに next-i18next.config.js
というファイルを書きます。設定ファイルの書き方はREADMEを参照してください。ここでは、デフォルトで日本語を使う・対応言語は日本語とアメリカ英語、という設定をしています。
module.exports = { i18n: { defaultLocale: 'ja-JP', locales: [ 'ja-JP', 'en-US', ], }, }
言語ごとのページを生成できるようなファイル構成にする
pages
ディレクトリを以下のように、[lang]
ディレクトリにページを突っ込むような構成にします。簡単のため index.tsx
だけ用意します。
pages ├── [lang] │ └── index.tsx └── _app.tsx
getStaticProps
で言語ごとの情報を読み込む
react-i18nextの serverSideTranslations
関数で翻訳データを読み込んで、それを getStaticProps
で呼び出して、propsとして渡します。
import nextI18nextConfig from '../../next-i18next.config'; import {serverSideTranslations} from 'next-i18next/serverSideTranslations'; const getI18nProps = async (ctx) => { let locale = ctx.params?.lang ?? nextI18nextConfig.i18n.defaultLocale; if (locale instanceof Array) { locale = locale[0]; } const props = await serverSideTranslations(locale); return props; }; export const getStaticProps = async (ctx) => ({ props: await getI18nProps(ctx), });
getStaticPaths
で生成対象の言語を指定する
next-i18next.config.js
に対応言語の一覧があるので、それを使ってHTMLを生成する対象の言語を指定します。
const getI18nPaths = () => nextI18nextConfig.i18n.locales.map(lang => ({ params: { lang, }, })); export const getStaticPaths = () => ({ fallback: false, paths: getI18nPaths(), });
翻訳する
ここまでできたら useTranslation
フックを使って翻訳していけばよいです。
const { t } = useTranslation(); t('hello');
next build
して next export
したら、言語ごとにHTMLファイルが生成されていることが確認できます。
注意点
生成されたHTMLに翻訳データが埋め込まれる
生成されたHTMLに翻訳データが埋め込まれることに注意しましょう。文言が多いとそれだけファイルサイズも大きくなるし、公開したくない文言がある場合は含めてはいけません。翻訳データの名前空間を絞っておくのが安全です。
クライアントサイドのJavaScriptで翻訳文言を表示する必要がない場合は更に最適化する余地があるかもしれません。
next dev
で起動する際にも正しく翻訳させる
defaultNS
(デフォルトで使う翻訳データの名前空間) をいじっている場合などでは、 serverSideTranslations
関数の第3引数に next-i18next.config.js
の内容を渡す必要があります。
const props = await serverSideTranslations(locale, undefined, nextI18nextConfig);
こうした上で next dev
で開発用サーバーを起動して、 /ja-JP
などのパスにアクセスすると動作確認できます。
next export
で生成した静的ファイルに対して動作確認するには
out
ディレクトリ以下で適当なHTTPサーバーを立ち上げればよいです。Pythonなどで適当なワンライナーを書いてもよいし、http-serverなどのライブラリを使うとNode.js上で完結できてよさそうです。
おわりに
Next.jsで国際化しつつStatic HTML Exportできましたね。ファイルパスに []
といった記号を使うのは初見だとギョッとするけど思ったよりも簡単に実現できたのでよかったです。こうして生成したファイルを何らかの方法で言語ごとに出し分ければよさそうですね。