next-intl で作る、本当に多言語な Next.js サイト
ローカライズされたルーティング、静的レンダリング、hreflang、そして言語切り替え——パフォーマンスも SEO も犠牲にせず、Next.js サイトを 10 言語で構成する方法。
なぜ多言語対応は本物のアーキテクチャの問題なのか
インターフェースを翻訳するのは簡単です。まっとうな多言語サイト——インデックスされ、速く、保守できる——を作ることは、最後ではなく最初に下すアーキテクチャの決定です。このポートフォリオは 10 言語で存在します。規模に耐える選択を紹介します。
ロケールセグメントによるルーティング
App Router で最も堅牢なアプローチ:ルートに動的な [locale] セグメントを置くこと。すべてのページは app/[locale]/… の下に置かれ、言語は一級の URL データになります(/fr/projects、/en/projects)。
next-intl では、このセグメントはレンダリング時に検証されます。
- サポートするロケールは、中央の
routing設定に列挙します。 - 未知のロケールは、壊れたページではなく、きれいな
notFound()を発生させます。 - ナビゲーションは、正しい言語を自動で前置するローカライズ済みの
Linkを通します。
利点:コンポーネントがロケールを「手作業で」扱うことは決してありません。翻訳を求めれば、残りはシステムが引き受けます。
静的レンダリングの落とし穴
本番で最も高くつく間違いです。先にロケールを固定せずに翻訳を呼び出すと、next-intl はリクエストのヘッダーを読みます。結果、ページは動的レンダリングに切り替わり、静的なプリレンダリングを失います——ときには本番で DYNAMIC_SERVER_USAGE エラーとともに。
対策は、各ページの一番上の一行に収まります。
setRequestLocale(locale);
あらゆる getTranslations の前に呼び出すことで、完全な静的レンダリングを保証します。locale × slug を掛け合わせる generateStaticParams と組み合わせれば、ビルド時に各ページを各言語でプリレンダリングします。
静的な多言語は、単一言語より遅くはありません。ただ、呼び出しの順序にうるさいだけです。
hreflang、あるいは自分自身と競合しない方法
何の指示もなければ、Google はあなたの 10 の言語版を、同じキーワードを争う 10 の競合ページとして扱います。解決策は hreflang:各ページが自らのバリアント全体を宣言します。
同期を保つべき場所は二つ。
- 各ページのメタデータ —
alternateタグを生成するgenerateAlternatesヘルパー経由で。 - サイトマップ — 各 URL が、そこに自らの言語と
x-defaultを列挙します。
この二つのソースの一貫性こそが、スペイン語の検索を /fr ではなく /es に着地させるのです。
言語切り替え、ユーザー側から
言語セレクターは、現在のページを失わずにロケールを変えなければなりません。素朴な反射——トップに戻す——はストレスです。next-intl のローカライズされた usePathname を使えば、接頭辞のないパスを取得し、選ばれた言語で再発行できます。ユーザーは、いた場所にそのまま留まります。
私が心に留めること
- ルートの
[locale]セグメントが土台です。すべてはそこから流れ出ます。 - 翻訳の前に
setRequestLocale:静的を保つための、交渉の余地なきルール。 hreflangは二重に管理します(メタデータとサイトマップ)、常に同期させて。- テキストの方向(アラビア語の RTL)は、ページごとではなく
<html dir>のレベルで制御します。
うまくやれば、多言語対応は見えなくなります。どの訪問者も、このサイトは自分のために書かれたと感じ、Google はどの扉を開けばよいかを正確に知っているのです。