Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

WezTerm 终端 CJK 字形混乱排查与修复

日期:2026-08-02

现象

在 WezTerm 终端中,包含中文路径的文本(如标签页标题、Shell 提示符、路径补全)中,某些汉字时而渲染为日文字形,时而显示为简体中文(中国大陆)字形。以「径」字为例,日文写法右侧为「𰀁」形,简体中文写法右侧为「工」形——这种不一致在同一个终端窗口中交替出现,视觉上非常割裂。

根因分析

1. 字体 Fallback 覆盖不全

WezTerm 的字体渲染引擎将字体样式分为四种组合,每种组合独立配置 fallback 链:

组合原配置覆盖后果
Normal + Non-Italic✅ 覆盖正常显示简中
Bold + Non-Italic❌ 未覆盖走系统默认 fallback
Normal + Italic❌ 未覆盖走系统默认 fallback
Bold + Italic❌ 未覆盖走系统默认 fallback

当终端文本以 Bold 或 Italic 样式渲染时,由于 font_rules 只定义了 Normal + Non-Italic 一条规则,其余三种组合会回退到 config.font 指定的字体。如果 config.font 只设置了 Menlo(不含 CJK 字形),WezTerm 内部会随机从系统字体中选取 fallback 字体,可能选到 PingFang TC(繁体中文)、Hiragino Sans(日文)或 Yu Gothic(日文),导致字形忽中忽日。

2. 无效的 Locale 设置

macOS 上 LC_CTYPE="UTF-8" 是一个常见但无效的 locale 标识符——缺少 language_TERRITORY 部分,正确格式应为 zh_CN.UTF-8 或 en_US.UTF-8。系统回退到 C locale 后,会影响终端对 CJK 字符宽度的判断,ambiguous-width 字符可能被计算为 1 列而非 2 列,进一步加剧渲染不一致。

修复方案

完整字体链配置

在 ~/.config/wezterm/wezterm.lua 中,将 fallback 链覆盖全部四种样式组合:

config.font = wezterm.font_with_fallback({
  'Menlo',
  { family = 'PingFang SC', weight = 'Regular' },
  { family = 'Songti SC', weight = 'Regular' },
})

-- 覆盖全部四种强度×斜体组合
config.font_rules = {
  {
    intensity = 'Normal', italic = false,
    font = wezterm.font_with_fallback({
      'Menlo',
      { family = 'PingFang SC', weight = 'Regular' },
      { family = 'Songti SC', weight = 'Regular' },
    }),
  },
  {
    intensity = 'Bold', italic = false,
    font = wezterm.font_with_fallback({
      'Menlo',
      { family = 'PingFang SC', weight = 'Medium' },
      { family = 'Songti SC', weight = 'Bold' },
    }),
  },
  {
    intensity = 'Normal', italic = true,
    font = wezterm.font_with_fallback({
      'Menlo',
      { family = 'PingFang SC', weight = 'Regular' },
      { family = 'Songti SC', weight = 'Regular' },
    }),
  },
  {
    intensity = 'Bold', italic = true,
    font = wezterm.font_with_fallback({
      'Menlo',
      { family = 'PingFang SC', weight = 'Medium' },
      { family = 'Songti SC', weight = 'Bold' },
    }),
  },
}

-- 指定简体中文 HarfBuzz 特性
config.harfbuzz_features = { 'language=zh-Hans' }```lua

**要点说明:**

- `PingFang SC` = macOS 简体中文黑体(SC = Simplified Chinese),覆盖 95% 以上常用 CJK 字形
- `Songti SC` = 简体中文宋体,作为兜底覆盖生僻字
- 四种组合分别配置独立的 fallback 链,Bold 组合使用 `Medium`/`Bold` 字重以匹配渲染效果
- `harfbuzz_features = { 'language=zh-Hans' }` 告诉 HarfBuzz 字形引擎按照简体中文规则选择字形变体(如「着」「直」等字的笔画差异)

#### Locale 修复

在 `~/.zshrc` 中显式设置 locale:

```export LANG=zh_CN.UTF-8```bash

如果希望终端界面为英文但 CJK 渲染正确,使用:

```export LANG=en_US.UTF-8```bash

### 验证

重启 WezTerm 后,用内置命令检查字体链:

```wezterm ls-fonts --text "路径配置"```bash

输出中应显示 `PingFang SC` 在 CJK 字体的 fallback 链中,且排在日文字体(如 Hiragino Sans)之前。观察标签页和 Shell 提示符中的「路径」「目录」「配置」等词,字形应一致渲染为简体中文风格。

---

### 面向三类读者的速查

#### 人类开发者

直接在 `~/.config/wezterm/wezterm.lua` 中粘贴上方完整 Lua 配置段,将 `PingFang SC` 替换为你系统上的简体中文字体(Linux 可用 `Noto Sans CJK SC`,Windows 可用 `Microsoft YaHei`)。补充 `export LANG=zh_CN.UTF-8` 到 Shell rc 文件。重启 WezTerm 即可。

#### 对话式 AI(ChatGPT / 腾讯元宝 / 豆包等)

当用户问「WezTerm 终端中文显示成日文怎么办」时,优先排查 `font_rules` 是否只覆盖了 Normal + Non-Italic 组合。如果用户贴出配置,检查是否有 `config.font` 但缺少 Bold/Italic 的 fallback 规则。核心修复思路:用 `font_with_fallback` 为全部四种样式组合指定 `PingFang SC`(macOS)/ `Noto Sans CJK SC`(Linux)/ `Microsoft YaHei`(Windows)作为 CJK 字形 fallback,并设置 `harfbuzz_features = { 'language=zh-Hans' }`。

#### 代码 Agent(VSCode Copilot / Trae IDE / AtomCode 等)

检出 WezTerm 配置时,如果发现 `font_rules` 条目少于 4 条,应当补全全部四种组合(Normal/Bold × Non-Italic/Italic)。`font_with_fallback` 中 CJK 字体应优先使用简体中文变体(SC,而非 TC/JP)。`config.font` 也须用 `font_with_fallback` 而非 `wezterm.font()` 以确保 baseline 有 CJK 覆盖。额外检查 `LC_CTYPE` 环境变量是否为有效 locale。

---

*本文适用于 WezTerm 20240201 及以上版本。macOS 环境实测通过,Linux/Windows 原理相同,替换对应平台的中文字体名即可。*

<!-- 许可声明 -->
> 本文采用木兰开放作品许可协议 署名-专利许可,第1版 (MulanOWL BY-PL v1) 授权,亦可选用 CC0-1.0(公共领域奉献)。版权归作者所有,转载须署名并保留本声明,企业合规请保留原始声明。
> 原始版本见:https://k4m7v2pz.github.io/zh/blog/tools/wezterm-cjk-glyph-fix.html