React Router v7에서 언어 전환 컴포넌트 구축하는 방법
동일한 페이지에 머물면서 언어 전환하기
문제
사용자들은 언어 전환기가 현재 컨텍스트를 유지해주기를 기대합니다. 제품 페이지, 도움말 문서 또는 계정 설정을 탐색하는 중에 영어에서 스페인어로 전환할 때 동일한 페이지가 스페인어로 표시되어야 합니다. 그러나 많은 구현에서는 언어 선택을 새 언어로 홈페이지로 리디렉션하는 탐색 이벤트로 취급하여 사용자가 이전 위치로 다시 이동해야 합니다. 이는 사용자의 흐름을 방해하고 좌절감을 주며, 특히 사용자가 복잡한 탐색 계층 구조 내에 있는 콘텐츠가 많은 애플리케이션에서 더욱 그렇습니다.
근본 원인은 언어 전환기가 현재 페이지를 기반으로 URL을 동적으로 구성하는 대신 하드코딩된 목적지 URL을 사용하는 경우가 많기 때문입니다. 현재 URL 구조를 읽고 변환하지 않으면 전환기는 언어 변경 시 애플리케이션에서 사용자의 위치를 유지할 수 없습니다.
해결책
현재 URL을 읽고 활성 로케일 매개변수와 나머지 경로 세그먼트를 추출하는 언어 전환기 컴포넌트를 구축합니다. 지원되는 각 언어에 대해 다른 모든 경로 세그먼트와 쿼리 매개변수는 그대로 유지하면서 로케일 세그먼트만 교체하여 새 URL을 생성합니다. 이러한 URL을 링크로 렌더링하여 사용자가 애플리케이션에서 위치를 잃지 않고 언어를 전환할 수 있도록 합니다.
이 접근 방식은 로케일을 탐색 목적지가 아닌 URL 구조에서 교체 가능한 매개변수로 취급하여 /en/products/shoes에서 /es/products/shoes로 전환할 때 사용자의 컨텍스트를 유지합니다.
단계
1. 로케일 인식 URL을 구축하는 헬퍼 함수 생성
현재 경로와 대상 로케일을 받아 로케일 세그먼트를 교체하여 새 경로를 구성하는 함수를 정의합니다.
export function buildLocalePath(
currentPath: string,
newLocale: string,
): string {
const segments = currentPath.split("/").filter(Boolean);
if (segments.length === 0) {
return `/${newLocale}`;
}
segments[0] = newLocale;
return `/${segments.join("/")}`;
}
이 함수는 경로명을 세그먼트로 분할하고, 첫 번째 세그먼트를 대상 로케일로 교체한 다음 경로를 재구성합니다. 루트 경로와 같은 엣지 케이스를 처리하고 로케일이 항상 첫 번째 세그먼트가 되도록 합니다.
2. 지원하는 로케일 정의하기
애플리케이션이 지원하는 모든 언어를 나열하는 구성 객체를 생성합니다.
export const locales = [
{ code: "en", label: "English" },
{ code: "es", label: "Español" },
{ code: "fr", label: "Français" },
{ code: "de", label: "Deutsch" },
];
이 구성은 언어 전환기에 표시할 언어의 진실 소스 역할을 하며 각 로케일에 대한 사용자 친화적인 레이블을 제공합니다.
3. 언어 전환기 컴포넌트 구축하기
현재 위치를 읽고, 활성 로케일을 결정하며, 지원되는 다른 모든 언어에 대한 링크를 렌더링하는 컴포넌트를 생성합니다.
import { Link, useLocation, useParams } from "react-router";
import { locales, buildLocalePath } from "./i18n-config";
export function LanguageSwitcher() {
const location = useLocation();
const params = useParams();
const currentLocale = params.locale || "en";
return (
<nav aria-label="Language switcher">
<ul>
{locales.map((locale) => {
const isActive = locale.code === currentLocale;
const newPath = buildLocalePath(location.pathname, locale.code);
return (
<li key={locale.code}>
{isActive ? (
<span aria-current="true">{locale.label}</span>
) : (
<Link to={newPath}>{locale.label}</Link>
)}
</li>
);
})}
</ul>
</nav>
);
}
이 컴포넌트는 useLocation을 사용하여 현재 경로명에 접근하고 useParams를 사용하여 URL에서 활성 로케일을 추출합니다. 지원되는 각 로케일에 대해 헬퍼 함수를 사용하여 새 경로를 생성하고 현재 언어에 대해서는 링크 또는 비대화형 요소를 렌더링합니다.
4. 쿼리 매개변수 및 해시 프래그먼트 보존하기
언어를 전환할 때 쿼리 문자열과 URL 프래그먼트를 유지하도록 헬퍼 함수를 확장합니다.
export function buildLocalePath(
currentPath: string,
search: string,
hash: string,
newLocale: string,
): string {
const segments = currentPath.split("/").filter(Boolean);
if (segments.length === 0) {
return `/${newLocale}${search}${hash}`;
}
segments[0] = newLocale;
return `/${segments.join("/")}${search}${hash}`;
}
이 업데이트된 버전은 location 객체에서 search와 hash 속성을 받아 생성된 경로에 추가하여 필터, 정렬 매개변수 및 앵커 링크가 언어 전환 시에도 유지되도록 합니다.
5. 향상된 헬퍼를 사용하도록 컴포넌트 업데이트
전체 위치 정보를 헬퍼 함수에 전달하도록 스위처를 수정합니다.
import { Link, useLocation, useParams } from "react-router";
import { locales, buildLocalePath } from "./i18n-config";
export function LanguageSwitcher() {
const location = useLocation();
const params = useParams();
const currentLocale = params.locale || "en";
return (
<nav aria-label="Language switcher">
<ul>
{locales.map((locale) => {
const isActive = locale.code === currentLocale;
const newPath = buildLocalePath(
location.pathname,
location.search,
location.hash,
locale.code,
);
return (
<li key={locale.code}>
{isActive ? (
<span aria-current="true">{locale.label}</span>
) : (
<Link to={newPath}>{locale.label}</Link>
)}
</li>
);
})}
</ul>
</nav>
);
}
이제 컴포넌트는 location.search와 location.hash를 헬퍼에 전달하여 /en/products?category=shoes#reviews와 같은 URL이 스페인어로 전환할 때 /es/products?category=shoes#reviews가 되도록 보장합니다.