~/blog/zhtw-mcp-calque-blindspot-sweep

AI Workflow · part 7

[Skill] 我的繁中不夠台 — zhtw-mcp 掃 72 篇文章修了 128 處陸用詞

cat --toc

TL;DR

sysprog21/zhtw-mcp(jserv 老師寫的繁中檢查工具)套到 ai-muninn 全部 72 篇繁中文章。三輪掃完修了 128 處陸用詞 / 42 個檔案 / 兩岸用詞命中數從 207 降到 135。但真正的收穫不是這些數字 — 是發現我寫 並行 / 平行 / 文件 / 檔案 都對,寫數據 / 用戶卻預設滑過去。盲點不是「不知道」,是「不會主動懷疑」

白話版:為什麼一個會中文的人寫不好「台灣中文」?

你打字時,手指其實有一個詞庫。詞庫不是空的 — 是被你看過的東西塞滿的。Bilibili 的科普影片、知乎的技術文、GitHub 上的中文 README,絕大多數是簡體 + 對岸用詞。看多了,即使你寫繁體,「數據」「用戶」「連接」這些還是會自動跑到指尖。

你要寫的是「資料」「使用者」「連線」。寫的瞬間你完全知道該寫哪個。但你沒有特別停下來想 — 因為你覺得「我又不是新手,還要自己檢查?」

結果就是,寫完 72 篇文章後,某個檢查工具跑過去,跟你說:你寫了 36 次「數據」、9 次「用戶」、7 次「連接」。整本詞庫滲透進去了,你完全沒發現。

這是「會但不檢」的問題,不是「不會」。解法不是學新詞,是把自我檢查變成寫作流程的一部分。


起因

幾天前(2026-05-02)寫 DGX Spark 量化深度文,我反覆寫了「並發」「高併發」當技術詞 — 直到 Gemini 2.5 Pro 跳出來提醒才意識到那是大陸用語。台灣寫 concurrency 該用「並行」,而大陸的「並行」反而是 parallel — 同一個詞鏡像衝突最容易踩。

那篇單獨修了。但我懷疑全部 72 篇都有類似問題,沒工具能批次掃。

直到看到 sysprog21/zhtw-mcpjserv 老師寫的(嵌入式 / Linux kernel 圈的台灣老前輩),工具方向不會錯,直接裝來掃。


工具:zhtw-mcp 是什麼

zhtw-mcp 是一個 Rust 寫的繁中檢查工具,落實三個官方標準:

  1. 重訂標點符號手冊 — 全形標點規則
  2. 國字標準字體 — 字形變體(裏→裡、着→著)
  3. 兩岸詞彙正規化 — 來自 OpenCC 的 TWPhrases / TWVariants 資料集 + 自家規則

整套規則 1100+ 詞彙、15 條大小寫規則,全部編成執行檔。可以當命令列跑,也能接 MCP server 給 AI 助理當檢查工具用。

我從原始碼編一份(GitHub releases 還沒發執行檔):

git clone https://github.com/sysprog21/zhtw-mcp ~/Projects/zhtw-mcp
cd ~/Projects/zhtw-mcp
make    # 先用 python 下載 OpenCC 資料 → 編執行檔,~50s

裝好的執行檔在 target/release/zhtw-mcp。命令列用法很直觀:

zhtw-mcp lint file.md                         # 列出問題
zhtw-mcp lint file.md --content-type markdown # 跳過程式碼區塊
zhtw-mcp lint file.md --relaxed               # 鬆綁標點 / 文法
zhtw-mcp lint file.md --fix --dry-run         # 預覽修法

⚠️ 第一個雷:不能直接用 --fix

我第一個直覺是「掃完直接 --fix 全套搞定」。試了一個檔差點災難:

zhtw-mcp 預設會把 YAML 標頭裡的 "..." 改成 「...」:

# 修前(正常)
description: "完整的本地 AI Agent 架構..."

# 修後(YAML 壞掉)
description: 「完整的本地 AI Agent 架構...」

YAML 解析器認不得「」當作字串包裹符,整個文章顯示失敗。72 篇全跑一輪 = 整個站炸掉。

而且 ai-muninn 風格刻意保留半形混排(中英混排 + 半形標點,讀起來更像程式碼註解,不是正規論文),--fix 會強制把所有半形標點改成全形,寫起來變得拘謹,不是我要的調性。


流程設計:用 Python 精準動刀,不要直接 --fix

最後設計成這樣:

  1. 掃描階段:用 zhtw-mcp --format compact --relaxed 抓命中列表
  2. 過濾階段:寫個 Python 只挑 cross_strait(兩岸用詞)規則,其他像標點全跳
  3. 應用階段:Python 自己做替換,跳過 YAML 標頭 + ``` 程式碼區塊 + 行內反引號
def split_sections(text):
    # 切出標頭、程式碼區塊、內文三塊
    ...

def fix_text(text):
    out_lines = []
    for kind, chunk, start in split_sections(text):
        for line in chunk:
            if kind == 'body':
                # 只在內文做兩岸用詞替換
                # 還要避開行內反引號裡的內容
                ...

完整 Python 不貼了(每一輪掃完我都調整詞彙對照表),但邏輯就這三層保護。


三輪結果

第一輪:高頻硬陸用詞(84 處 / 42 檔)

這輪主打「動詞或名詞單詞預設寫成陸版」 — 台灣讀者一眼看到會皺眉的詞:

陸用 → 台用命中數為何踩坑
數據 → 資料36最高頻!幾乎每篇技術文都會寫到 data
用戶 → 使用者9user 直譯
連接 → 連線7network connection 直譯
發送 → 傳送5send 直譯
模板 → 範本5template 直譯
導航 → 導覽4navigation 直譯
只讀 → 唯讀4readonly
設備 → 裝置3device
性能 → 效能2performance
卸載 → 解除安裝2uninstall
溢出 → 溢位2overflow
在線 → 線上2online
擴展 → 擴充2extension(軟體情境)
緩存 → 快取1cache

這 14 個詞應該進我的繁中盲點記憶清單 — 之前只記了「並發 / 複現 / 矽片 / 內存」5 個,這次新發現 14 個高頻盲點

第二輪:邊界詞(36 處)

這輪只動兩個我自己同意的邊界詞:

  • 優化最佳化(30 處)
  • 算法演算法(6 處)

這兩個詞兩岸通用,「優化」「算法」在台灣軟體圈也廣用,沒改也不算錯。但教育部偏好「最佳化」「演算法」,檢查工具也會標起來。所以這輪是「作者判斷」而不是「自動修」 — 想要更貼教育部標準才動。

算法演算法 有個正規表達式陷阱:不能用單純 replace,因為「演算法」本身包含「算法」這段子字串,會變成「演演算法」。要用 negative lookbehind:

pattern = re.compile(r'(?<!演)算法')

剩下沒動的邊界詞:

  • 通過 / 透過 — 兩岸並存
  • 前綴 / 字首 — 技術情境通用
  • 分配 / 配置 — 程式記憶體情境通用
  • 版本號 / 版本號碼 — 科技文「版本號」普及
  • 消息 / 訊息 — 高風險!「好消息」「收到消息」是台灣慣用語(指新聞 / 資訊,不是 message),無腦替換會變「好訊息」、「收到訊息」 — 直接破壞語意。這條我刻意拒絕了

第三輪:同字不同義(8 處)

這輪掃「兩岸字一樣但語意衝突」最危險的那層:

英文概念大陸用台灣用注意
concurrency並發並行大陸的「並行」其實是 parallel,完全不同概念
parallel並行平行同上,語意鏡像衝突
process(作業系統)進程行程 / 程序台灣「進程」是「進步」,不是作業系統的 process
file文件檔案兩岸都用「文件」,但台灣指 document
document文檔文件鏡像衝突
render渲染算繪台灣「渲染」原意是「誇張」(繪畫術語)
traverse遍歷走訪台灣「遍歷」是遍歷理論(Ergodic theory)專用

結果意外乾淨 — 我寫得對的部分:

  • 並行 9 處,全部當「concurrent」用,正確
  • 平行 2 處,正確當「parallel」用
  • 文件 57 處,全部當「document」用(file 我都寫「檔案」)
  • 檔案 115 處,正確當「file」用
  • 行程 4 處,「京都行程」「旅行行程」這種行程義
  • 進程 1 處是誤判(「鑽進程式碼裡」是子字串切錯)

寫錯的只有兩個:

  • 並發 7 處(「並發負載」「理論並發 7.48x」)→ 改成 並行
  • 遍歷 1 處(「遍歷 request.messages」)→ 改成 走訪

渲染 4 處我刻意保留 — 軟體情境下廣用,連 Apple 台灣官方文件都用「渲染」,業界比教育部偏好的「算繪」更普及。


真正的收穫:三層盲點不對稱

修完 128 處後,我看著三輪命中分布想了 5 分鐘:

命中數分布特徵
第一層(高頻陸用詞)84大宗 — 技術名詞單詞直譯
第二層(邊界詞)36中等 — 兩岸並存,作者判斷
第三層(同字不同義)8最少 — 我反而寫得對

最危險的第三層(語意衝突,寫錯讀者會誤解)反而文章最乾淨。最不危險的第一層(讀者看到只是覺得「不夠台」)反而寫錯最多。

為什麼?

寫到「並行」「平行」這種詞時,我的腦會自動觸發「等等,這字兩邊意思不一樣」的警報 — 因為我意識到這是衝突詞。但寫到「數據」「用戶」「連接」時,警報不響 — 我覺得這只是「比較中性的詞」。

所以我的盲點不是「不知道台灣怎麼說」(我寫對了 9 次「並行」、115 次「檔案」、57 次「文件 = document」)。是「碰到陸用詞時預設不會主動懷疑」。對「危險詞」我會自我檢查,對「無感詞」我會直譯滑過去。

這跟「學更多台灣詞」沒關係 — 我已經知道。問題是自我檢查的觸發機制太敏感,只對少數詞響鈴。


解法:把自我檢查變成流程

知道盲點不對稱以後,解法很清楚:不能靠意志力把每個詞都檢查一遍,要靠檢查工具補開警報蓋不住的那些詞

寫文前的自動檢查

我把 zhtw-mcp 接進寫文流程:

# alias in ~/.zshrc
zhtw_check() {
  ~/Projects/zhtw-mcp/target/release/zhtw-mcp lint "$1" \
    --content-type markdown --relaxed --format compact \
    | grep -E ':(W|E):cross_strait:'
}

# 寫完文章 publish 前先跑
zhtw_check content/blog/zh-TW/new-article.mdx

只看 cross_strait,跳過 punctuation / translationese — 跟我的風格習慣對齊。

把命中詞收進記憶清單

把這次發現的 14 個高頻盲點 + 7 個邊界詞 + 2 個同字不同義詞全進我的繁中盲點記憶清單。下次寫文 Claude 開新對話就會載入這張表,寫到陸用詞時主動提醒。

兩層審查疊加

我另外有一條 Codex 雙語審查流程在跑(寫完文章丟給 Codex 做敘事層的繁中校稿)。跟 zhtw-mcp 是不同顆粒度的疊加 — Codex 抓敘事腔(整段讀起來像不像台灣人寫的),zhtw-mcp 抓詞彙層的滲透(單字寫對了沒)。


教戰守則

寫繁中技術文、想避開陸用詞的人,五點實戰建議:

  1. 不要相信自己的「台灣感」 — 我寫文 6 個月,以為繁中寫得很乾淨,結果檢查工具一掃 207 處命中。對自己的母語直覺打折。
  2. zhtw-mcpcargo install 五分鐘搞定。一個執行檔、不用 API key、Apache 2.0 授權。
  3. 不要直接跑 --fix 全文 — 它會把 YAML 標頭裡的 "..." 改成「...」破壞 parser,還會強制所有標點變全形。寫個 Python 自己控制,只動內文的兩岸用詞。
  4. 同字不同義那層反而不是你的問題 — 並行/平行/文件/檔案這種衝突詞,你自己寫的時候會多想一秒。真正的盲點是高頻單詞(數據/用戶/連接/發送/模板...)— 這些詞看起來「中性」,警報不響。
  5. 建立「該主動懷疑」的詞庫 — 檢查工具掃過的命中詞收進記憶清單,下次寫文主動規避,而不是事後修。

不做什麼

  • 不修翻譯腔的 456 條命中(誤判率高,需要逐篇判斷,不適合批次處理)
  • 不改半形標點(ai-muninn 風格選擇 — 半形混排讓中英技術詞讀起來更像程式碼註解)
  • 不改「渲染」這類業界廣用詞(教育部偏好「算繪」但連 Apple 台灣官方文件都用「渲染」,改成教育部形式反而拗口)

P.S. 連這篇文章也被自己抓出 ~50 個命中

寫完文章我順手對自己跑檢查工具,跳出 ~50 個兩岸用詞命中:數據 7 處、用戶 6 處、並發 6 處、遍歷 4 處...

全部是引用,不是作者寫錯。第一輪那張「數據 → 資料(36 處)」表格,檢查工具在「數據」上跳警告;邊界詞那段我寫「『好消息』『收到消息』是台灣慣用語」,檢查工具在「消息」上跳警告;同字不同義那段「『進程』=『進步』」,在「進程」上跳警告。

如果我此時無腦 --fix,這篇講「不要無腦 --fix」的文章會被自己毀掉:

  • 表格「數據 → 資料」會變「資料 → 資料」 — 同字兩邊,讀者完全看不懂在示範什麼
  • 「『好消息』是慣用語」會變「『好訊息』是慣用語」 — 本來在解釋為什麼這慣用語不該改,結果自己改了

這正好是本篇核心論點的收尾 — 檢查工具的結果永遠需要人工檢視,引用情境是詞彙規則最常見的合法誤判。精準動刀的流程之所以勝過全文 --fix,不只是 YAML 標頭的保護,更是因為檢查規則沒有語境理解能力,人類讀者要做最後一道把關

知道了之後,流程多一條:不只看命中數,看每個命中周圍兩行。我的 zhtw-mcp grep 改成 grep -B 1 -A 1,引用情境一眼就分得出來。


相關閱讀

常見問題

zhtw-mcp 是什麼?跟 OpenCC 差在哪?
zhtw-mcp 是 [sysprog21/jserv](https://github.com/sysprog21/zhtw-mcp) 寫的繁中檢查工具,把 1100+ 詞彙規則 + 教育部標準字體 + 兩岸用詞對照表編成 Rust 執行檔。OpenCC 只做字元/詞彙層的簡轉繁,zhtw-mcp 多做語境敏感的「兩岸同字不同義」、翻譯腔偵測、半形/全形標點規則。一句話:OpenCC 把字面變繁體,zhtw-mcp 把寫法變台灣。
為什麼不能直接用 zhtw-mcp 的 --fix?
因為它會把 YAML 標頭裡的 `"..."` 字串改成 `「...」`,直接破壞 YAML 解析,文章顯示失敗。--fix 還會強制改 ai-muninn 風格刻意保留的半形混排。實務上要寫個 Python 自己控制:跳過標頭跟程式碼區塊,只在內文套兩岸用詞規則。
寫繁中最容易踩的陸用詞是哪幾個?
從 ai-muninn 72 篇文章實測,最高頻三組是:**數據(36 處)→ 資料**、**用戶(9)→ 使用者**、**連接(7)→ 連線**。這些都是技術文常用詞,我寫作時預設會直譯英文 data/user/connect 過去,不會主動懷疑。同字不同義那層反而寫得對(並行/平行/文件/檔案)— 因為這些字「看起來像陸用詞」,我反而會多想一秒。
檢查工具報的「翻譯腔」是什麼?要修嗎?
翻譯腔 = AI 寫作痕跡偵測,例如破折號用太多、否定平行句式(『不是 X、是 Y』)、語氣詞密度過高。本次只看兩岸用詞不碰翻譯腔,因為誤判率高、很多是作者風格選擇。要動的話建議逐篇判斷,不適合批次修。