如何在 React Router v7 中检测用户的语言偏好

基于浏览器偏好自动重定向

问题

每个浏览器在发送 HTTP 请求时都会附带一个 Accept-Language 头,指明用户按优先顺序偏好的语言。这一头信息包含了用户期望看到的语言的宝贵信息,但大多数应用程序完全忽略了它。相反,它们向每位访问者显示默认语言——通常是英语,迫使用户手动寻找语言切换器,即使他们的浏览器已经传达了他们的偏好。这种做法增加了不必要的摩擦,尤其是对国际用户来说,留下了糟糕的第一印象。

解决方案

为根路径创建一个加载器,从传入请求中读取 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 头的值并返回最佳匹配的支持语言环境。

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;
}

此函数解析头信息,按优先级顺序遍历用户的语言偏好,并返回与支持语言环境的第一个匹配项,或者回退到默认值。

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 头并重定向到适当的语言环境路径。

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 头,确定最佳语言环境,并将其重定向到该语言环境的根路径,确保用户从首次页面加载时就能看到其首选语言的内容。