Remix i18n子组件用翻译触发Hydration不匹配错误求助
Remix + remix-i18next 子组件加载翻译导致 Hydration 失败问题
我在Remix应用中使用remix-i18next包实现国际化翻译。仅父组件加载特定命名空间的翻译时一切正常,但当子组件也加载指定JSON文件的翻译时,出现**「Hydration failed because the initial UI does not match what was rendered on the server」**错误,移除子组件翻译逻辑后错误消失。
父组件代码
import { Card } from "@shopify/polaris"; import { Spacer } from "../components/globalComponents" import HaveQuestionsCard from "../components/HaveQuestionsCard"; // i18n imports and configurations import { useTranslation } from "react-i18next"; export let handle = { i18n: "testHome" }; // 加载"testHome"命名空间的翻译 export default function TestHome() { let { t } = useTranslation("testHome"); return ( <> <Spacer height={"10rem"} /> <Card> <h1> {t("title")} </h1> </Card> <Spacer height={"2rem"} /> <HaveQuestionsCard /> </> ) }
子组件代码
import { Card, Text, InlineStack, Link } from "@shopify/polaris"; import { Spacer } from "./globalComponents"; import SupportImg from "../media/bundle/support.svg"; // i18n imports and configurations import { useTranslation } from "react-i18next"; export let handle = { i18n: "haveQuestionsCard" }; // 加载"haveQuestionsCard"命名空间的翻译 export default function HaveQuestionsCard() { // 获取翻译函数 let { t } = useTranslation("haveQuestionsCard"); return ( <Card> <InlineStack gap={"200"}> <Text as="h2" variant="headingMd"> {t("title")} </Text> <img alt="" width="8%" height="8%" style={{ objectFit: "cover", objectPosition: "center", }} src={SupportImg} /> </InlineStack> <Spacer /> <Text as="p" variant="bodyMd"> {t("details")} </Text> {/* <Spacer /> */} <Link monochrome url="#"> <Text as="h2" variant="bodyMd" fontWeight="medium" tone="subdued"> {t("link")} </Text> </Link> </Card> ); }
错误截图

解决方案
remix-i18next中,handle.i18n配置仅在路由组件中生效,子组件(非路由组件)不能通过导出handle加载命名空间——这会导致服务端渲染时子组件的翻译未被预加载,客户端hydration阶段才加载内容,最终出现服务端与客户端UI不匹配的问题。
正确处理步骤:
- 在父路由组件中预加载所有需要的命名空间
修改父组件的handle.i18n,将子组件依赖的命名空间也包含进来:export let handle = { i18n: ["testHome", "haveQuestionsCard"] }; - 移除子组件中的
handle导出
删除子组件代码中的export let handle = { i18n: "haveQuestionsCard" };,保留useTranslation("haveQuestionsCard")即可正常使用翻译函数。
原理:remix-i18next会在服务端渲染路由组件时,根据handle.i18n配置预加载所有指定的命名空间翻译内容,确保服务端和客户端渲染的UI完全一致,从根源上避免hydration不匹配错误。
若需要异步加载翻译,也可以结合React的Suspense组件和useTranslation的suspense选项,但预加载命名空间是更贴合Remix服务端渲染模型的最优方案。
内容的提问来源于stack exchange,提问作者Wakil Ahmed
相关产品推荐
相关产品推荐

