前端多语言

目录导航

Locale 来源

后端 config.locale 仍是全栈 locale 基础。frontend.i18n 负责前端页面文案和 hydration 行为。

服务端应该从这些来源决定请求 locale:

  • URL prefix
  • cookie
  • 用户偏好
  • Accept-Language
  • route 显式逻辑

然后 res.render() 把确定后的 locale 和 messages 写入 SSR document。

前端 Locale 文件

页面文案放在 src/frontend/locales/**

// src/frontend/locales/en-US.ts
export default {
  dashboard: {
    title: "Dashboard",
    welcome: "Welcome back",
  },
};
// src/frontend/locales/zh-CN.ts
export default {
  dashboard: {
    title: "仪表盘",
    welcome: "欢迎回来",
  },
};

所有 locale 文件应保持相同对象结构。缺 key 应视为内容错误。

组件中使用文案

Vext 默认前端 API 是对象访问,而不是 t("a.b.c")

import { useVextI18n } from "vextjs/frontend";

export default function DashboardPage() {
  const i18n = useVextI18n();
  return <h1>{i18n.dashboard.title}</h1>;
}

组件明确知道 locale 时,也可以指定:

const english = useVextI18n("en-US");

SSR 与 Hydration

默认模式是:

frontend: {
  i18n: {
    clientLoad: "current",
  },
}

"current" 表示浏览器 hydration 只加载 SSR 当前 locale,减少首屏 JS。

只有页面需要无刷新切换语言时才使用 "all"

frontend: {
  i18n: {
    clientLoad: "all",
  },
}

切换语言

最简单的切换流程是 reload-based:

  1. 用户选择语言。
  2. 写入 cookie、用户偏好 API、URL prefix 或其他服务端可见位置。
  3. 导航或刷新页面。
  4. SSR 和 hydration 使用同一个 locale。

避免服务端先渲染一种语言,而浏览器 hydration 立刻渲染另一种语言。

缓存与 Vary

如果 HTML 会因语言不同而变化,缓存 key 必须包含语言。

常见策略:

  • 保留 Vary: Accept-Language
  • CDN key 包含 locale
  • 使用 /en/zh 这样的语言路径前缀
  • 反向代理 key 包含语言偏好 cookie

JS/CSS 文件是 content hash 的,除非你故意构建独立 locale bundle,否则不需要语言级缓存 key。