如何在 Next.js (Pages Router) v16 中跨会话记住语言选择
存储用户明确的语言选择
问题
当用户明确选择了一种语言时,这一选择反映了他们的偏好,应优先于通过浏览器头信息或地理位置的自动检测。如果没有持久化,这种偏好会在浏览器关闭或会话结束时丢失。在下次访问时,应用程序会重新开始,迫使用户再次选择语言。这种重复操作表明应用程序不尊重用户的偏好,增加了使用的摩擦并降低了信任。
这个挑战有两个方面:在用户选择语言时捕获其明确选择,并在后续访问中在任何自动检测逻辑运行之前检索该选择。如果在请求生命周期的早期未检查存储的偏好,用户可能会根据浏览器设置被重定向,而不是根据他们的明确选择,这削弱了选择的价值。
解决方案
当用户明确选择语言时,将其语言选择存储在一个持久化的 cookie 中。在未来访问应用程序根目录时,先检查这个 cookie,再回退到基于浏览器的语言检测。如果找到有效的存储语言偏好,则将用户重定向到该语言的根路径,确保立即尊重他们的偏好。
这种方法将用户的明确选择与自动检测分开。cookie 作为一种持久的意图信号,可以在浏览器重启后仍然有效,并优先于诸如 Accept-Language 头之类的临时信号。通过在初始请求期间在服务器端检查 cookie,重定向会在页面渲染之前发生,从而提供无缝的体验。
步骤
1. 创建一个助手函数,在客户端设置语言偏好 cookie
当用户选择一种语言时,将他们的选择存储在一个跨会话持久的 cookie 中。
export function setLocalePreference(locale: string) {
const maxAge = 60 * 60 * 24 * 365;
document.cookie = `NEXT_LOCALE=${locale}; path=/; max-age=${maxAge}; SameSite=Lax`;
}
此函数会写入一个名为 NEXT_LOCALE 的 cookie,包含所选的语言环境,有效期为一年。path=/ 确保它在整个应用程序中可用,而 SameSite=Lax 提供了合理的 CSRF 保护,同时允许在顶级导航时发送该 cookie。
2. 在用户选择语言时调用辅助函数
将辅助函数集成到语言切换组件中,以便在选择后立即保存偏好。
import { useRouter } from "next/router";
import { setLocalePreference } from "@/lib/locale";
export default function LanguageSwitcher() {
const router = useRouter();
const { locales, locale: currentLocale } = router;
const handleLocaleChange = (newLocale: string) => {
setLocalePreference(newLocale);
router.push(router.pathname, router.asPath, { locale: newLocale });
};
return (
<select
value={currentLocale}
onChange={(e) => handleLocaleChange(e.target.value)}
>
{locales?.map((loc) => (
<option key={loc} value={loc}>
{loc.toUpperCase()}
</option>
))}
</select>
);
}
当用户更改选择时,会设置 cookie,并且路由器会导航到新语言环境的同一页面。该 cookie 将在所有后续请求中可用。
3. 在根页面检查存储的偏好
在根页面的 getServerSideProps 中,读取 cookie 并在其存在且有效时重定向到存储的语言环境。
import { GetServerSideProps } from "next";
export const getServerSideProps: GetServerSideProps = async (context) => {
const storedLocale = context.req.cookies.NEXT_LOCALE;
const { locales, defaultLocale } = context;
if (
storedLocale &&
locales?.includes(storedLocale) &&
storedLocale !== defaultLocale
) {
return {
redirect: {
destination: `/${storedLocale}`,
permanent: false,
},
};
}
return {
redirect: {
destination: `/${defaultLocale}`,
permanent: false,
},
};
};
export default function RootPage() {
return null;
}
此代码检查 NEXT_LOCALE cookie 是否存在并包含应用程序配置列表中的有效语言环境。如果存储的语言环境不是默认值,则用户会被重定向到该语言环境的根目录。否则,他们会被重定向到默认语言环境。重定向在渲染之前的服务器端发生,确保用户立即进入正确的语言环境。
4. 在 Next.js 中配置语言区域路由
确保您的 next.config.js 定义了支持的语言区域,以便重定向逻辑可以验证存储的偏好。
module.exports = {
i18n: {
locales: ["en", "fr", "de", "es"],
defaultLocale: "en",
},
};
此配置启用了 Next.js 内置的 i18n 路由,并使 locales 和 defaultLocale 可用于 getServerSideProps。根页面逻辑使用这些值来验证存储的 cookie 并构建正确的重定向目标。