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

Next.js中不使用子路径/域名路由实现i18n的方案咨询

在Next.js中实现无路由切换的i18n(解决服务端/客户端文本不匹配问题)

问题根源

你遇到的Text content does not match server-rendered HTML错误,本质是服务端渲染时用的语言和客户端hydrate时的语言不一致——服务端输出了英文"login",但客户端初始化后切换成了德语"Anmelden",导致DOM不匹配。下面是不用子路径/域名路由的完整解决方案:


1. 安装依赖

直接用i18next生态,不需要Next.js内置的i18n路由:

npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend

2. 配置i18n核心

在src/i18n.js(或项目根目录)创建配置文件,禁用路由相关逻辑,优先从localStorage/cookie读取语言:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';

i18n
  .use(Backend) // 加载public文件夹下的翻译文件
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: 'en',
    debug: false,
    interpolation: { escapeValue: false }, // React自带转义,无需额外处理
    detection: {
      order: ['localStorage', 'cookie', 'navigator'], // 优先级:本地存储 > Cookie > 浏览器语言
      caches: ['localStorage', 'cookie'], // 缓存语言选择
    },
    react: { useSuspense: false }, // 避免SSR时的Suspense阻塞
  });

export default i18n;

3. 同步服务端与客户端语言

Next.js是SSR/SSG,服务端无法访问浏览器存储,必须通过Cookie传递用户的语言偏好,保证两端渲染一致。

3.1 改造_app.js

在pages/_app.js中处理服务端语言获取和客户端初始化:

import '../i18n';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

function MyApp({ Component, pageProps, initialLanguage }) {
  const { i18n } = useTranslation();
  const [isHydrated, setIsHydrated] = useState(false);

  useEffect(() => {
    setIsHydrated(true);
    // 客户端初始化时,同步服务端传递的初始语言
    if (initialLanguage) i18n.changeLanguage(initialLanguage);
  }, [i18n, initialLanguage]);

  // 未完成hydrate前不渲染内容,避免DOM不匹配
  if (!isHydrated) return null;

  return <Component {...pageProps} />;
}

// 服务端获取初始语言
MyApp.getInitialProps = async ({ ctx }) => {
  let initialLanguage = 'en';
  // 从Cookie读取用户之前的选择
  if (ctx.req?.headers.cookie) {
    const langCookie = ctx.req.headers.cookie.split(';').find(c => c.trim().startsWith('i18next='));
    if (langCookie) initialLanguage = langCookie.split('=')[1];
  }
  // 无Cookie时,从请求头获取浏览器偏好语言
  else if (ctx.req) {
    const acceptLang = ctx.req.headers['accept-language'];
    if (acceptLang) initialLanguage = acceptLang.split(',')[0].split('-')[0];
  }
  return { initialLanguage };
};

export default MyApp;

3.2 实现语言选择器

创建语言切换组件,切换时同步更新Cookie,确保服务端下次渲染能拿到正确语言:

import { useTranslation } from 'react-i18next';

const LanguageSelector = () => {
  const { i18n } = useTranslation();

  const switchLanguage = (lng) => {
    i18n.changeLanguage(lng);
    // 设置Cookie,有效期1年
    document.cookie = `i18next=${lng}; max-age=31536000; path=/`;
  };

  return (
    <div className="language-selector">
      <button onClick={() => switchLanguage('en')}>English</button>
      <button onClick={() => switchLanguage('de')}>Deutsch</button>
    </div>
  );
};

export default LanguageSelector;

4. 存放翻译文件

在public/locales文件夹下创建对应语言的翻译文件:

  • public/locales/en/translation.json
{
  "login": "Login"
}
  • public/locales/de/translation.json
{
  "login": "Anmelden"
}

5. 在组件中使用翻译

正常调用useTranslation获取翻译函数:

import { useTranslation } from 'react-i18next';

const LoginButton = () => {
  const { t } = useTranslation();
  return <button>{t('login')}</button>;
};

export default LoginButton;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 05:36:35