聚焦三個區塊: - 開發流程(單檔 UserScript、無 build/test、手動驗證、@version 同步) - 核心架構(四個關鍵結構、三層替換順序、TreeWalker + MutationObserver + SPA hook) - 不變條件(整句優先、同詞單譯、搜尋語法 / 使用者內容不可翻、不依賴 React hash class) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.9 KiB
4.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
專案性質
單一檔案 UserScript(ScriptCat / Tampermonkey),把 GitHub 介面翻成台灣繁體中文。全部邏輯在 github-zh-tw.user.js,沒有 package.json、建置腳本、測試套件、lint 設定、相依套件。
開發流程
改 github-zh-tw.user.js 後:
- 驗證只能手動:在瀏覽器裝 ScriptCat/Tampermonkey,把整份檔案貼進「新增腳本」,存檔後強制重載
https://github.com/*驗結果。沒有自動化測試可跑。 - 發版:改內容時同時修腳本檔開頭
@version(UserScript header 用這個判斷更新)。DEVELOPMENT.md記錄了每個版本的改動脈絡,重大改動順手補一段。 - 不要建立
package.json/ 加 build 工具 / 加 npm 相依。檔案必須保持能直接貼進 Tampermonkey 就跑。
核心架構(動一行詞庫前先讀完)
所有邏輯在 IIFE 內,四個關鍵結構:
TRANSLATION_MAP(Map)— 英→中詞庫,按語意分類排列。建構時會依字串長度排序成WORD_BOUNDARY_REGEX,長詞優先匹配。LOWER_MAP— 小寫鍵的查表。regex 用gi旗標(大小寫不敏感)匹配後,以小寫查譯文。SKIP_CONTEXT_SELECTOR— 使用者內容脈絡白名單(檔名、commit 訊息、repo 描述、Topics、README、程式碼、Issue/PR 標題、使用者名稱、搜尋框語法…)。shouldSkipTextAncestor用el.closest(...)判斷祖先是否落在這些 selector。SKIP_TAGS—SCRIPT/STYLE/CODE/PRE/INPUT/TEXTAREA/NOSCRIPT。文字節點跳過,但屬性仍會翻(<input placeholder>會翻,輸入內容不動)。
替換流程(replaceText 三層,順序不可交換)
TIME_AGO_REGEX "3 days ago" → "3 天前" ← 先跑,避免 days 被當詞庫吃掉
WORD_BOUNDARY_REGEX 詞庫整批替換 ← 長詞優先
ABBREV_REGEX "62.8k" → "6.3 萬" ← 最後,避開 k/M 在詞庫中撞到
掃描策略
- 文字節點:
TreeWalker(SHOW_TEXT)走全部,靠shouldSkipTextAncestor剔除。不用 SCAN 白名單(v0.12 拿掉了,白名單會漏<th>/<td>/<relative-time>等)。 - 屬性:
querySelectorAll(ATTR_SELECTOR)— 翻data-content/aria-label/title/placeholder。 - SPA:MutationObserver(
childList+attributes)+ hookpushState/replaceState+popstate+turbo:load/turbo:render,所有 trigger 都走同一個 150ms debounce 後做全域 re-scan。
修改詞庫的不變條件
這些規則是踩過坑才定的(DEVELOPMENT.md 有血淚史),動之前先確認新需求不會撞到:
- 整句優先於單字。要譯
Active branches就加整句,不要靠Active+branches組合(長詞優先 regex 會整句吃掉,否則會出現「Active 分支」這種半翻)。 - 一個英文詞只能一個翻譯。因為
gi+LOWER_MAP,Open(tab)和opened(動詞)共用同一譯文。取捨原則:保頻率高的那個;另一個保留英文。 - 搜尋語法不可翻。
is:issue state:open這類 token 翻掉會破壞搜尋。靠[role="searchbox"]/[role="combobox"]/.pl-c1等 skip selector 擋下。加新詞時確認不會污染搜尋框。 - 使用者內容不可翻。檔名、commit 訊息、Issue 標題、Repo 描述、Topics、使用者名稱、README、程式碼。遇到誤翻時,加 skip selector 而不是從詞庫拔詞。
- React class 不可靠。GitHub 新 UI 的 class 帶 hash(
SearchInput-module__xxx_f5Xpk)會變。一律用穩定的role/data-testid/data-hovercard-*/[href*="/blob/"]這類語意屬性。 - 詞庫條目不要帶結尾標點。
Search branches...結尾.會讓\b尾界失敗。詞庫只放Search branches,regex 在\b前停下自然保留原...。 - 避免太通用的短詞。
of、Page、Showing這類會打穿「Member of X」「out of」等片語,不要進詞庫。
數字格式化(formatAbbrev)
val ≥ 1,000,000 → "X 萬"(≥100 萬整數;否則 1 位小數)
1,000,000 > val ≥ 10,000 → "X.X 萬"(`.0` 去掉)
val < 10,000 → "X,XXX" 千分號
無 k/M 後綴的純整數 → 不動
回報問題時要怎麼處理
使用者反映「某某沒翻」或「某某誤翻」時,先分類:
- 沒翻 → 加詞庫。先確認在哪個語意分類、是否該加整句以免半翻。
- 誤翻使用者內容(檔名、commit 訊息、使用者名、repo 描述…)→ 加
SKIP_CONTEXT_SELECTOR,別動詞庫。用 DevTools 找穩定的 selector(data-testid/role/hrefpattern)。 - 誤翻搜尋語法/程式碼 → 加 skip selector,動詞庫不能解。
- 半翻(「Active 分支清單」)→ 補整句進詞庫,利用長詞優先規則蓋過去。