TanStack Start v1でURLのロケールパラメータを検証する方法

サポートされていないロケールコードを適切に処理する

問題

言語コードがURL構造の一部になると、検証が必要なユーザー入力に変わります。ユーザーは、/en/about/fr/contactのような有効なコードと同じように、/xx/about/gibberish/contact/typo123/productsなど、任意の文字列をロケールセグメントに手動で入力できます。検証がない場合、アプリケーションは存在しないロケールの翻訳を読み込もうとしたり、壊れたコンテンツを表示したり、クラッシュしたりする可能性があります。無効なロケールはそれぞれ、ユーザーが回復したり、動作するページに移動したりできない潜在的な行き止まりを表します。

検証されていないロケールパラメータは、予測不可能な動作を引き起こします。アプリケーションは、翻訳の読み込みに静かに失敗したり、フォールバックと欠落したコンテンツが混在した状態でレンダリングしたり、翻訳キーにアクセスしたときにランタイムエラーをスローしたりする可能性があります。壊れたリンクをたどったり、URLを誤入力したりしたユーザーは、何が問題だったのか、どのように修正すればよいのかについて明確なフィードバックを得られません。

解決策

ルートのbeforeLoad関数で、URLからのロケールパラメータをサポートされているロケールのリストに対して検証します。ロケールが無効または欠落している場合は、デフォルトのロケールを使用した有効なURLにユーザーをリダイレクトするか、not-foundエラーをスローして役立つエラーページを表示します。これにより、サポートされているロケールのみが処理され、ユーザーが常に有効で翻訳可能なページにアクセスできるようになります。

beforeLoad関数はルートが読み込まれる前に実行されるため、ロケールをチェックするのに最適な場所です。redirect()またはnotFound()エラーをスローすることで、無効なロケールでルートがレンダリングされるのを防ぎ、ユーザーを動作する状態に誘導します。

手順

1. サポートするロケールを定義する

有効なロケールコードの定数配列と、型安全な検証関数を作成します。

const SUPPORTED_LOCALES = ["en", "fr", "es", "de"] as const;

type Locale = (typeof SUPPORTED_LOCALES)[number];

function isValidLocale(locale: string | undefined): locale is Locale {
  return SUPPORTED_LOCALES.includes(locale as Locale);
}

これにより、サポートされるロケールの単一の信頼できる情報源と、TypeScriptが理解できる再利用可能な検証関数が提供されます。

2. ロケール検証を含むレイアウトルートを作成する

オプションのロケールパラメータを使用し、beforeLoadで検証します。

import { createFileRoute, redirect } from "@tanstack/react-router";

const DEFAULT_LOCALE: Locale = "en";

export const Route = createFileRoute("/{-$locale}")({
  beforeLoad: ({ params }) => {
    const { locale } = params;

    if (locale && !isValidLocale(locale)) {
      throw redirect({
        to: "/{-$locale}",
        params: { locale: undefined },
        replace: true,
      });
    }

    return {
      locale: (locale as Locale) || DEFAULT_LOCALE,
    };
  },
});

beforeLoad関数はロケールパラメータをチェックします。存在するが無効な場合、ユーザーはロケールプレフィックスなしの同じパスにリダイレクトされ、デフォルトのロケールに解決されます。検証されたロケールは、子ルートが使用できるようにコンテキストで返されます。

3. ネストされたルートでロケールを検証する

ロケールが必要なルートの場合、検証を行い、無効な場合はnotFound()をスローします。

import { createFileRoute, notFound } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/products")({
  beforeLoad: ({ params }) => {
    const { locale } = params;

    if (locale && !isValidLocale(locale)) {
      throw notFound();
    }

    return {
      locale: (locale as Locale) || DEFAULT_LOCALE,
    };
  },
  component: ProductsPage,
});

function ProductsPage() {
  const { locale } = Route.useRouteContext();
  return <div>Products in {locale}</div>;
}

このアプローチは、リダイレクトする代わりに無効なロケールに対して404ページを表示します。これは、URLが不正であることを示したい場合に便利で、静かに修正するのではなく明示的に通知します。

4. 無効なロケール用の404コンポーネントを追加する

ルートルートにnotFoundComponentを定義して、無効なロケールエラーを適切に処理します。

import { createRootRoute } from "@tanstack/react-router";

export const Route = createRootRoute({
  notFoundComponent: () => {
    return (
      <div>
        <h1>Page Not Found</h1>
        <p>The language or page you requested does not exist.</p>
        <a href="/">Go to home page</a>
      </div>
    );
  },
});

このコンポーネントは、beforeLoadからnotFound()がスローされたときにレンダリングされ、ユーザーに明確なメッセージと有効なページに戻る方法を提供します。