You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13多语言站点:如何用Cookie记住用户上次选择的语言

方案选择:优先用Cookie,LocalStorage做兜底
  • Cookie是最优解:服务端组件能直接读取,页面初始渲染就能加载用户偏好的语言,完全适配NextJS13的服务端渲染逻辑,不会出现客户端二次切换的闪烁问题。
  • LocalStorage仅作兜底:只能在客户端访问,服务端渲染时拿不到值,第一次加载还是默认语言,客户端读取后再切换会有视觉跳动,适合Cookie被禁用的场景。
具体实现步骤

1. 存储用户选择的语言到Cookie

在语言切换的客户端组件里,用户点击切换按钮时,除了跳转对应URL,同时设置Cookie(有效期可设为30天):

// 客户端组件中的语言切换逻辑
const handleLanguageChange = (lang) => {
  // 设置全站有效Cookie,有效期30天
  document.cookie = `preferred_lang=${lang}; path=/; maxAge=${30*24*60*60}; SameSite=Lax`;
  // 跳转到对应语言路径
  window.location.href = `/${lang}`;
};

2. 服务端读取Cookie,设置默认语言

在服务端组件(比如layout.js)中,通过headers()获取Cookie,解析出用户偏好语言,存在且合法就用该语言,否则用默认英语:

// app/layout.js(服务端组件)
import { headers } from 'next/headers';
import getDictionary from './dictionaries';

export default async function RootLayout({ children }) {
  const headersList = headers();
  const cookie = headersList.get('cookie');
  let preferredLang = 'en'; // 默认英语
  
  if (cookie) {
    // 解析Cookie提取语言值
    const langMatch = cookie.match(/preferred_lang=([a-z-]+)/);
    // 替换成你实际支持的语言列表
    if (langMatch && ['en', 'zh', 'es'].includes(langMatch[1])) {
      preferredLang = langMatch[1];
    }
  }

  const dict = await getDictionary(preferredLang);

  return (
    <html lang={preferredLang}>
      <body>
        {/* 将字典传递给子组件或通过Context分发 */}
        {children}
      </body>
    </html>
  );
}

3. 根路径重定向(可选)

如果用户访问根路径example.com/,可以在服务端组件中读取Cookie,直接重定向到用户偏好的语言页面:

// app/page.js(服务端组件)
import { redirect } from 'next/navigation';
import { headers } from 'next/headers';

export default async function HomePage() {
  const headersList = headers();
  const cookie = headersList.get('cookie');
  let preferredLang = 'en';

  if (cookie) {
    const langMatch = cookie.match(/preferred_lang=([a-z-]+)/);
    if (langMatch && ['en', 'zh', 'es'].includes(langMatch[1])) {
      preferredLang = langMatch[1];
    }
  }

  redirect(`/${preferredLang}`);
}

4. LocalStorage兜底逻辑(可选)

担心Cookie被禁用的话,在客户端组件中添加LocalStorage的读取和存储逻辑:

// 客户端组件
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';

export default function LanguageSwitcher() {
  const pathname = usePathname();
  const currentLang = pathname.split('/')[1] || 'en';

  useEffect(() => {
    // 页面加载时读取LocalStorage,若Cookie未生效则切换
    const savedLang = localStorage.getItem('preferred_lang');
    if (savedLang && savedLang !== currentLang && ['en', 'zh', 'es'].includes(savedLang)) {
      document.cookie = `preferred_lang=${savedLang}; path=/; maxAge=${30*24*60*60}; SameSite=Lax`;
      window.location.href = `/${savedLang}`;
    }
  }, []);

  const handleChange = (lang) => {
    // 切换时同时存到LocalStorage和Cookie
    localStorage.setItem('preferred_lang', lang);
    document.cookie = `preferred_lang=${lang}; path=/; maxAge=${30*24*60*60}; SameSite=Lax`;
    window.location.href = `/${lang}`;
  };

  return (
    <div>
      <button onClick={() => handleChange('en')}>English</button>
      <button onClick={() => handleChange('zh')}>中文</button>
    </div>
  );
}
注意事项
  • 维护一个合法语言列表,避免非法语言值导致逻辑错误。
  • Cookie的SameSite属性设为Lax或Strict,符合浏览器安全规范。

内容的提问来源于stack exchange,提问作者IdoBa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:23:14