TanStack Start v1에서 세션 간 언어 선택을 기억하는 방법
사용자의 명시적 언어 선택 저장
문제
사용자가 명시적으로 언어를 선택할 때, 그 선택은 현재 브라우저 세션을 넘어 지속되어야 하는 의도적인 선호도를 나타냅니다. 지속성이 없으면 애플리케이션은 매번 방문할 때마다 이 선호도를 잊어버리고, 사용자는 반복적으로 언어를 다시 선택해야 합니다. 이는 사용자 경험에 마찰을 일으키고 애플리케이션이 사용자의 선택을 존중하지 않는다는 신호를 보내며, 전반적인 경험을 저하시키고 사용자가 의도한 작업을 완료하기 전에 사이트를 떠날 가능성을 높입니다.
해결책
사용자가 명시적으로 언어를 선택할 때 그 선택을 지속적인 쿠키에 저장합니다. 이후 방문 시, 브라우저 헤더와 같은 자동 감지 방법으로 돌아가기 전에 이 저장된 선호도를 확인합니다. 유효한 저장된 언어가 발견되면 사용자를 사이트 루트에서 해당 언어의 경로로 리디렉션하여 추가 단계 없이 선호하는 로케일에 직접 도달할 수 있도록 합니다.
단계
1. 언어 선호도를 저장하는 서버 함수 생성
서버 함수를 사용하면 애플리케이션 어디에서나 호출할 수 있는 서버 전용 로직을 정의할 수 있습니다. 선택한 로케일을 쿠키에 기록하는 함수를 정의합니다.
import { createServerFn } from "@tanstack/react-start";
import { setCookie } from "@tanstack/react-start/server";
const LOCALE_COOKIE = "user_locale";
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
export const saveLocalePreference = createServerFn({ method: "POST" })
.validator((locale: string) => locale)
.handler(async ({ data }) => {
setCookie(LOCALE_COOKIE, data, {
maxAge: COOKIE_MAX_AGE,
path: "/",
sameSite: "lax",
});
return { success: true };
});
이 서버 함수는 @tanstack/react-start/server의 setCookie를 사용하여 로케일 선호도를 저장하고, 이후 요청에서 사용할 수 있도록 합니다.
2. 사용자가 언어를 선택할 때 저장 함수 호출하기
언어 전환 컴포넌트에서 사용자가 선택한 후 서버 함수를 호출합니다.
import { useNavigate } from "@tanstack/react-router";
import { saveLocalePreference } from "./locale-preference";
export function LanguageSwitcher({ currentLocale }: { currentLocale: string }) {
const navigate = useNavigate();
const handleLocaleChange = async (newLocale: string) => {
await saveLocalePreference({ data: newLocale });
navigate({ to: `/${newLocale}` });
};
return (
<select
value={currentLocale}
onChange={(e) => handleLocaleChange(e.target.value)}
>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
);
}
이렇게 하면 새 로케일로 이동하기 전에 환경설정이 저장됩니다.
3. 저장된 환경설정을 읽는 서버 함수 생성하기
쿠키에서 저장된 로케일을 검색하는 함수를 정의합니다.
import { createServerFn } from "@tanstack/react-start";
import { getCookie } from "@tanstack/react-start/server";
const LOCALE_COOKIE = "user_locale";
export const getStoredLocale = createServerFn({ method: "GET" }).handler(
async () => {
const stored = getCookie(LOCALE_COOKIE);
return stored || null;
},
);
@tanstack/react-start/server의 getCookie 함수는 이전 방문에서 설정된 쿠키 값을 읽습니다.
4. 루트 경로에서 저장된 환경설정 확인하기
경로의 beforeLoad 콜백에서 redirect 함수를 사용하여 저장된 환경설정이 발견되면 리디렉션을 트리거합니다.
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getStoredLocale } from "./locale-preference";
const SUPPORTED_LOCALES = ["en", "es", "fr"];
const DEFAULT_LOCALE = "en";
export const Route = createFileRoute("/")({
beforeLoad: async () => {
const stored = await getStoredLocale();
if (stored && SUPPORTED_LOCALES.includes(stored)) {
throw redirect({ to: `/${stored}` });
}
throw redirect({ to: `/${DEFAULT_LOCALE}` });
},
});
이 코드는 먼저 저장된 환경설정을 확인하고 유효한 경우 해당 로케일로 리디렉션하며, 그렇지 않으면 기본 로케일로 폴백합니다.
5. 지원되는 언어에 대해 저장된 로케일 유효성 검사
리디렉션하기 전에 저장된 값이 인식된 로케일인지 확인하는 유효성 검사를 추가합니다.
import { createFileRoute, redirect } from "@tanstack/react-router";
import { getStoredLocale } from "./locale-preference";
const SUPPORTED_LOCALES = ["en", "es", "fr", "de", "ja"] as const;
function isValidLocale(value: string | null): value is string {
return value !== null && SUPPORTED_LOCALES.includes(value as any);
}
export const Route = createFileRoute("/")({
beforeLoad: async () => {
const stored = await getStoredLocale();
const locale = isValidLocale(stored) ? stored : "en";
throw redirect({ to: `/${locale}` });
},
});
이는 쿠키 변조나 오래된 값으로부터 보호하기 위해 유효하지 않거나 지원되지 않는 로케일로의 리디렉션을 방지합니다.