TanStack Start v1에서 사용자 언어 환경설정을 감지하는 방법
브라우저 환경설정에 따른 자동 리디렉션
문제
웹 브라우저는 모든 HTTP 요청과 함께 사용자가 선호하는 언어를 우선순위에 따라 표시하는 Accept-Language 헤더를 전송합니다. 이 헤더는 사용자가 가장 편안하게 사용할 수 있는 언어에 대한 중요한 정보를 제공하지만, 많은 애플리케이션에서는 이를 완전히 무시합니다. 대신, 실제 사용자 선호도와 관계없이 모든 방문자에게 기본 언어(일반적으로 영어)를 표시합니다. 사용자는 언어 전환기를 수동으로 찾아야 하는데, 이는 애플리케이션이 이미 더 나은 초기 선택을 위한 정보를 가지고 있음에도 불필요한 마찰을 만듭니다.
이러한 개인화 기회의 상실은 브라우저 언어 환경설정을 명시적으로 구성한 비영어권 사용자에게 특히 답답한 경험입니다. 결과적으로 첫인상이 저하되고 사용자가 선호하는 언어로 콘텐츠를 이용하기 전에 추가 단계가 필요하게 됩니다.
해결책
루트 경로에 대한 요청을 가로채고 Accept-Language 헤더를 검사하여 사용자가 선호하는 언어를 결정합니다. 헤더를 분석하여 애플리케이션이 지원하는 가장 높은 우선순위 언어를 추출합니다. 일치하는 항목이 발견되면 사용자를 적절한 현지화된 경로로 리디렉션합니다. 헤더에서 지원되는 언어가 발견되지 않으면 기본 언어 대체로 리디렉션합니다.
이 접근 방식은 각 언어가 자체 경로 접두사를 가지는 명확한 URL 구조를 유지하면서 사용자 선호도를 자동으로 존중합니다. 리디렉션은 페이지가 렌더링되기 전에 서버 측에서 발생하므로 사용자는 잘못된 언어가 깜빡이는 것을 보지 않고 선호하는 언어로 된 콘텐츠에 직접 도달합니다.
단계
1. Accept-Language 헤더를 분석하는 헬퍼 생성
Accept-Language 헤더에는 선호도 순서를 나타내는 선택적 품질 값이 있는 언어 코드가 포함되어 있습니다. 이러한 언어를 추출하고, 우선순위에 따라 정렬하며, 지원되는 언어 목록에서 첫 번째 일치 항목을 찾는 파서를 구축합니다.
export function parseAcceptLanguage(
header: string | null,
supportedLocales: string[],
): string | null {
if (!header) {
return null;
}
const languages = header
.split(",")
.map((lang) => {
const [code, qValue] = lang.trim().split(";q=");
const quality = qValue ? parseFloat(qValue) : 1.0;
return { code: code.toLowerCase(), quality };
})
.sort((a, b) => b.quality - a.quality);
for (const { code } of languages) {
const exactMatch = supportedLocales.find(
(locale) => locale.toLowerCase() === code,
);
if (exactMatch) {
return exactMatch;
}
const baseCode = code.split("-")[0];
const baseMatch = supportedLocales.find((locale) =>
locale.toLowerCase().startsWith(baseCode),
);
if (baseMatch) {
return baseMatch;
}
}
return null;
}
이 함수는 헤더를 쉼표로 분할하고, 품질 값을 추출하며, 선호도에 따라 정렬한 다음 지원되는 로케일에 대해 정확한 일치와 기본 언어 일치를 모두 확인합니다.
2. 지원하는 로케일 정의하기
애플리케이션이 지원하는 모든 언어를 나열하고 기본 폴백으로 사용할 언어를 지정하는 구성을 생성합니다.
export const SUPPORTED_LOCALES = ["en", "fr", "de", "es", "ja"];
export const DEFAULT_LOCALE = "en";
이러한 상수는 언어 구성을 중앙 집중화하고 애플리케이션이 성장함에 따라 지원되는 언어를 쉽게 추가하거나 제거할 수 있게 합니다.
3. 루트 경로에 대한 서버 라우트 핸들러 생성하기
인덱스 라우트에 서버 측 GET 핸들러를 추가하여 Accept-Language 헤더를 읽고, 최적의 로케일을 결정한 다음, 사용자를 적절한 언어별 경로로 리디렉션합니다.
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getRequestHeaders } from "@tanstack/react-start/server";
export const Route = createFileRoute("/")({
server: {
handlers: {
GET: async () => {
const headers = getRequestHeaders();
const acceptLanguage = headers.get("accept-language");
const preferredLocale = parseAcceptLanguage(
acceptLanguage,
SUPPORTED_LOCALES,
);
const targetLocale = preferredLocale || DEFAULT_LOCALE;
throw redirect({
to: `/${targetLocale}`,
statusCode: 302,
});
},
},
},
});
이 핸들러는 사용자가 루트 경로를 방문할 때 서버에서 실행되어 사용자의 언어 환경설정을 검사하고 클라이언트 측 코드가 실행되기 전에 즉시 가장 적합한 로케일 경로로 리디렉션합니다.
4. 헬퍼 함수 가져오기
로케일 구성과 함께 파일 상단에서 파싱 헬퍼를 가져와 라우트 파일에서 사용할 수 있도록 합니다.
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getRequestHeaders } from "@tanstack/react-start/server";
import {
parseAcceptLanguage,
SUPPORTED_LOCALES,
DEFAULT_LOCALE,
} from "../lib/locale";
필요한 경우 애플리케이션 전체에서 재사용할 수 있도록 parseAcceptLanguage 함수와 로케일 상수를 공유 모듈에 배치하세요.