三份文件定位不重疊: - README.md:參考手冊(功能、架構、規則對照表、相容性) - QUICKSTART.md:操作指南(安裝、自訂翻譯、自訂跳過、FAQ) - SUMMARY.md:開發故事線(v0.6→v0.15 順序敘事、設計心得)
138 lines
5.4 KiB
Markdown
138 lines
5.4 KiB
Markdown
# GitHub 中文化 (繁體)
|
||
|
||
一份 ScriptCat / Tampermonkey 用的 UserScript,把 GitHub 介面轉成台灣用語的繁體中文,不動使用者內容(檔名、commit 訊息、Issue 標題、程式碼、README)。
|
||
|
||
> 想快速裝起來用?看 [`QUICKSTART.md`](./QUICKSTART.md)
|
||
> 想看一路怎麼做出來的?看 [`SUMMARY.md`](./SUMMARY.md)
|
||
|
||
## 檔案
|
||
|
||
| 檔案 | 用途 |
|
||
|---|---|
|
||
| `github-zh-tw.user.js` | 腳本本體(貼到 ScriptCat / Tampermonkey) |
|
||
| `README.md` | 參考手冊(本檔)— 功能、架構、規則 |
|
||
| `QUICKSTART.md` | 安裝與自訂操作指南 |
|
||
| `SUMMARY.md` | 開發故事線、設計取捨 |
|
||
|
||
## 功能概覽
|
||
|
||
| 類別 | 例子 |
|
||
|---|---|
|
||
| 導覽列 | `Code` / `Issues` / `Pull requests` / `Actions` / `Security` / `Insights` |
|
||
| 倉庫側欄 | `About` / `Releases` / `Contributors` / `Sponsor this project` |
|
||
| Branches 頁 | `Default` / `Active` / `Stale` / `All` / `Behind` / `Ahead` |
|
||
| Issue / PR 列表 | `Sort by` / `Newest` / `Oldest` / `No results found` |
|
||
| 數字縮寫 | `62.8k` → `6.3 萬`、`1.2M` → `120 萬`、`7,800` 千分號 |
|
||
| 相對時間 | `3 days ago` → `3 天前`、`last month` → `上個月` |
|
||
| 頁尾 / 無障礙 | `Terms` / `Privacy` / `Footer navigation` / `GitHub Homepage` |
|
||
|
||
## 不翻什麼(刻意)
|
||
|
||
| 內容類別 | 選擇器依據 |
|
||
|---|---|
|
||
| 檔名、資料夾名 | `.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`、`[itemprop="about"]` |
|
||
| Topic 標籤 | `a.topic-tag`、`.topic-tag-link` |
|
||
| 使用者 / 組織名 | `a[data-hovercard-type="user"]`、`a[data-hovercard-url*="/users/"]` |
|
||
| README(渲染後) | `.markdown-body` |
|
||
| 程式碼檢視 | `.blob-code-inner`、`.highlight`、`.react-code-lines` |
|
||
| Issue / PR 標題 | `.markdown-title`、`.js-issue-title` |
|
||
| 搜尋語法(`is:issue state:open`) | `[role="searchbox"]`、`[role="combobox"]`、`.pl-c1` 等 |
|
||
| Labels | `.IssueLabel`、`.Label` |
|
||
| 編輯器、程式碼輸入 | `<code>`、`<pre>`、`<input>`、`<textarea>`、`[contenteditable]` |
|
||
|
||
## 核心架構
|
||
|
||
### 替換流程(`replaceText` 三層)
|
||
|
||
```
|
||
text
|
||
├─ 1. TIME_AGO_REGEX "3 days ago" → "3 天前"
|
||
│ /\b(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago\b/gi
|
||
│
|
||
├─ 2. WORD_BOUNDARY_REGEX 詞庫批次替換
|
||
│ 長詞優先、大小寫不敏感
|
||
│
|
||
└─ 3. ABBREV_REGEX "62.8k" → "6.3 萬"
|
||
/\b(\d+(?:\.\d+)?)([kKmM])\b/g
|
||
```
|
||
|
||
### 跳過規則(`shouldSkipTextAncestor`)
|
||
|
||
```
|
||
elements (往祖先走)
|
||
├─ SKIP_TAGS SCRIPT / STYLE / CODE / PRE / INPUT / TEXTAREA / NOSCRIPT
|
||
├─ isContentEditable (所有可編輯區)
|
||
├─ role="textbox"
|
||
└─ closest(SKIP_CONTEXT_SELECTOR)
|
||
└─ 使用者內容脈絡(見上表)
|
||
```
|
||
|
||
**屬性翻譯獨立於文字節點**:
|
||
`<input placeholder="Search branches...">` 的 placeholder 會翻,但輸入內容不動。
|
||
|
||
### 掃描策略
|
||
|
||
| 對象 | 方法 |
|
||
|---|---|
|
||
| 所有文字節點 | `TreeWalker(NodeFilter.SHOW_TEXT)`,不靠白名單 |
|
||
| 屬性 | `querySelectorAll('[data-content], [aria-label], [title], [placeholder]')` |
|
||
|
||
### 動態更新
|
||
|
||
- **`MutationObserver`**:監聽 `childList` + `attributes`,新增節點立即翻、屬性變更立即補。
|
||
- **SPA 路由**:hook `history.pushState` / `replaceState`,監聽 `popstate`、`turbo:load`、`turbo:render`。
|
||
- **150ms debounce**:保險起見切頁/大量 DOM 變動後做一次全域掃描。
|
||
|
||
## 詞庫結構
|
||
|
||
`TRANSLATION_MAP`(`Map`)按分類排列:
|
||
|
||
1. 倉庫導覽(Code / Issues / PR / Actions…)
|
||
2. 關注 / 分支 / 星標(Watch / Fork / Star)
|
||
3. 倉庫側欄(About / Releases / Contributors…)
|
||
4. 檔案列表操作(Go to file / Add file / Clone…)
|
||
5. PR / Issue 按鈕(New issue / Merge / Review changes…)
|
||
6. 列表篩選(Open / Closed / Author / Labels…)
|
||
7. 全站導覽 / 使用者選單
|
||
8. 通用動作(Save / Cancel / Edit…)
|
||
9. 頁尾 / 無障礙
|
||
10. 相對時間短語
|
||
|
||
**長詞優先**:建構 regex 時會依字串長度排序,讓 `Active branches` 優先於 `Branches` 單字匹配。
|
||
|
||
## 翻譯規則的限制
|
||
|
||
### 大小寫不敏感 → 同詞只能一個翻譯
|
||
`Open`(tab)和 `opened`(動詞)經 `gi` + `LOWER_MAP` 查表會得到同一翻譯。本腳本選「保留 tab 翻譯」,動詞的 `opened` 保持英文。
|
||
|
||
### 結尾標點不可作為關鍵詞一部分
|
||
`Search branches...` 的結尾 `\b` 會失敗(`.` 非字元 + 後面也非字元)。詞庫只放 `Search branches`,regex 會在 `\b` 前停下,保留原 `...`。
|
||
|
||
### 使用者內容的邊界判斷
|
||
靠穩定的語意屬性(`role` / `data-testid` / `data-hovercard-*` / `href` pattern),避開 React CSS 模組的 hash class。
|
||
|
||
## 數字格式化規則
|
||
|
||
```
|
||
val ≥ 1,000,000 → "X 萬" (≥100 萬無小數 / 否則 1 位小數)
|
||
1,000,000 > val ≥ 10,000 → "X.X 萬" (1 位小數,.0 去掉)
|
||
10,000 > val → "X,XXX" (千分號)
|
||
val 為純整數(無 k/M 後綴) → 不處理
|
||
```
|
||
|
||
## 相容性
|
||
|
||
| 項目 | 狀態 |
|
||
|---|---|
|
||
| ScriptCat / Tampermonkey / Violentmonkey | ✅ |
|
||
| Chrome / Edge / Firefox / Safari | ✅ |
|
||
| GitHub Turbo / React 新 UI | ✅ |
|
||
| GitHub Classic UI | ✅(維持運作) |
|
||
| GitHub Enterprise | 未測試(`@match` 需調整) |
|
||
|
||
## 授權
|
||
|
||
MIT
|