PlantUML 多语言支持:CJK 字体、RTL、Unicode 字符、emoji 的全部配置

puml.online

PlantUML 是 JVM / Java 写的,理论上 unicode 全兼容——但实际「中文 / 日文 / 阿拉伯文 / emoji」各自踩不同的坑,这一篇一次性整理。

CJK:中文 / 日文 / 韩文

默认会变「豆腐」

PlantUUM 默认用 Java Logical Font——Linux 上没有 CJK 字体 → 显示成 □□□

1
Alice -> Bob: 你好  # 渲染成 "□□□"

解决方案:指定字体

1
2
3
4
5
@startuml
skinparam defaultFontName "Noto Sans CJK SC"
Alice -> Bob: 你好
Bob --> Alice: 你好
@enduml

支持的常见 CJK 字体:

字体 系统 推荐度
Noto Sans CJK SC Linux/跨平台 ⭐⭐⭐⭐⭐
Noto Sans CJK TC 台湾繁体 ⭐⭐⭐⭐⭐
Source Han Sans SC macOS/Adobe ⭐⭐⭐⭐⭐
Microsoft YaHei Windows ⭐⭐⭐
PingFang SC macOS 中文 ⭐⭐⭐⭐
WenQuanYi Micro Hei Linux 旧版 ⭐⭐
Sarasa Mono SC 等宽场景 ⭐⭐⭐

字体回退(fallback)

如果指定字体没有某种 unicode 字符,应该回退到另一个字体。这在 PlantUML 是有限支持:

1
2
3
@startuml
skinparam defaultFontName "Noto Sans CJK SC, Noto Sans, Arial"
@enduml

但 PlantUML 内部 font-family 传给 Graphviz / PlantUML Skia 渲染引擎——fallback 行为实际依赖底层引擎,不保证 100% 工作。

更稳的方案:保证单字体已经覆盖了所需字符范围。

字体安装:服务端

如果你用 plantuml-server(docker):

1
2
3
# 在 Dockerfile 里装 Noto
FROM plantuml/plantuml-server:latest
RUN apt-get update && apt-get install -y fonts-noto-cjk

或者用官方 plantuml/plantuml-server 镜像,已经内置 Noto CJK。

字体安装:客户端

如果用 TeaVM PlantUML(浏览器跑 plantuml.js),TeaVM 本身只内置了有限字体——CJK 显示成方块。

自托管 TeaVM + 自带字体:

1
2
3
4
5
6
7
<!-- 显式注入字体到文档里 -->
<style>
@font-face {
font-family: 'Noto Sans CJK SC';
src: url('/fonts/NotoSansCJKsc-Regular.woff2') format('woff2');
}
</style>

但 PlantUML 渲染在 Canvas / SVG 里,font-face 并不会自动注入到 Canvas——需要 SVG <text> 节点的 inline font-family + 字体 base64 内嵌

1
2
3
4
5
6
7
// 渲染后处理
async function injectFontIntoSVG(svgText, fontBase64) {
return svgText.replace(
/font-family="[^"]*"/g,
`font-family="Noto Sans CJK SC" data-font="${fontBase64}"`
);
}

注意:浏览器对 SVG <text> 元素的 data-font 自定义字段支持有限最稳方案是改 PlantUML 的字体配置—— TeaVM 自带字体可重新打包。

字体嵌套(woff2 base64)

如果一定要塞进 SVG:

1
2
3
4
5
# 把 Noto Sans CJK SC 切成子集(只包含你需要的字符)
pyftsubset NotoSansCJKsc-Regular.otf \
--output-file=noto-subset.woff2 \
--flavor=woff2 \
--text="你好世界验证码登录"

得到 ~150KB woff2 → base64 嵌入 SVG(SVG 文件会突然增大 100KB)。

Unicode 字符范围

中文标点

1
2
3
4
5
@startuml
Alice -> Bob: 你好(中文括号)
Alice -> Bob: 「书名号」
Alice -> Bob: 引号"双引号"
@enduml

大部分 CJK 字体(Noto / 思源黑体)已覆盖中文标点:

  • 中文括号:()
  • 全角空格: 
  • 中文标点:,。;:!?
  • 引号:「」"" 『』
  • 破折号:——

表情符号 emoji

PlantUML 支持 emoji 但依赖底层渲染引擎:

1
2
3
4
@startuml
Alice -> Bob: :smile:
Bob --> Alice: :tada:
@enduml

注意 :smile: 这种是 PlantUML 自定义的 short code,只在 preprocessor $ 模式下生效

如果想要直接 emoji:

1
2
3
@startuml
Alice -> Bob: 😊
@enduml
字体 emoji 支持 备注
Noto Sans CJK 部分 旧版本 emoji 缺失
Apple Color Emoji macOS 系统字体
Noto Color Emoji Linux/Android 字体
Segoe UI Emoji Windows 系统字体

PlantUML 默认 不保证 emoji 渲染,要看你引用的字体库。

组合字符(combining diacritics)

a + ̃ 这种字素组合(如越南语、阿拉伯语),PlantUML 通常能渲染,但字距可能错

1
2
3
4
5
@startuml
actor "Tô" as T
actor "Über" as U
T --> U
@enduml

RTL 文字(阿拉伯文 / 希伯来文)

PlantUUM 的 layout 算法是 Graphviz 的 dot——自然支持 RTL

1
2
3
4
5
6
7
@startuml
skinparam backgroundColor #fafafa
actor "أحمد" as A
actor "محمد" as M
A -> M: مرحبا
M --> A: أهلاً
@enduml

注意

  • 节点名用 RTL 字符没问题
  • 消息文字也是 RTL 字符 → 自动镜像(layout)
  • 顺序:actor A 在「左」还是「右」要看 bidi 算法

如果你想强制 RTL 渲染布局:

1
2
3
4
5
6
7
@startuml
left to right direction
' 但这个选项只决定 layout 方向,不影响单行的文本方向
actor "用户" as User
actor "نظام" as Sys
User --> Sys
@enduml

PlantUML 限制:单行的 RTL 文本自动 bidi 算法对图标题 / 带 RTL 字符的 layout 经常生成奇怪布局。你可能要手动微调 top to bottom directionleft to right direction

Arab / Hebrew 在 CJK 字体

如果你选了 Noto Sans CJK SC 这个字体,它覆盖阿拉伯文。多字体 fallback

1
2
3
4
@startuml
skinparam defaultFontName "Noto Sans CJK SC, Noto Sans Arabic"
actor "محمد" as M
@enduml

但 PlantUML 实际渲染的字体回落取决于底层引擎——测试验证才能确定哪种字体真正生效。

等宽 / monospace

代码场景需要 monospace:

1
2
3
4
5
6
7
@startuml
skinparam defaultFontName "JetBrains Mono, Noto Sans Mono CJK SC"
note right of Bob
Code:
```python
def hello():
print("你好")

end note
@enduml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

**Noto Sans Mono CJK SC** 同时覆盖 CJK + 等宽。

## 实际渲染验证流程

### 1. 写一行测试 puml

```plantuml
@startuml
skinparam defaultFontName "Noto Sans CJK SC"
Alice -> Bob: 你好世界 (中文测试)
Alice -> Bob: 🎉🚀 emoji 测试
Alice -> Bob: αβγδ 数学希腊字母
Alice -> Bob: Русский язык кириллица
@enduml

2. plantuml CLI 渲染

1
plantuml -tsvg test.puml

打开 SVG 在 Chrome / Safari 看:

  • ✅ 中文显示正常
  • ⚠️ emoji 方块 → 字体缺
  • ✅ 希腊字母显示
  • ⚠️ 西里尔字母方块 → 字体缺

3. 修复 + 重新

1
2
3
@startuml
skinparam defaultFontName "Noto Sans CJK SC, Noto Color Emoji, Noto Sans"
@enduml

4. CI 验证

1
2
3
4
5
6
7
8
9
# 渲染 → 检查 SVG 内的 CJK 字符
plantuml -tsvg ci-test.puml
for ch in 你 好 世 界 🎉; do
if grep -q "$ch" ci-test.svg; then
echo "✅ $ch found"
else
echo "❌ $ch missing"
fi
done

更稳的方式:使用 SVGO 紧凑 SVG,提取 <text> 节点的实际字符内容。

PlantUML 内部的 unicode 处理

文件编码

.puml 文件必须 UTF-8 保存——这是 PlantUML 的硬性要求。Windows 用 ANSI 保存会失败或乱码。

BOM(字节序标记)

避免 —— PlantUML 1.2020+ 的 parser 能吃 BOM 但不保证。建议:

1
2
# 移除 UTF-8 BOM
sed -i '1s/^\xef\xbb\xbf//' file.puml

团队协作中的多语言实战

一个常见的痛

「我看到的是 □□□,同事看到的是中文」

根因:team member 各自本地字体不同。最稳方案

  1. CI 渲染图 → 截图 → 合并到 release
  2. render 结果不含字体(SVG 不内嵌字体文件)
  3. 浏览图的人没装 Noto → 自己看到豆腐

根治:SVG 内嵌 woff2 base64。或者用 PDF 输出(在客户端通常自动 fallback 字体)。

文件组织建议

1
2
3
4
5
6
7
8
9
10
docs/diagrams/
├── system.puml # 英文 source(maintain)
├── system-i18n/
│ ├── system_zh-CN.svg # 中文渲染结果
│ ├── system_en.svg
│ ├── system_ja.svg
│ └── ...
├── fonts/
│ ├── NotoSansCJKsc-Regular.woff2
│ └── README.md # 字体来源许可

每改一行 puml,CI 渲染所有语言的 SVG → 上传到 wiki。

PlantUML 中的 i18n 模板

puml 中不直接支持 i18n 函数,但 !define + $ 可变:

1
2
3
4
5
6
7
8
9
10
@startuml
!$zh = "你好"
!$en = "Hello"

!if %variable("LANG") == "zh"
Alice -> Bob: %zh
!else
Alice -> Bob: %en
!endif
@enduml

实际环境变量需要在调用 plantuml CLI 时注入:

1
plantuml -DLANG=zh -tdefault test.puml

多语言源代码的 git 工作流

把不同语言 source 写在 git 仓库:

1
2
3
4
5
docs/diagrams/
├── en/system.puml
├── zh-CN/system.puml
├── ja/system.puml
└── render.sh
1
2
3
4
5
6
7
#!/bin/bash
for lang in en zh-CN ja; do
for f in docs/diagrams/$lang/*.puml; do
name=$(basename "$f" .puml)
plantuml -tsvg "$f" -o "static/img/diagrams/$lang/"
done
done

CI 跑:bash render.sh → 发布到 wiki。

高级:CJK 等宽 / 非等宽混合

1
2
3
4
5
6
7
8
9
@startuml
skinparam defaultFontName "Inter"
note right of Bob
Mixed:
中文 Chinese + English with **Markdown**
- Item 1
- Item 2
end note
@enduml

字体回退链路:

  • Inter → 拉丁字母漂亮
  • 命中 CJK 字符 → 回退到 Noto Sans CJK SC(如果设置了 fallback)

PlantUML + skinparam 多字体语法:

1
2
3
4
skinparam defaultFontName "Inter"
skinparam sequence {
ParticipantFontName "Inter, Noto Sans CJK SC"
}

实战建议清单

  1. 生产用 Noto Sans CJK SC——开源、字符覆盖全、Linux/Mac/Windows 都好装
  2. CI 服务端装好 CJK 字体——docker 镜像构建时 apt-get install fonts-noto-cjk
  3. TeaVM 客户端就别想了——字体注入太麻烦,改用 plantuml-server
  4. !theme cyborg / !theme dark——避开字体黑名单
  5. CJK 字符占位较宽——Graphviz dot 算法会算 CJK 字符宽度,skinparam nodesep 40 给点空间
  6. skinparam dpi——配合 CSS 让图放大时不糊

落地 puml.online 的具体决策

我们的项目:

  • 大部分图 CJK 注释 → 用 Noto Sans CJK SC
  • TeaVM WASM 编辑器渲染 → fallback 到 plantuml.com(TeaVM 不支持 CJK 字体)
  • CI 渲染 → docker 镜像内置 Noto

不需要扩展 unicode 复杂度。

小结

  • PlantUML unicode 实际分三层:字体可用性、RTL 算法、emoji 兼容
  • CJK 主要坑:字体不存在 —— 默认 JVM 字体是不带 CJK 的
  • Noto Sans CJK SC + 服务端 docker 内置 是 95% 的生产方案
  • TeaVM + 客户端:放弃 CJK,改用 plantuml.com

下一步

  • 标题: PlantUML 多语言支持:CJK 字体、RTL、Unicode 字符、emoji 的全部配置
  • 作者: puml.online
  • 创建于 : 2026-07-30 12:10:00
  • 更新于 : 2026-08-14 21:34:29
  • 链接: https://puml.online/blog/plantuml-multilingual-notes/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。