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

刷新页面后SSR与客户端翻译不匹配引发Hydration错误如何解决?

解决Next.js SSR与客户端翻译Hydration不匹配问题

技术栈版本

  • Next.js: 15.1.2
  • React: 18.3.1
  • i18next: 25.2.1
  • next-i18next: 15.4.2
  • react-i18next: 15.5.3

问题描述

客户端翻译功能正常,但刷新页面(尤其生产环境)出现以下错误:

Hydration failed because the server rendered HTML didn't match the client...

已确认next-i18next.config.js配置正确,且在getStaticProps中使用了serverSideTranslations,但仍存在翻译不匹配。

解决方案

1. 确保服务端与客户端Locale严格同步

服务端渲染时必须将当前页面的locale准确传递给serverSideTranslations,避免客户端自行判断Locale时出现偏差:

export async function getStaticProps({ locale }) {
  return {
    props: {
      // 确保传入当前页面的locale,且指定对应的命名空间
      ...await serverSideTranslations(locale, ['common']),
    },
  };
}

同时页面组件需接收locale作为props,确保客户端使用与服务端一致的Locale值。

2. 调整ready状态的处理逻辑,避免Hydration结构不匹配

当前代码中服务端渲染时ready状态为true(服务端已加载翻译资源),但客户端初始渲染时ready可能为false,导致服务端输出翻译内容、客户端输出Loading...,引发HTML结构不匹配。

修改为服务端直接输出翻译内容,客户端在ready状态未就绪时保持与服务端一致的内容(而非替换成Loading):

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

export default function YourComponent() {
  const [clientReady, setClientReady] = useState(false);
  const { t, ready } = useTranslation('common');

  useEffect(() => {
    if (ready) {
      setClientReady(true);
    }
  }, [ready]);

  // 服务端直接返回翻译内容,避免Hydration不匹配
  if (typeof window === 'undefined') {
    return <div>{t('your_translation_key')}</div>;
  }

  // 客户端未就绪时,仍渲染服务端一致的翻译占位(不要用Loading)
  if (!clientReady) {
    return <div>{t('your_translation_key')}</div>;
  }

  return <div>{t('your_translation_key')}</div>;
}

3. 验证生产环境翻译文件的打包与路径

确保public/locales目录下的翻译文件(如tr/common.json、en/common.json)存在且内容正确,生产环境下next-i18next会将这些文件打包为静态资源,路径错误会导致客户端加载翻译失败,引发不匹配。

4. 检查App Router适配(若使用Next.js 15 App Router)

如果项目使用App Router,需确保服务端组件能正确获取Locale并初始化i18n:

// app/i18n.ts
import { createInstance } from 'i18next';
import { initReactI18next } from 'react-i18next';
import resources from '../locales/resources';

export async function getI18nConfig(locale: string) {
  const i18n = createInstance();
  await i18n.use(initReactI18next).init({
    lng: locale,
    resources,
    react: { useSuspense: false },
  });
  return i18n;
}

在layout组件中传递Locale并初始化i18n实例,确保服务端与客户端的翻译配置完全一致。

5. 临时应急方案:禁用组件SSR(不推荐)

若以上方案均无效,可临时将翻译组件设为纯客户端组件,禁用SSR(会失去SSR优势,仅作应急):

import dynamic from 'next/dynamic';

const TranslatedComponent = dynamic(() => import('./TranslatedComponent'), {
  ssr: false,
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 20:35:18