服务端渲染如何正确使用多语言? #13268
|
配置 default: 'zh-CN', 切换语言时控制台会有警告: |
Replies: 1 comment
|
这是一个经典的 SSR 水合不匹配(hydration mismatch) 问题。 原因: 服务端渲染时,服务器不知道用户当前选择的语言是什么,所以始终使用你配置的 解决方案:让服务端也能感知到用户的语言偏好。 方案 1:通过 Cookie 传递语言信息(推荐) 切换语言时,将当前语言写入 Cookie,服务端从请求的 Cookie 中读取语言: 1)切换语言时同步写入 Cookie: import { setLocale } from 'umi';
function changeLanguage(lang: string) {
// 写入 cookie,确保服务端能读到
document.cookie = `umi_locale=${lang}; path=/; max-age=31536000`;
setLocale(lang);
}2)在服务端入口( // app.ts
export const ssr = {
modifyServerRenderData(data: any) {
const { request } = data;
// 从 cookie 中解析语言
const cookieStr = request?.headers?.cookie || '';
const match = cookieStr.match(/umi_locale=([^;]+)/);
const locale = match ? match[1] : 'zh-CN';
return {
...data,
locale,
};
},
};3)在 // app.ts
import { setLocale } from 'umi';
export function render(oldRender: () => void) {
// 客户端:从 cookie 读取语言并设置,确保和服务端一致
const match = document.cookie.match(/umi_locale=([^;]+)/);
if (match) {
setLocale(match[1], false); // false = 不刷新页面
}
oldRender();
}这样服务端和客户端使用同一个 Cookie 值作为语言来源,渲染结果就一致了。 方案 2:基于 URL 区分语言 如果你的项目可以接受 URL 带语言前缀(如 // .umirc.ts
export default {
locale: {
default: 'zh-CN',
baseSeparator: '-',
useLocalStorage: false, // 关闭 localStorage,完全由 URL 控制
},
ssr: {},
};方案 3:临时抑制警告(不推荐,仅应急) 如果短期内无法改架构,可以在切换语言后强制刷新页面,避免水合不匹配: import { setLocale } from 'umi';
function changeLanguage(lang: string) {
setLocale(lang, true); // true = 刷新页面
}这样每次切换语言都是全量刷新,服务端会用新的默认语言重新渲染,不会出现 mismatch。但用户体验差一些。 总结: 核心问题是服务端和客户端的语言来源不一致。推荐方案 1(Cookie 同步),SSR 场景下这也是业界通用做法(Next.js 等框架处理 i18n + SSR 也是类似思路)。 |
这是一个经典的 SSR 水合不匹配(hydration mismatch) 问题。
原因:
服务端渲染时,服务器不知道用户当前选择的语言是什么,所以始终使用你配置的
default: 'zh-CN'来渲染 HTML。而客户端 hydrate 时,Umi 的 locale 插件会从localStorage(或navigator.language)读取到用户之前切换的语言(比如en-US),导致客户端渲染出来的文本和服务端不一致,React 就会抛出这个警告。解决方案:让服务端也能感知到用户的语言偏好。
方案 1:通过 Cookie 传递语言信息(推荐)
切换语言时,将当前语言写入 Cookie,服务端从请求的 Cookie 中读取语言:
1)切换语言时同步写入 Cookie:
2)在服务端入口(
app.ts)中,通过请求头获取 Cookie 并设置初始语言: