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>;
}

이 접근 방식은 리디렉션 대신 유효하지 않은 로케일에 대해 찾을 수 없음 페이지를 표시합니다. 이는 URL이 잘못 형성되었음을 알리고 싶을 때 유용하며, 조용히 수정하는 대신 명시적으로 오류를 표시합니다.

4. 유효하지 않은 로케일을 위한 찾을 수 없음 컴포넌트 추가하기

루트 라우트에 notFoundComponent를 정의하여 유효하지 않은 로케일 오류를 우아하게 처리합니다.

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

export const Route = createRootRoute({
  notFoundComponent: () => {
    return (
      <div>
        <h1>페이지를 찾을 수 없습니다</h1>
        <p>요청하신 언어 또는 페이지가 존재하지 않습니다.</p>
        <a href="/">홈페이지로 이동</a>
      </div>
    );
  },
});

이 컴포넌트는 beforeLoad에서 notFound()가 발생했을 때 렌더링되어 사용자에게 명확한 메시지와 유효한 페이지로 돌아갈 수 있는 방법을 제공합니다.