如何在 React Router v7 中检测用户的语言偏好
基于浏览器偏好自动重定向
问题
每个浏览器在发送 HTTP 请求时都会携带 Accept-Language 头部,按优先顺序指明用户偏好的语言。这一头部包含了用户期望看到的语言的重要信息,但大多数应用却完全忽略了它。相反,应用通常会向每位访问者展示默认语言(通常为英语),即使浏览器已经传达了用户的偏好,用户仍需手动查找语言切换器。这不仅增加了不必要的操作,还会给国际用户留下不佳的第一印象。
解决方案
为根路径创建一个 loader,从传入请求中读取 Accept-Language 头部。解析该头部,提取用户偏好的语言及其权重值。将这些偏好语言与应用支持的本地化语言进行比对。如果找到匹配项,则将用户重定向到对应语言的路径;如果没有匹配,则重定向到默认语言。这样,用户可以根据其浏览器已配置的偏好,自动访问本地化版本的网站。
步骤
1. 安装用于解析 Accept-Language 头部的库
Accept-Language 头部有特定格式,并包含权重值,需要仔细解析。建议使用专门的库来正确处理。
npm install accept-language-parser
该库会将头部字符串解析为有序的语言偏好列表,按照 HTTP 规范正确处理权重值和各种边界情况。
2. 定义支持的本地化语言
创建一个辅助文件,列出应用支持的所有本地化语言,并指定默认回退语言。
export const supportedLocales = ["en", "fr", "de", "es", "ja"] as const;
export const defaultLocale = "en";
export type Locale = (typeof supportedLocales)[number];
这为应用程序支持的语言提供了单一的可信来源,并确保整个代码库的类型安全。
3. 创建本地化检测辅助函数
编写一个函数,接收 Accept-Language 头部的值,并返回与支持语言最匹配的 locale。
import parser from "accept-language-parser";
import { supportedLocales, defaultLocale, type Locale } from "./locales";
export function detectLocale(acceptLanguageHeader: string | null): Locale {
if (!acceptLanguageHeader) {
return defaultLocale;
}
const languages = parser.parse(acceptLanguageHeader);
for (const lang of languages) {
const code = lang.code.toLowerCase();
if (supportedLocales.includes(code as Locale)) {
return code as Locale;
}
}
return defaultLocale;
}
该函数会解析头部,按优先级顺序遍历用户的语言偏好,并返回与支持语言列表中第一个匹配的 locale,若无匹配则回退到默认值。
4. 配置根索引路由
在路由配置中添加一个索引路由,用于处理根路径的请求。
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/index.tsx"),
route(":locale", "routes/locale-root.tsx", []),
] satisfies RouteConfig;
索引路由会在其他路由匹配前拦截根路径请求,使你能够执行语言检测和重定向。
5. 实现带有语言检测的索引路由加载器
创建索引路由模块,读取 Accept-Language 头部并重定向到对应的 locale 路径。
import { redirect } from "react-router";
import type { Route } from "./+types/index";
import { detectLocale } from "~/utils/detect-locale";
export async function loader({ request }: Route.LoaderArgs) {
const acceptLanguage = request.headers.get("Accept-Language");
const locale = detectLocale(acceptLanguage);
return redirect(`/${locale}`);
}
当用户访问根路径时,该加载器会从请求中提取 Accept-Language 头部,确定最佳 locale,并将其重定向到该 locale 的根路径,确保用户从首次加载页面起就能看到其偏好语言的内容。