React Router v7에서 세션 간 언어 선택을 기억하는 방법
사용자의 명시적 언어 선택 저장하기
문제
사용자가 명시적으로 언어를 선택할 때, 그 선택은 사용자의 선호도를 반영하며 자동 감지를 무시해야 합니다. 지속성이 없으면 이 선택은 브라우저가 닫히거나 세션이 종료될 때 사라집니다. 다음 방문 시, 애플리케이션은 새로 시작하여 사용자가 다시 언어를 선택하도록 강요합니다. 이러한 반복은 애플리케이션이 사용자의 선호도를 존중하지 않는다는 신호를 보내며, 마찰을 일으키고 신뢰를 감소시킵니다.
해결책
사용자가 언어를 선택할 때 쿠키와 같은 지속적인 위치에 해당 선택을 저장합니다. 이후 방문 시, 브라우저 헤더나 다른 감지 방법으로 돌아가기 전에 이 저장된 선호도를 확인합니다. 유효한 저장된 언어가 발견되면 사용자를 자동으로 해당 언어의 경로로 리디렉션합니다. 이렇게 하면 사용자의 명시적 선택이 우선시되고 세션 간에 지속됩니다.
단계
1. 언어 선호도를 저장하기 위한 쿠키 생성
긴 만료 시간을 가진 사용자의 선택된 언어를 보관할 쿠키를 정의합니다.
import { createCookie } from "react-router";
export const languagePreference = createCookie("language-preference", {
maxAge: 31536000,
httpOnly: false,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
이 쿠키는 1년 동안 지속되며 선호도를 읽기 위해 클라이언트 측 코드에서 접근할 수 있습니다.
2. 언어 선택을 저장하는 액션 추가
언어 선택 폼 제출을 처리하고 선택을 쿠키에 저장하는 액션을 생성합니다.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const selectedLanguage = formData.get("language");
if (typeof selectedLanguage === "string") {
return redirect(`/${selectedLanguage}`, {
headers: {
"Set-Cookie": await languagePreference.serialize(selectedLanguage),
},
});
}
return redirect("/");
}
사용자가 언어 선택을 제출하면, 이 액션은 그것을 쿠키에 저장하고 사용자를 적절한 언어 경로로 리디렉션합니다.
3. 언어 선택 컴포넌트 만들기
사용자가 선호하는 언어를 선택할 수 있는 폼 컴포넌트를 구축합니다.
import { Form } from "react-router";
export function LanguageSelector({
currentLanguage,
}: {
currentLanguage: string;
}) {
return (
<Form method="post">
<select
name="language"
defaultValue={currentLanguage}
onChange={(e) => e.currentTarget.form?.requestSubmit()}
>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
</select>
</Form>
);
}
이 컴포넌트는 사용자가 선택을 변경하면 자동으로 제출되어 환경설정을 저장하는 액션을 트리거합니다.
4. 루트 로더에서 저장된 환경설정 확인하기
루트 라우트 로더에 저장된 언어 환경설정을 확인하고 그에 따라 리다이렉트하는 로직을 추가합니다.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const cookieHeader = request.headers.get("Cookie");
const storedLanguage = await languagePreference.parse(cookieHeader);
if (url.pathname === "/" && storedLanguage) {
return redirect(`/${storedLanguage}`);
}
return null;
}
사용자가 루트 경로를 방문하면 이 로더는 저장된 언어 환경설정을 확인하고 선택한 언어 라우트로 리다이렉트합니다(존재하는 경우).
5. 저장된 언어를 지원되는 로케일과 비교하여 검증하기
리다이렉션에 사용하기 전에 저장된 환경설정이 유효한지 확인합니다.
import { redirect } from "react-router";
import type { Route } from "./+types/root";
import { languagePreference } from "./cookies";
const SUPPORTED_LANGUAGES = ["en", "es", "fr", "de"];
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const cookieHeader = request.headers.get("Cookie");
const storedLanguage = await languagePreference.parse(cookieHeader);
if (
url.pathname === "/" &&
storedLanguage &&
SUPPORTED_LANGUAGES.includes(storedLanguage)
) {
return redirect(`/${storedLanguage}`);
}
return null;
}
이 검증은 쿠키 값이 변조되었거나 환경설정이 저장된 이후 지원되는 언어가 변경된 경우 잘못되거나 지원되지 않는 언어 라우트로 리다이렉트되는 것을 방지합니다.