如何在 Next.js (Pages Router) v16 中检测用户语言偏好

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

问题

每个浏览器在发送 HTTP 请求时都会附带一个 Accept-Language 头,指示用户的首选语言及其优先级顺序。然而,大多数应用程序忽略了这一重要信号,而是向所有访问者提供默认语言,迫使用户即使应用程序已经知道他们的偏好,也需要手动寻找语言切换器。这在首次访问时造成了不必要的阻碍,甚至可能导致用户在找到自己语言的内容之前就放弃了网站。

当用户访问应用程序的根路径时,可以利用这一机会检查他们的语言偏好,并立即将他们引导到他们能够理解的语言内容。如果没有这种检测,国际用户将面临以英语为主的体验,无论他们的浏览器设置如何,从而错失提供友好、本地化的首次印象的机会。

解决方案

创建一个根页面,在每次对根路径的请求时运行服务器端逻辑。从传入请求中读取 Accept-Language HTTP 头并解析它,以提取用户的最优先语言。将此语言与应用程序支持的语言列表进行比较。如果找到匹配项,则将用户重定向到该语言的根路径。如果没有支持的语言匹配,则重定向到默认语言路径。

此方法利用了 Next.js 的 getServerSideProps 函数,该函数在每次请求时在服务器上执行,并可以返回一个重定向响应。通过在根路径处理检测,应用程序提供了一个智能的默认设置,同时仍然允许用户在之后手动切换语言。

步骤

1. 安装一个库来解析 Accept-Language 头

Accept-Language 标头包含一个以逗号分隔的语言代码列表,并带有可选的质量值,这些值必须被解析。安装一个解析库来处理此格式。

npm install accept-language-parser

此库从标头字符串中提取语言代码和质量分数,并按优先顺序返回它们。

2. 创建一个带有服务器端重定向逻辑的根页面

创建一个 pages/index.tsx 文件,该文件将自动路由到根目录。使用 getServerSideProps 返回一个包含目标地址和永久标志的重定向对象。

import { GetServerSideProps } from "next";
import parser from "accept-language-parser";

const SUPPORTED_LOCALES = ["en", "fr", "es", "de"];
const DEFAULT_LOCALE = "en";

export default function RootPage() {
  return null;
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const acceptLanguageHeader = context.req.headers["accept-language"];

  let targetLocale = DEFAULT_LOCALE;

  if (acceptLanguageHeader) {
    const languages = parser.parse(acceptLanguageHeader);

    const matchedLanguage = languages.find((lang) =>
      SUPPORTED_LOCALES.includes(lang.code),
    );

    if (matchedLanguage) {
      targetLocale = matchedLanguage.code;
    }
  }

  return {
    redirect: {
      destination: `/${targetLocale}`,
      permanent: false,
    },
  };
};

getServerSideProps 函数在每次请求时运行,读取 Accept-Language 标头并在渲染任何页面内容之前重定向到适当的语言路径。

3. 定义支持的语言环境

更新 SUPPORTED_LOCALES 数组以匹配您的应用程序支持的语言。解析器将按质量顺序返回语言,代码会选择第一个匹配项。

const SUPPORTED_LOCALES = ["en", "fr", "es", "de", "ja", "zh"];
const DEFAULT_LOCALE = "en";

解析器按从高到低的质量顺序返回语言,因此找到的第一个支持的语言代表您的应用程序可以满足的用户最强偏好。

4. 处理没有 Accept-Language 标头的情况

某些请求可能不包含 Accept-Language 标头。代码会检查标头是否存在,并在缺失时回退到默认语言环境。

if (acceptLanguageHeader) {
  const languages = parser.parse(acceptLanguageHeader);

  const matchedLanguage = languages.find((lang) =>
    SUPPORTED_LOCALES.includes(lang.code),
  );

  if (matchedLanguage) {
    targetLocale = matchedLanguage.code;
  }
}

这确保了即使浏览器语言信息不可用,应用程序也始终会重定向到有效的语言环境路径。