Next.js(Pages Router) v16에서 탐색 링크의 로케일을 유지하는 방법

내부 탐색에서 로케일 유지

문제

웹 애플리케이션이 URL 경로에 언어 기본 설정을 인코딩하는 경우, 모든 내부 링크는 사용자 세션 전체에서 해당 언어 컨텍스트를 유지해야 합니다. 명시적인 로케일 처리가 없으면 단순 경로로 작성된 링크가 의도치 않게 언어 접두사를 제거하여 사용자가 탐색 중에 선택한 언어를 잃게 될 수 있습니다. 이는 로컬라이즈된 경험을 방해하고 사용자가 선호하는 언어를 반복적으로 선택하도록 강제합니다.

솔루션

라우터 컨텍스트에서 현재 로케일을 읽어 모든 내부 탐색 링크에 자동으로 포함되도록 합니다. Next.js Pages Router는 라우팅 시스템을 통해 내장 로케일 지원을 제공하며, 활성 로케일은 useRouter 훅을 통해 사용할 수 있습니다. 기본적으로 Link 컴포넌트는 클라이언트 측 전환 중에 현재 로케일을 유지하지만, 이 동작을 이해하고 애플리케이션 전체에 일관되게 적용하면 원활한 로케일 인식 탐색이 보장됩니다.

단계

1. 라우터에서 현재 로케일 액세스

useRouter 훅은 locale(현재 활성 로케일), locales(구성된 모든 로케일), defaultLocale(구성된 기본 로케일)를 제공합니다.

import { useRouter } from "next/router";

export default function Navigation() {
  const router = useRouter();
  const currentLocale = router.locale;

  return (
    <nav>
      <p>Current locale: {currentLocale}</p>
    </nav>
  );
}

이 컴포넌트는 라우터에서 활성 로케일을 읽어 탐색 로직에서 사용할 수 있도록 합니다.

Link에 locale prop이 제공되지 않으면 클라이언트 전환 중에 현재 활성 로케일이 사용됩니다.

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <Link href="/about">About</Link>
      <Link href="/products">Products</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

이러한 링크는 자동으로 현재 로케일을 유지합니다. 사용자가 /fr/products를 보고 있는 경우 "About"을 클릭하면 /fr/about로 이동합니다.

3. 명시적 제어를 위한 로케일 인식 링크 헬퍼 생성

명시적 제어가 필요하거나 로케일 처리를 더 명확하게 하려는 경우 현재 로케일을 명시적으로 전달하는 래퍼 컴포넌트를 생성합니다.

import Link from "next/link";
import { useRouter } from "next/router";
import { ReactNode } from "react";

interface LocaleLinkProps {
  href: string;
  children: ReactNode;
}

export function LocaleLink({ href, children }: LocaleLinkProps) {
  const { locale } = useRouter();

  return (
    <Link href={href} locale={locale}>
      {children}
    </Link>
  );
}

이 컴포넌트는 로케일 보존을 명시적으로 만들며, 필요한 경우 추가적인 로케일별 로직으로 확장할 수 있습니다.

4. 로케일 보존을 사용한 프로그래매틱 네비게이션 처리

라우터 메서드를 직접 사용할 때, 전환 옵션을 통해 로케일을 지정하거나, href 매개변수를 객체로 전달하여 로케일을 포함한 모든 라우팅 정보를 보존할 수 있습니다.

import { useRouter } from "next/router";

export default function NavigationButton() {
  const router = useRouter();
  const { pathname, asPath, query, locale } = router;

  const handleNavigate = () => {
    router.push({ pathname: "/dashboard", query }, asPath, { locale });
  };

  return <button onClick={handleNavigate}>Go to Dashboard</button>;
}

이 패턴은 프로그래매틱 네비게이션이 현재 로케일과 기존 쿼리 매개변수를 유지하도록 보장합니다.

5. 애플리케이션 전체에 일관된 링크 패턴 적용

애플리케이션 전체에서 표준 Link 컴포넌트를 사용하고 내장된 로케일 보존 동작을 활용합니다.

import Link from "next/link";

export default function ProductCard({ productId }: { productId: string }) {
  return (
    <article>
      <h2>Product {productId}</h2>
      <Link href={`/products/${productId}`}>View Details</Link>
      <Link href="/products">Back to Products</Link>
    </article>
  );
}

정적 및 동적 라우트 모두 자동으로 현재 로케일 접두사를 포함하여, 사용자가 애플리케이션을 탐색하는 동안 선택한 언어를 유지합니다.