Files
github-zh-tw/DEVELOPMENT.md

159 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GitHub 中文化 (繁體) UserScript — 開發紀錄
一份給 ScriptCat / Tampermonkey 用的 GitHub 介面繁體中文化腳本,檔案在 `github-zh-tw.user.js`。本文件紀錄從 v0.6 一路迭代到 v0.15 的過程、遇到的坑與解法。
## 設計原則
1. **只翻 GitHub 介面本身,不動使用者內容。** 檔名、commit 訊息、issue 標題、使用者名稱、topic 標籤、repo 描述、README、程式碼一律保留原樣。
2. **不破壞功能。** 搜尋語法(`is:issue state:open`)必須維持英文,否則點擊篩選會失效。
3. **SPA 友善。** GitHub 用 Turbo/pushState切頁不會重載腳本需要自己監聽。
4. **效能優先。** 預編譯 regex、debounce、只處理必要節點。
## 架構概念
三層替換:
```
text
├─ TIME_AGO_REGEX "3 days ago" → "3 天前"
├─ WORD_BOUNDARY_REGEX 詞庫批次替換(長詞優先、大小寫不敏感)
└─ ABBREV_REGEX "62.8k" → "6.3 萬"
```
兩層跳過:
```
shouldSkipTextAncestor(el)
├─ SKIP_TAGS SCRIPT / STYLE / CODE / PRE / INPUT / TEXTAREA ...
├─ isContentEditable / role="textbox"
└─ SKIP_CONTEXT_SELECTOR closest() 快速判斷使用者內容脈絡
```
掃描策略:`TreeWalker` 走所有文字節點 + `querySelectorAll(ATTR_SELECTOR)` 補翻屬性。
## 版本演進
### v0.6(初版)
使用者提供,基本能翻導覽列。用 `setInterval(500ms)` 輪詢 + MutationObserver flag。
**問題:** 詞庫太少、每個詞跑一次 regex 效能差、沒處理 SPA。
### v0.7
- 擴充詞庫Settings、Pulls、Commits、Branches…
- 使用預編譯的 `WORD_BOUNDARY_REGEX` 一次替換
- 拿掉 setInterval 輪詢,改 MutationObserver + debounce
- Hook `pushState` / `replaceState`、監聽 `turbo:load`
### v0.8
**Bug** `stars` / `watching` / `forks` 小寫沒被翻。
**原因:** regex 只有 `g``i` 旗標。
**修:**`gi`,搭配 `LOWER_MAP` 做大小寫不敏感查表。
**Bug** `Security and quality``安全 and quality`
**原因:** 只有 `Security` 在詞庫,`and quality` 不在。
**修:** 加整句 `Security and quality``安全與品質`。長詞優先排序會先吃掉整句。
### v0.9(數字格式化)
使用者要求「62.8k」改成更好看的格式。
新增 `formatAbbrev`
- `≥ 1 萬``X.X 萬`≥100 萬去掉小數)
- `< 1 萬` → 千分號 `7,800`
- 純數字不動
**額外問題:** `<strong>62.8k</strong>` 沒被掃到。
**原因:** SCAN_SELECTORS 沒包 `<strong>`
**修:** 加入 `strong, b, em, h1-h4, li`
### v0.10
**Bug** 按鈕上的 `7.8k` / `62.8k`(在 `<span class="Counter">` 裡)沒格式化。
**原因:** `Counter` 在 skip 清單。
**修:** 移除 `Counter` skip。純數字本來就不會被誤翻`k/M` 後綴才會處理。
### v0.11(分支頁)
Branches 頁大量詞彙沒翻Default、Active、Stale、All、Updated、Check status、Behind、Ahead 等。
也加了相對時間 regex
```js
TIME_AGO_REGEX = /\b(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago\b/gi
```
**修 `Active 分支清單` 的半翻:**`Branches``分支`(中文無複數差異),加整句 `Active branches``活躍分支`
### v0.12TreeWalker 重構)
**Bug** `<th>` / `<td>` / `<relative-time>` 的文字沒翻,`<input>` 的 placeholder 也沒翻。
**原因:** SCAN_SELECTORS 白名單太窄;`<input>` 整個被 SKIP_TAGS 跳過,連屬性都沒碰。
**大改:**
1. 拿掉 SCAN_SELECTORS改用 `TreeWalker` 走所有文字節點
2. 屬性翻譯獨立於文字節點跳過邏輯 — `<input>` 文字跳過但 placeholder 仍翻
3. `shouldSkipTextAncestor` 改成走 parent chain比單一元素判斷更穩
### v0.13
補空狀態整句:`No branches match the search``沒有分支符合搜尋條件` 等。
**教訓:** 差點加了 `of``/共`,但 `of` 會破壞「Member of X」「out of」等句型移除。同理 `Page``Showing` 也太通用不加。
### v0.14(使用者內容保護)
使用者抱怨檔名、commit 訊息、repo 描述被翻(`授權` / `自述檔.md` / `更新.sh` / `Initial 提交` / `全部 IN ONE Hacking Tool For Hackers`)。
**新增 `SKIP_CONTEXT_SELECTOR`**
- 檔名:`.react-directory-filename-column``a[href*="/blob/"]``a[href*="/tree/"]`
- Commit`a[href*="/commit/"]``[data-testid="latest-commit-details"]`
- Repo 描述:`.BorderGrid-cell > p``.f4.my-3`
- Topics`a.topic-tag`
- README`.markdown-body`
- 程式碼:`.blob-code-inner``.highlight``.react-code-lines`
- Issue / PR 標題:`.markdown-title``.js-issue-title`
`el.closest(SKIP_CONTEXT_SELECTOR)` 一次判斷祖先脈絡。
### v0.15Issues 頁)
多個新問題:
1. `is:issue state:開啟中` — 搜尋語法被翻,**破壞功能**
2. `karanraza608-星標` — 使用者名稱被翻
3. 下拉選單沒翻Sort by / Newest / Oldest…
4. `read the 貢獻 guidelines` — 半翻
5. Dismiss / Want to contribute 沒翻
**新增跳過脈絡:**
- 使用者:`a[data-hovercard-type="user"|"organization"]``a[data-hovercard-url*="/users/"]`
- 搜尋:`[role="searchbox"]``[role="combobox"]`、語法 token `.pl-c1`
- Labels`.IssueLabel``.Label`
**新增詞庫:** `Sort by` / `Order` / `Newest` / `Oldest` / `Created on` / `Last updated` / `Total comments` / `Best match` / `Reactions` / `Recently updated` / `Dismiss` / `Want to contribute to` / 整句 `If you have a bug or an idea, read the contributing guidelines before opening an issue`
## 關鍵技術點
### 大小寫不敏感 + 保留原大小寫?
做不到。因為 `Open` (tab) 和 `opened` (issue meta 動詞) 經過 `gi` + LOWER_MAP 會用同一個翻譯。只能二選一。目前選「保留 tab 翻譯」,動詞保留英文。
### 長詞優先
```js
const sorted = [...TRANSLATION_MAP.keys()]
.sort((a, b) => b.length - a.length)
```
搭配 regex 的回溯backtracking長詞失敗時會嘗試短詞。讓「Active branches」整句優先於「Branches」單字。
### 屬性裡的 `...` 結尾
`Search branches...` 放進詞庫但 `\b...\b` 的尾端 `\b` 不會成立(`.` 是非字元 + 後方結尾也非字元)。解法是詞庫只放 `Search branches`regex 會在 `\b` 前停下,保留後面的 `...`
### React 元件的 key 變動
GitHub 的 React class 常含 hash`SearchInput-module__searchInput_f5Xpk`)。不靠這些,改靠穩定的 `role``data-testid``data-hovercard-*``[href*="/blob/"]`
## 目前已知限制
- **大小寫衝突**:同詞不同語境無法分別翻譯。
- **使用者自定 label / project 名稱**:會看內容決定,但已用 `.IssueLabel` / `.Label` 跳過彩色 label。
- **Issue 標題**:刻意保留英文(屬使用者內容)。
- **新 UI 改版**:如果 GitHub 改變 class / data-testid跳過規則可能失效。
## 檔案
- `github-zh-tw.user.js` — 腳本本體
- `DEVELOPMENT.md` — 本文件
## 安裝
在 ScriptCat / Tampermonkey「新增腳本」貼上 `github-zh-tw.user.js` 全文。或用「從本地檔案匯入」。