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

Next.js集成react-i18n刷新页面出现文本不匹配等水化错误

Next.js + react-i18next 刷新页面 hydration 不匹配问题解决

问题出在服务端渲染时,react-i18next 还没加载完翻译文件,导致服务端输出的是翻译key(比如page_about),客户端加载完成后显示翻译后的文本(比如About Us),两边内容不匹配就触发了 hydration 错误。下面是具体解决步骤:

1. 区分服务端/客户端初始化i18n

修改src/configs/i18n.js,让服务端直接读取本地翻译文件,避免依赖HTTP请求加载:

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

const isServer = typeof window === 'undefined'

// 封装初始化函数,支持传入语言参数
const initI18n = async (lng = 'tr') => {
  const backendOptions = {
    loadPath: '/locales/{{lng}}.json'
  }

  // 服务端直接读取public/locales下的翻译文件
  if (isServer) {
    const localesDir = path.join(process.cwd(), 'public', 'locales')
    backendOptions.loadPath = (language) => {
      const filePath = path.join(localesDir, `${language}.json`)
      return JSON.parse(fs.readFileSync(filePath, 'utf8'))
    }
  }

  await i18n
    // 服务端不需要http-backend和浏览器语言检测
    .use(isServer ? {} : Backend)
    .use(isServer ? {} : LanguageDetector)
    .use(initReactI18next)
    .init({
      lng: isServer ? lng : undefined,
      backend: backendOptions,
      fallbackLng: 'tr',
      debug: false,
      keySeparator: false,
      react: {
        useSuspense: true, // 开启Suspense配合服务端预加载
      },
      interpolation: {
        escapeValue: false,
        formatSeparator: ','
      }
    })
}

export default initI18n

2. 在_app.js中预加载i18n并包裹Suspense

修改_app.js,确保服务端渲染前完成翻译加载,客户端用Suspense处理加载状态:

import initI18n from 'src/configs/i18n'
import { Suspense } from 'react'

const MyApp = ({ Component, pageProps }) => {
  const getLayout = Component.layout ?? (page => <Layout>{page}</Layout>)

  return (
    <>
      <Provider store={store}>
        <ThemeProvider theme={theme}>
          {/* 用Suspense包裹,避免hydration时内容不匹配 */}
          <Suspense fallback={<div>加载中...</div>}>
            {getLayout(<Component {...pageProps} />)}
          </Suspense>
        </ThemeProvider>
      </Provider>
    </>
  )
}

MyApp.getInitialProps = async (context) => {
  // 服务端初始化i18n,可从请求头获取用户语言偏好
  if (typeof window === 'undefined') {
    const req = context.ctx.req
    // 从accept-language头提取首选语言,没有则用默认tr
    const userLng = req.headers['accept-language']?.split(',')[0].split('-')[0] || 'tr'
    await initI18n(userLng)
  }
  const ctx = await App.getInitialProps(context)

  return {
    ...ctx,
  };
};

// 客户端初始化i18n
if (typeof window !== 'undefined') {
  initI18n()
}

export default MyApp

3. 简化Translations组件

去掉冗余的模板字符串,直接返回翻译结果:

import { useTranslation } from "react-i18next";

const Translations = ({ text }) => {
  const { t } = useTranslation()
  return <>{t(text)}</>
}

export default Translations

这样修改后,服务端渲染时会提前加载对应语言的翻译内容,确保服务端输出的HTML和客户端 hydration 时的内容完全一致,就能解决刷新页面时的那些错误了。

内容的提问来源于stack exchange,提问作者M.Çelik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:57:55