Next.js の i18n、そのやり方は間違っています
JavaScript における国際化は、問題のある慣習に落ち着いてしまいました。すべてのユーザー向け文字列を JSON ファイルに抽出し、キーを割り当て、そのキーをコンポーネント内で参照するやり方です。テキストそのものの代わりに t('home.hero.title') と書く、という具合です。UI はある場所に、コンテンツは別の場所に存在します。
これは一応機能します。何千ものアプリがこの方法でリリースされています。しかし、開発者体験としては優れているとは言えません。
コードレビューで t('checkout.summary.total') を読んでも何もわかりません — 何が変わったのか確認するには JSON ファイルを開く必要があります。キーは考案して名前空間を切り、同期を保たなければなりません。どのキーがまだ使われているのかわからないせいで、古くなった翻訳がどんどん蓄積されていきます。この問題があまりにも広く蔓延しているので、それだけを管理するためのツールのカテゴリが丸ごと存在するほどです。キーを自動サジェストする IDE 拡張、キーを検証する型ジェネレーター、未使用キーを検出するリンターなどです。これらのツールは、設計の悪いパラダイムが生み出した問題を解決しようとしています。
<T> コンポーネント
コンテンツは、それが使われている場所から切り離されるべきではありません。見出し・段落・ボタンをレンダリングするコンポーネントは、それぞれの要素が何を表示するかについての単一のソース・オブ・トゥルースであるべきであり、どこか別の場所に保存された文字列を指すプロキシであってはいけません。コードと翻訳が 2 つの並行したシステムになっていると、必ずズレが生じます。
もしライブラリがその逆に動いてくれたらどうでしょうか — コードの書き換えを要求するのではなく、あなたのコードに適応してくれたら? i18n は本来、こうあるべきです。
import { T } from 'gt-next';
function Hero() {
return (
<T>
<h1>Ship your product worldwide</h1>
<p>Reach every market without rewriting your app.</p>
</T>
);
}JSX を <T> でラップします。英語のテキストは、そのまま書いておきます。ユーザーがスペイン語や日本語でアクセスしたとき、<T> 内のコンテンツが、構造もフォーマットも含めてまるごと翻訳されます。
キーは不要。JSON ファイルも不要。相互参照も不要。唯一のソース・オブ・トゥルースは、コードです。
セットアップ
上記の構文は、Next.js App Router 向けのオープンソース i18n ライブラリである gt-next のものです。導入は、次のコマンドを 1 回実行するだけです。
npx gtx-cli@latest initセットアップウィザード は依存関係をインストールし、Next.js の設定を withGTConfig でラップし、ルートレイアウトに GTProvider を追加し、ロケールを含む gt.config.json を作成し、翻訳のホットリロード用に開発用 API キーを設定し、CDN(コンテンツ配信ネットワーク)上の翻訳ストレージを構成します — これらすべてを対話的に行います。
これが完了したら、コンテンツを <T> でラップし、開発サーバーを起動して、<LocaleSelector> コンポーネントを使って言語を切り替えます。
import { LocaleSelector } from 'gt-next';
function Header() {
return (
<header>
<nav>{/* ... */}</nav>
<LocaleSelector />
</header>
);
}開発時には翻訳がオンデマンドで実行されるため、アプリをあらゆる言語ですぐに確認できます。
デプロイ
本番環境では、翻訳は事前に生成されます。
-
dash.generaltranslation.com から 本番用の API キーを取得 します。本番キーは
gtx-api-から始まります(ローカルで使用するgtx-dev-キーとは異なります)。 -
ビルドプロセスに
translateステップを追加します。
{
"scripts": {
"build": "npx gtx-cli translate --publish && next build"
}
}translate コマンドは、コードベース内でのすべての <T> の使用箇所をスキャンし、翻訳を生成して CDN(コンテンツ配信ネットワーク)に公開します。アプリをビルドすると、すべてのロケールの翻訳がすぐに利用できる状態になります。
次のステップ
- 変数コンポーネント —
<T>内の動的コンテンツを<Var>、<Num>、<Currency>で処理する - 分岐コンポーネント —
<Plural>と<Branch>を使って、ロケールに応じてコンテンツを条件付きでレンダリングする useGTとgetGT— 属性、プレースホルダー、メタデータの通常の文字列を翻訳する- スタンドアロンモード — General Translation プラットフォームを使わずに gt-next を利用する