Как валидировать параметры локали в URL в TanStack Start v1

Корректная обработка неподдерживаемых кодов локалей

Проблема

Когда языковые коды становятся частью структуры URL, они превращаются во ввод пользователя, который нужно валидировать. Пользователь может вручную ввести любую строку в сегмент локали — /xx/about, /gibberish/contact или /typo123/products — так же легко, как и валидные коды вроде /en/about или /fr/contact. Без валидации приложение может попытаться загрузить переводы для несуществующих локалей, показать некорректный контент или даже упасть. Каждая невалидная локаль — это потенциальный тупик, из которого пользователь не сможет восстановиться или перейти на рабочую страницу.

Невалидированные параметры локали приводят к непредсказуемому поведению. Приложение может тихо не загрузить переводы, отобразить смесь запасного и отсутствующего контента или выбросить ошибку во время выполнения при обращении к ключам перевода. Пользователи, которые переходят по битым ссылкам или ошибаются в URL, остаются без понятной обратной связи о том, что пошло не так и как это исправить.

Решение

Валидируйте параметр локали из URL, сверяя его со списком поддерживаемых локалей в функции beforeLoad маршрута. Если локаль невалидна или отсутствует, перенаправьте пользователя на корректный 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. Создайте маршрут layout с валидацией локали

Используйте необязательный параметр локали и валидируйте его в 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>;
}

Этот подход показывает страницу «не найдено» для невалидных локалей вместо редиректа — это удобно, если вы хотите явно показать, что URL некорректен, а не исправлять его молча.

4. Добавьте компонент not-found для невалидных локалей

Определите 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>
    );
  },
});

Этот компонент отображается, когда notFound() выбрасывается из beforeLoad, чтобы пользователь видел понятное сообщение и мог вернуться на рабочую страницу.