Next.js(ページルーター)v16でナビゲーションリンクのロケールを維持する方法

内部ナビゲーション間でロケールを維持する

問題

Webアプリケーションが言語設定をURLパスに組み込んでいる場合、ユーザーセッション全体を通じてすべての内部リンクがその言語コンテキストを保持する必要があります。明示的なロケール処理がなければ、単純なパスとして記述されたリンクが誤って言語プレフィックスを削除してしまい、ユーザーがナビゲーション中に選択した言語を失うことがあります。これによりローカライズされた体験が中断され、ユーザーは希望する言語を何度も選択し直す必要が生じます。

解決策

すべての内部ナビゲーションリンクが、ルーターコンテキストから読み取った現在のロケールを自動的に含むようにします。Next.js Pages Routerは、ルーティングシステムを通じて組み込みのロケールサポートを提供しており、アクティブなロケールはuseRouterフックを通じて利用できます。デフォルトでは、Linkコンポーネントはクライアントサイドの遷移中に現在のロケールを保持しますが、この動作を理解し、アプリケーション全体で一貫して適用することで、シームレスなロケール対応のナビゲーションが確保されます。

ステップ

1. ルーターから現在のロケールにアクセスする

useRouterフックは、locale(現在アクティブなロケール)、locales(設定されたすべてのロケール)、およびdefaultLocale(設定されたデフォルトロケール)を提供します。

import { useRouter } from "next/router";

export default function Navigation() {
  const router = useRouter();
  const currentLocale = router.locale;

  return (
    <nav>
      <p>Current locale: {currentLocale}</p>
    </nav>
  );
}

このコンポーネントはルーターからアクティブなロケールを読み取り、ナビゲーションロジックで使用できるようにします。

2. 明示的なロケールプロパティなしでLinkコンポーネントを使用する

Linkにロケールプロパティが提供されていない場合、クライアント遷移中に現在アクティブなロケールが使用されます。

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <Link href="/about">About</Link>
      <Link href="/products">Products</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

これらのリンクは自動的に現在のロケールを維持します。ユーザーが/fr/productsを閲覧している場合、「About」をクリックすると/fr/aboutに移動します。

3. 明示的な制御のためのロケール対応リンクヘルパーを作成する

明示的な制御が必要な場合や、ロケール処理をより可視化したい場合は、現在のロケールを明示的に渡すラッパーコンポーネントを作成します。

import Link from "next/link";
import { useRouter } from "next/router";
import { ReactNode } from "react";

interface LocaleLinkProps {
  href: string;
  children: ReactNode;
}

export function LocaleLink({ href, children }: LocaleLinkProps) {
  const { locale } = useRouter();

  return (
    <Link href={href} locale={locale}>
      {children}
    </Link>
  );
}

このコンポーネントはロケールの保持を明示的にし、必要に応じて追加のロケール固有のロジックで拡張することができます。

4. ロケールを保持したプログラムによるナビゲーションを処理する

ルーターメソッドを直接使用する場合、遷移オプションでロケールを指定するか、hrefパラメータをオブジェクトとして渡すことでロケールを含むすべてのルーティング情報を保持できます。

import { useRouter } from "next/router";

export default function NavigationButton() {
  const router = useRouter();
  const { pathname, asPath, query, locale } = router;

  const handleNavigate = () => {
    router.push({ pathname: "/dashboard", query }, asPath, { locale });
  };

  return <button onClick={handleNavigate}>Go to Dashboard</button>;
}

このパターンにより、プログラムによるナビゲーションが現在のロケールと既存のクエリパラメータを維持することを保証します。

5. アプリケーション全体で一貫したリンクパターンを適用する

アプリケーション全体で標準のLinkコンポーネントを使用し、その組み込みのロケール保持機能に依存します。

import Link from "next/link";

export default function ProductCard({ productId }: { productId: string }) {
  return (
    <article>
      <h2>Product {productId}</h2>
      <Link href={`/products/${productId}`}>詳細を見る</Link>
      <Link href="/products">製品一覧に戻る</Link>
    </article>
  );
}

静的ルートと動的ルートの両方に、現在のロケールプレフィックスが自動的に含まれ、ユーザーがアプリケーション内を移動する際に選択した言語を維持します。