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 함수와 로케일 상수를 공유 모듈에 배치하세요.