React Router v7에서 탐색 링크의 로케일을 유지하는 방법

내부 탐색에서 로케일 유지

문제

로케일 정보가 URL 경로에 인코딩되어 있는 경우, 모든 탐색 링크는 일관된 사용자 경험을 유지하기 위해 해당 로케일을 보존해야 합니다. 사용자가 사이트의 프랑스어 버전을 탐색하고 /about 링크를 클릭하면, 프랑스어를 유지하면서 /fr/about로 이동할 것으로 예상합니다. 로케일 인식 링크가 없으면 사용자는 세션 중간에 기본 언어로 전환되어 탐색 컨텍스트가 깨지고 언어를 다시 수동으로 전환해야 합니다. 이는 마찰을 일으키고 현지화된 경험을 저해합니다.

모든 링크에 로케일 접두사를 하드코딩하는 것은 오류가 발생하기 쉽고 코드베이스를 취약하게 만듭니다. 사용자가 애플리케이션을 탐색하면서 활성 로케일이 변경될 수 있으며, 수백 개의 링크를 수동으로 업데이트하는 것은 지속 가능하지 않습니다.

솔루션

URL에서 현재 로케일을 자동으로 읽고 모든 내부 탐색 경로에 접두사로 추가하는 커스텀 Link 컴포넌트를 생성합니다. React Router의 Link 컴포넌트를 래핑함으로써 로케일 처리를 한 곳에 중앙 집중화합니다. 래퍼는 현재 라우트에서 로케일 매개변수를 추출하고 모든 대상 경로에 이를 포함시켜, 수동 개입 없이 탐색이 사용자의 언어 선택을 보존하도록 보장합니다.

이 접근 방식은 애플리케이션 전체에서 링크 정의를 깔끔하고 로케일에 구애받지 않게 유지하면서 모든 클릭과 함께 로케일 컨텍스트가 이동하도록 보장합니다.

단계

useParams를 사용하여 URL에서 현재 로케일을 추출하고 React Router의 Link 컴포넌트를 래핑하여 대상 경로에 로케일을 접두사로 추가하는 커스텀 컴포넌트를 구축합니다.

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

export function LocaleLink({ to, ...props }: LinkProps) {
  const { locale } = useParams<{ locale: string }>();

  const localizedTo =
    typeof to === "string"
      ? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
      : {
          ...to,
          pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
        };

  return <Link to={localizedTo} {...props} />;
}

이 컴포넌트는 현재 라우트에서 로케일 파라미터를 읽고 to prop에 전달하는 모든 경로에 자동으로 접두사를 추가하며, 문자열 및 객체 형식을 모두 처리합니다.

로케일을 유지하는 탐색이 필요한 곳마다 표준 Link 컴포넌트를 LocaleLink로 교체하세요.

import { LocaleLink } from "./LocaleLink";

export function Navigation() {
  return (
    <nav>
      <LocaleLink to="/">Home</LocaleLink>
      <LocaleLink to="/about">About</LocaleLink>
      <LocaleLink to="/products">Products</LocaleLink>
    </nav>
  );
}

/fr/products에 있는 사용자가 About 링크를 클릭하면 /fr/about로 이동합니다. 로케일 접두사는 링크 정의를 복잡하게 만들지 않고 자동으로 추가됩니다.

3. 절대 경로 및 외부 링크에 대한 엣지 케이스 처리

경로에 이미 로케일이 포함되어 있거나 외부 URL을 가리키는 경우를 감지하도록 래퍼를 확장하여 이중 접두사 추가나 외부 탐색 중단을 방지하세요.

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

export function LocaleLink({ to, ...props }: LinkProps) {
  const { locale } = useParams<{ locale: string }>();

  if (!locale) {
    return <Link to={to} {...props} />;
  }

  const isExternal =
    typeof to === "string" &&
    (to.startsWith("http://") || to.startsWith("https://"));
  const alreadyLocalized =
    typeof to === "string" && to.startsWith(`/${locale}/`);

  if (isExternal || alreadyLocalized) {
    return <Link to={to} {...props} />;
  }

  const localizedTo =
    typeof to === "string"
      ? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
      : {
          ...to,
          pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
        };

  return <Link to={localizedTo} {...props} />;
}

이는 경로가 이미 로케일로 시작하는 경우 이중 접두사 추가를 방지하고 외부 URL을 변경하지 않고 전달하여 모든 탐색 시나리오에서 컴포넌트가 안정적으로 작동하도록 보장합니다.