メインコンテンツへスキップ

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 はどの扉を開けばよいかを正確に知っているのです。

AGENTS.md とコードエージェント:開発者の新しい道具立て