` 裡)、`Search branches...`(placeholder)全都沒翻。
檢視原因 — 這些文字在 `| `、` | `、``、`` 等標籤裡,而我的 `SCAN_SELECTORS` 是寫死的白名單:`span, a, button, summary, strong, b, em, h1-h4, li`。
每次 GitHub 改用新標籤我就要補 — 這條路走不下去。
**大改**:
- 拿掉 SCAN_SELECTORS,改 `TreeWalker(NodeFilter.SHOW_TEXT)` 掃所有文字節點
- `shouldSkipTextAncestor` 走 parent chain,祖先命中 SKIP_TAGS 就跳
- 把屬性翻譯從文字節點跳過邏輯解耦 — `` 文字不翻,但 `placeholder` 翻
這次改動是全文重構最大的一次。之後再也沒為了「某個標籤翻不到」而補白名單。
## v0.13:`of` 的誘惑
補 Branches 空狀態(`No branches match the search`)整句翻譯。
差點加 `of` → `/共`,寫到一半停下來想:「Member of organization」「one of many」「out of date」這些都會爆。
刪掉。`Showing` / `Page` 也一樣,太通用的詞只會製造誤傷。
> 原則:只有在能保證不誤傷的情況下才加單字;有歧義的留給整句處理。
## v0.14:使用者內容入侵
使用者翻進 repo 主頁,傻眼:
```
授權 ← LICENSE
自述檔.md ← README.md
更新.sh ← update.sh
Initial 提交 ← Initial commit
全部 IN ONE Hacking Tool For Hackers ← All IN ONE...
```
檔名、commit 訊息、repo 描述**都是使用者自己產生的內容**,一個字都不該動。
但這些內容在 DOM 上沒有 `` 包起來(那是我 skip 的 tag),跟 UI 的 `` 長得一樣。
新增一條 `SKIP_CONTEXT_SELECTOR`,用 `el.closest()` 判斷祖先脈絡:
- `.react-directory-filename-column`、`a[href*="/blob/"]`、`a[href*="/tree/"]` — 檔名
- `a[href*="/commit/"]`、`[data-testid="latest-commit-details"]` — commit 訊息
- `.BorderGrid-cell > p`、`.f4.my-3`、`[itemprop="about"]` — repo 描述
- `a.topic-tag` — topic 標籤
- `.markdown-body` — 渲染後的 README
- `.blob-code-inner`、`.highlight`、`.react-code-lines` — 程式碼檢視
- `.markdown-title`、`.js-issue-title` — Issue / PR 標題
這是整份腳本**最重要的一次設計決策**:從「列出要翻什麼」轉向「列出不要翻什麼」。
GitHub UI 裡能翻的文字變動慢,使用者內容的容器類型變動也慢,反而中間那層 React 組件 class 變動最快 — 避開最穩的兩端。
## v0.15:Issues 頁的三重災難
/issues 頁一次暴露三類問題:
**1. 搜尋語法被翻,破壞功能**
`is:issue state:開啟中` — `Open` tab 的翻譯污染了 `state:open` 這個過濾器語法。按下搜尋直接拋錯。
加 `[role="searchbox"]`、`[role="combobox"]`、`.pl-c1`(syntax highlight token class)等到 skip context。
**2. 使用者名稱被翻**
`karanraza608-星標` — 使用者 username 本來是 `karanraza608-stars`,結尾 `stars` 被詞庫吃掉。
加 `a[data-hovercard-type="user"]`、`a[data-hovercard-url*="/users/"]`。
**這個 selector 的選擇很關鍵** — GitHub 對任何會顯示使用者浮動卡的連結都會放 `data-hovercard-*`,穩定度高。
**3. 下拉選單半翻**
`排序 by` / `Last 更新時間` — 又是經典半翻。
`Sort by`、`Last updated` 整句丟進去。
另外在考慮要不要加 `opened` / `closed` 這些動詞(`#654 opened 2 days ago`)時踩到一個限制 — `Closed` 是 tab 名稱翻成「已關閉」,而 `closed` 當動詞應該是「關閉於」。由於我的 regex 大小寫不敏感,同字只能有一種翻譯。只好不翻動詞。
## 累積下來的幾個心得
1. **白名單會吃屎**。規則導向的東西用黑名單(skip)比白名單(scan)更好維護。
2. **使用者內容 vs. UI 的邊界靠語意屬性**。`role` / `data-testid` / `data-hovercard-*` / `href` pattern 比 class 穩。
3. **regex 的 `\b` 碰到標點會失敗**。詞庫別放結尾帶 `...`、`?` 的 key。
4. **半翻用整句修**。別妄想加個連接詞解決 — 直接加整句,讓長詞優先吃掉。
5. **大小寫不敏感有代價**。同字不同語境只能二選一,選使用頻率高的那個。
6. **一次只解一類問題**。每次使用者丟截圖就只修該截圖上的問題,不提前設計沒確認的需求。
## 接下來可能的方向
- Dark / light 主題感知的時間格式(目前沒差別)
- 讓使用者在擴充設定介面覆寫詞庫,不用改腳本原始碼
- 把 `TRANSLATION_MAP` 拆成獨立 JSON,腳本動態載入
- GitHub Enterprise 的 `@match` 範本
但這些不急。現版已經在實際瀏覽可接受。
|