React Router v7でロケールベースのルーティングを実装する方法

ロケールセグメントを使用したルーティングの設定

問題

多言語アプリケーションを構築する際、すべてを形作る基本的な決定事項があります。それは、アプリケーションがどの言語を表示するかをどのように判断するかということです。明示的なメカニズムがなければ、URL /about は曖昧になります。つまり、どの言語のコンテンツも表す可能性があるということです。ユーザーは特定の言語バージョンへのリンクを共有できず、検索エンジンはどのバージョンがどのオーディエンスに属するかを理解するのに苦労します。この曖昧さは、ユーザーエクスペリエンスと発見可能性の両方に問題を引き起こします。

解決策

言語識別子をURLパスに直接配置します。例えば、/en/about/fr/about のようにします。これにより、すべてのパスが特定の言語に固有のものとなり、ユーザーと検索エンジンの両方にとって曖昧さが解消されます。最初のセグメントとしてロケールパラメータを持つルートを定義することで、アプリケーションはURLからロケールを抽出し、それを使用してどの言語のコンテンツを表示するかを決定できます。このアプローチにより、すべてのURLがページとその言語の両方を明確に識別することが保証されます。

手順

1. ロケールパラメータを使用してルートを定義する

app/routes.ts でルートを設定し、各パスの最初のセグメントとしてロケールパラメータを含めます。

import { type RouteConfig, route, index } from "@react-router/dev/routes";

export default [
  route(":locale", "./localized-layout.tsx", [
    index("./home.tsx"),
    route("about", "./about.tsx"),
    route("contact", "./contact.tsx"),
  ]),
] satisfies RouteConfig;

コロンのプレフィックスにより、locale はURLから解析され、ルートコンポーネントにパラメータとして提供される動的セグメントになります。この設定により、/en/en/about/fr/contact のようなルートが作成され、最初のセグメントは常にロケールになります。

2. ロケールを抽出するレイアウトコンポーネントを作成する

子ルートは、親ルート内のOutletコンポーネントを通じてレンダリングされます。ロケールパラメータを抽出し、ネストされたルートをレンダリングするレイアウトを作成します。

import { Outlet, useParams } from "react-router";

export default function LocalizedLayout() {
  const { locale } = useParams();

  return (
    <div>
      <nav>
        <a href={`/${locale}`}>Home</a>
        <a href={`/${locale}/about`}>About</a>
        <a href={`/${locale}/contact`}>Contact</a>
      </nav>
      <Outlet />
    </div>
  );
}

useParamsフックは、URLから動的セグメント値を取得します。レイアウトはこのロケールを使用してナビゲーションリンクを構築し、Outletを介して子ルートにレンダリング制御を渡します。

3. ページコンポーネントでロケールにアクセスする

任意のルートコンポーネントでuseParamsフックを使用して、ロケールパラメータにアクセスします。

import { useParams } from "react-router";

export default function About() {
  const { locale } = useParams();

  return (
    <div>
      <h1>About Us</h1>
      <p>Current locale: {locale}</p>
    </div>
  );
}

ローカライズされたレイアウト内でレンダリングされるすべてのコンポーネントは、URLからロケールを抽出できます。この値は、適切な翻訳の読み込み、日付と数値のフォーマット、またはその他のロケール固有の決定を行うために使用できます。

4. クライアントサイドナビゲーションにLinkコンポーネントを使用する

アンカータグをLinkコンポーネントに置き換えて、クライアントサイドルーティングによるナビゲーションを有効にします。

import { Outlet, useParams, Link } from "react-router";

export default function LocalizedLayout() {
  const { locale } = useParams();

  return (
    <div>
      <nav>
        <Link to={`/${locale}`}>Home</Link>
        <Link to={`/${locale}/about`}>About</Link>
        <Link to={`/${locale}/contact`}>Contact</Link>
      </nav>
      <Outlet />
    </div>
  );
}

Linkコンポーネントはクライアントサイドでルーティングを処理し、Webページのリロードを防ぐため、ページ間のスムーズなナビゲーションが可能になります。各リンクにはロケールパラメータが含まれており、ナビゲーション全体で言語コンテキストが維持されます。