如何在 TanStack Start v1 中跨会话记住语言选择
存储用户明确的语言选择
问题
当用户明确选择一种语言时,这一选择代表了一个深思熟虑的偏好,应该在当前浏览器会话之外持续存在。如果没有持久性,应用程序会在每次访问时忘记这一偏好,迫使用户反复重新选择语言。这会增加摩擦,并表明应用程序不尊重用户的选择,从而降低整体体验,并可能导致用户在完成预期任务之前放弃网站。
解决方案
当用户明确选择语言时,将其语言选择存储在一个持久性 cookie 中。在后续访问中,在回退到自动检测方法(如浏览器头信息)之前,检查此存储的偏好。如果找到有效的存储语言,则将用户从站点根目录重定向到该语言的路径,确保他们直接进入其首选的语言环境,而无需额外步骤。
步骤
1. 创建一个服务器函数来存储语言偏好
服务器函数允许您定义仅在服务器上运行的逻辑,可以从应用程序的任何地方调用。定义一个函数,将选定的语言环境写入 cookie。
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. 创建一个服务器函数以读取存储的偏好设置
定义一个函数,从 cookie 中检索存储的语言环境。
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 函数读取了在之前访问中设置的 cookie 值。
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}` });
},
});
这可以防止重定向到无效或不支持的语言环境,从而保护系统免受 Cookie 篡改或过期值的影响。