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
相关产品推荐
相关产品推荐

