PlantUML multi-language notes — CJK fonts, RTL, Unicode, emoji
PlantUML is JVM-based, theoretically Unicode-friendly — but Chinese / Japanese / Arabic / emoji each bite in different ways. This post collects all the pitfalls in one go.
CJK: Chinese / Japanese / Korean
Defaults render as “tofu”
PlantUML defaults to Java Logical Font — Linux has no CJK font → renders as □□□.
1 | Alice -> Bob: 你好 # renders as "□□□" |
Fix: specify a font
1 | @startuml |
Common CJK fonts that work:
| Font | System | Recommendation |
|---|---|---|
| Noto Sans CJK SC | Linux/cross-platform | ⭐⭐⭐⭐⭐ |
| Noto Sans CJK TC | Taiwan-traditional | ⭐⭐⭐⭐⭐ |
| Source Han Sans SC | macOS/Adobe | ⭐⭐⭐⭐⭐ |
| Microsoft YaHei | Windows | ⭐⭐⭐ |
| PingFang SC | macOS Chinese | ⭐⭐⭐⭐ |
| WenQuanYi Micro Hei | Linux legacy | ⭐⭐ |
| Sarasa Mono SC | Monospace | ⭐⭐⭐ |
Font fallback
If a font is missing a Unicode character, it should fallback to another font. In PlantUML, this is limited support:
1 | @startuml |
But PlantUML passes font-family to the underlying Graphviz / Skia renderer — actual fallback behavior depends on the engine; not guaranteed to work 100%.
A more robust approach: ensure one font covers all the character ranges you need.
Font installation: server side
If you use plantuml-server (docker):
1 | # Install Noto in the Dockerfile |
The official plantuml/plantuml-server image already bundles Noto CJK.
Font installation: client side
If you use TeaVM PlantUML (browser runs plantuml.js), TeaVM itself only ships limited fonts — CJK shows as squares.
Self-host TeaVM + ship your own fonts:
1 | <!-- Inject fonts into the page --> |
But PlantUML renders into Canvas / SVG — @font-face doesn’t auto-inject into Canvas. You need either inline font-family on the SVG <text> node + fonts embedded base64:
1 | // Post-process after render |
Note: browsers’ support for SVG <text> element’s data-font custom field is limited. The stable solution is to change PlantUML’s font config — TeaVM-bundled fonts can be re-packaged.
Font inlining (woff2 base64)
If you have to bundle inside SVG:
1 | # Subset Noto Sans CJK SC to only the characters you need |
Yields ~150KB woff2 → base64 into SVG (SVG suddenly grows by 100KB).
Unicode character ranges
CJK punctuation
1 | @startuml |
Most CJK fonts (Noto / 思源黑体) cover CJK punctuation:
- Chinese parentheses:
() - Full-width space:
- Chinese punctuation:
,。;:!? - Quotation marks:
「」""『』 - Em dash:
——
Emojis
PlantUML supports emoji but depends on the underlying render engine:
1 | @startuml |
Note :smile: is a PlantUML custom shortcode, only active in preprocessor $ mode.
For literal emoji:
1 | @startuml |
| Font | Emoji support | Notes |
|---|---|---|
| Noto Sans CJK | Partial | Old versions lack emoji |
| Apple Color Emoji | ✅ | macOS system font |
| Noto Color Emoji | ✅ | Linux/Android font |
| Segoe UI Emoji | ✅ | Windows system font |
PlantUML defaults don’t guarantee emoji rendering — depends on which font library you reference.
Combining diacritics
a + ̃ diacritic combinations (Vietnamese, Arabic) usually render but kerning may be off.
1 | @startuml |
RTL (Arabic / Hebrew)
PlantUML’s layout uses Graphviz dot — naturally supports RTL:
1 | @startuml |
But caveats:
- Node names with RTL are fine.
- Message text with RTL → automatically bidi-mirrored (layout).
- Order: whether
actor Ais “left” or “right” depends on bidi algorithm.
If you want to force an RTL-rendered layout:
1 | @startuml |
PlantUML limit: single-line RTL text with automated bidi frequently produces weird layouts for diagram titles / layout-bearing RTL. You may need to manually tweak top to bottom direction or left to right direction.
Arabic / Hebrew in a CJK font
If you pick Noto Sans CJK SC, it doesn’t cover Arabic. Multi-font fallback:
1 | @startuml |
But actual fallback depends on the underlying engine — test to verify which font takes effect.
Monospace / code
Code scenarios need monospace:
1 | @startuml |
end note
@enduml
1 |
|
2. plantuml CLI render
1 | plantuml -tsvg test.puml |
Open SVG in Chrome / Safari:
- ✅ Chinese renders
- ⚠️ Emoji squares → font missing
- ✅ Greek letters render
- ⚠️ Cyrillic squares → font missing
3. Fix and re-render
1 | @startuml |
4. CI verification
1 | # Render → check for CJK characters in SVG |
A more robust approach: SVGO-compact the SVG, extract <text> node actual character content.
PlantUML’s internal Unicode handling
File encoding
.puml files must be saved as UTF-8 — PlantUML’s hard requirement. Files saved as ANSI on Windows will fail or produce mojibake.
BOM (byte-order mark)
Avoid it — PlantUML 1.2020+ parser accepts BOM but does not guarantee. Recommendation:
1 | # Strip UTF-8 BOM |
Team collaboration: multi-language practice
A common pain
“I see
□□□, my colleague sees Chinese”
Root cause: team members have different local fonts. Most stable approach:
- CI renders diagram → screenshot → bundle in release
- Rendered output doesn’t contain fonts (SVG doesn’t embed font files)
- Viewers without Noto installed → see tofu
Cure: SVG embeds woff2 base64. Or use PDF output (clients often auto-fallback fonts).
File organisation suggestion
1 | docs/diagrams/ |
Every puml edit → CI renders all language SVGs → upload to wiki.
PlantUML’s i18n pattern
puml doesn’t have native i18n functions, but !define + $ variable substitution works:
1 | @startuml |
The environment variable needs to be injected when calling plantuml CLI:
1 | plantuml -DLANG=zh -tdefault test.puml |
Multi-language source code in git
Store per-language source in git:
1 | docs/diagrams/ |
1 |
|
CI runs: bash render.sh → publish to wiki.
Advanced: CJK monospace / proportional mix
1 | @startuml |
Font fallback chain:
- Inter → Latin letters look nice
- Hits CJK characters → fallback to Noto Sans CJK SC (if fallback set)
PlantUML + skinparam multi-font syntax:
1 | skinparam defaultFontName "Inter" |
Practical checklist
- Production use Noto Sans CJK SC — open source, full coverage, easy to install on Linux/Mac/Windows
- CI servers install CJK fonts —
apt-get install fonts-noto-cjkwhen building docker image - Don’t bother with TeaVM client + CJK — font injection is too painful, switch to plantuml-server
!theme cyborg/!theme dark— avoid font blacklists- CJK characters are wide — Graphviz dot accounts for CJK width,
skinparam nodesep 40for breathing room skinparam dpi— pair with CSS so diagrams stay sharp when scaled
Decision for puml.online specifically
Our project:
- Most diagrams have CJK annotations → Noto Sans CJK SC
- TeaVM WASM editor rendering → fallback to plantuml.com (TeaVM lacks CJK)
- CI render → docker image bundles Noto
No need to extend the Unicode complexity.
Recap
- PlantUML’s Unicode story has three layers: font availability, RTL algorithm, emoji compatibility.
- CJK’s main pitfall: font is missing — JVM default font has no CJK.
- Noto Sans CJK SC + server-side docker built-in solves 95% of production cases.
- TeaVM + client: abandon CJK, switch to plantuml.com.
Next
- Title: PlantUML multi-language notes — CJK fonts, RTL, Unicode, emoji
- Author: puml.online
- Created at : 2026-07-30 12:11:00
- Updated at : 2026-08-14 21:34:29
- Link: https://puml.online/blog/plantuml-multilingual-notes-en/
- License: This work is licensed under CC BY-NC-SA 4.0.