hafuture
Back to Blog

多言語プロジェクトの落とし穴:Next.js i18n レイアウトバグ修正記

多言語サイト構築中に直面したヘッダーとフッターの言語固定問題と、NextIntlClientProviderを通じた解決プロセスを共有します。

Next.jsi18nnext-intlTechnical

こんにちは!本日は、hafuture サービスの開発過程で経験した、興味深くも少し困惑した技術的なトラブルシューティング事例をご紹介します。テーマは 「多言語環境におけるレイアウトコンポーネントの同期」 です。

問題の発見:「本文は韓国語なのに、メニューはなぜ英語のまま?」

hafuture は、世界中のユーザーをターゲットにテキスト処理、PDF 編集、各種計算機などの便利なツールを提供するプラットフォームです。そのため、韓国語、英語、日本語を完璧にサポートすることが何よりも重要でした。

私たちは next-intl ライブラリを使用して多言語対応を実装しましたが、ある日ブログページをテストしていたところ、奇妙な点に気づきました。/ko/blog のパスでアクセスした際、ブログ記事の本文とタイトルは正しく韓国語で表示されるものの、上部の ヘッダー(Header)メニュー と下部の フッター(Footer) が依然として英語のままでした。

それだけでなく、言語切り替えスイッチで言語を変えても、URL が変わるだけで共通のレイアウト要素は変わりませんでした。まるでレイアウトだけが別のタイムゾーンで生きているかのような感覚でした。

原因分析:クライアントサイド・プロバイダーの不足

原因は大きく分けて 2 つありました。

  1. NextIntlClientProvider のロケール欠落: layout.tsx ですべてのメッセージを読み込んで提供していましたが、NextIntlClientProvider に対して現在どの言語(locale)を使用すべきか明示的に伝えていませんでした。その結果、ブラウザで動作するクライアントコンポーネント(Header、Footer など)はデフォルトの英語で固定されてしまっていました。
  2. メッセージ読み込みの不確実性: サーバーコンポーネントで getMessages() を呼び出す際に引数を省略すると、リクエストのコンテキストを正確に把握できず、デフォルト言語のメッセージを返してしまうリスクがありました。

解決プロセス:明示的なロケール注入

この問題を解決するため、以下の手順でコードを修正しました。

1. Root Layout の修正

まず、RootLayout で URL から取得した locale 情報を NextIntlClientProvider に直接渡すように変更しました。これにより、配下のすべてのクライアントコンポーネントが同一の言語コンテキストを共有できるようになります。

// src/app/[locale]/layout.tsx
<NextIntlClientProvider locale={locale} messages={messages}>
  <Header />
  {children}
  <Footer />
</NextIntlClientProvider>

2. ブログページのメタデータと言語ロジックの強化

ブログ一覧ページでも getTranslations({ locale, namespace: "Blog" }) のようにロケールを明示的に指定し、サーバーサイドレンダリング(SSR)の時点で正確な言語データが含まれるように保証しました。

3. 言語切り替えロジックの単純化

既存の複雑なパス解析ロジックを削除し、next-intl の内蔵機能を活用するようにしました。この過程で発生していた不要なエラーも併せて解決されました。

結果と教訓

修正後、ブログページで言語を切り替えると、ヘッダーの「Text Tools」が「텍스트 도구(テキストツール)」に、「Blog」が「블로그(ブログ)」に即座に翻訳されることを確認できました。

今回の作業を通じて学んだ主要な教訓は以下の通りです:

  • コンポーネントのタイプ(Server/Client)に応じた i18n 戦略: サーバーコンポーネントはリクエストコンテキストを、クライアントコンポーネントはプロバイダーを通じたコンテキスト共有が不可欠です。
  • 「明示的」は「暗黙的」よりも優れている: 自動で処理されることを期待するよりも、ロケール情報を明示的に渡す方が、デバッグやメンテナンスの面で圧倒的に有利です。

グローバルサービスを目指す開発者の皆様にとって、この記事が少しでもお役に立てれば幸いです。多言語対応は単にテキストを変えるだけでなく、ユーザーの環境を尊重するための第一歩ですから。

ありがとうございました。