docs: 新增 README / QUICKSTART / SUMMARY 三份文件
三份文件定位不重疊: - README.md:參考手冊(功能、架構、規則對照表、相容性) - QUICKSTART.md:操作指南(安裝、自訂翻譯、自訂跳過、FAQ) - SUMMARY.md:開發故事線(v0.6→v0.15 順序敘事、設計心得)
This commit is contained in:
163
SUMMARY.md
Normal file
163
SUMMARY.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# 開發故事:從 v0.6 到 v0.15
|
||||
|
||||
這份腳本不是一次寫到位的。初版只翻了十幾個字,每看一頁 GitHub 就發現一個新問題。下面是這條路的順序紀錄。
|
||||
|
||||
## 起點 v0.6:能翻幾個字的樣子
|
||||
|
||||
使用者給的初版就能跑,但:
|
||||
|
||||
- 詞庫只有十幾條,多數頁面還是英文
|
||||
- 用 `setInterval(500ms)` 輪詢檢查 DOM 變動 — 永遠在掃,浪費 CPU
|
||||
- 每個詞建一個獨立 regex,對同一段文字跑 N 次
|
||||
- SPA 切頁常常翻不到(Turbo 不會重新觸發 `DOMContentLoaded`)
|
||||
|
||||
## v0.7:整理地基
|
||||
|
||||
先不加詞,把架構改對:
|
||||
|
||||
- 把所有詞合成一個 `WORD_BOUNDARY_REGEX`,長詞排前面(這個設計之後救了很多次半翻)
|
||||
- 拿掉 `setInterval`,改 `MutationObserver` + `debounce(150ms)`
|
||||
- Hook `history.pushState` / `replaceState`、聽 `turbo:load` — SPA 切頁能補翻
|
||||
|
||||
## v0.8:regex 的第一個坑
|
||||
|
||||
使用者貼了側邊欄的 HTML:`<strong>62.8k</strong> stars`。
|
||||
重載後發現 `stars` / `watching` / `forks` 都沒翻。
|
||||
|
||||
原因一點都不 glamorous — regex 旗標是 `g` 不是 `gi`。詞庫裡寫 `Stars` 大寫,遇到小寫 `stars` 就不配對。
|
||||
改成 `gi` + 建 `LOWER_MAP` 查表做大小寫不敏感匹配。
|
||||
|
||||
同時發現 `Security and quality` 被翻成 `安全 and quality` — 因為只有 `Security` 在詞庫。
|
||||
解法:整句丟進詞庫。配合「長詞優先」的排序,`Security and quality` 會先被吃掉,不會退化到只匹配 `Security`。
|
||||
**這個 pattern 之後反覆用**:看到半翻就加整句。
|
||||
|
||||
## v0.9:把數字弄漂亮
|
||||
|
||||
使用者想把 `62.8k` 改成更好看的樣子。
|
||||
標準做法是 `X 萬`(台灣習慣):
|
||||
|
||||
```
|
||||
62.8k → 6.3 萬
|
||||
7.8k → 7,800 (< 1 萬就千分號)
|
||||
1.2M → 120 萬
|
||||
```
|
||||
|
||||
寫了 `formatAbbrev`,加一條 `ABBREV_REGEX = /\b(\d+(?:\.\d+)?)([kKmM])\b/g`。
|
||||
|
||||
實作發現沒被吃到 — 因為 `62.8k` 包在 `<strong>` 裡,而 `<strong>` 不在 SCAN_SELECTORS 裡。
|
||||
補了 `strong, b, em, h1-h4, li`。**但這是治標**(之後 v0.12 會把整個 SCAN 白名單砍掉)。
|
||||
|
||||
## v0.10:Counter 的抉擇
|
||||
|
||||
按鈕上的 `7.8k` / `62.8k` 還是沒格式化。
|
||||
追到原因:這些數字在 `<span class="Counter">` 裡,而 `Counter` 在我的 skip 清單。
|
||||
當初加進 skip 是怕翻到純數字的計數 badge(例如 `Issues 5`)。
|
||||
|
||||
但仔細想 — regex 只匹配有 k/M 後綴的數字,純 `5` 本來就不會被動。
|
||||
所以 Counter 根本不需要 skip。拿掉。
|
||||
|
||||
> 教訓:skip 規則是雙刃,加之前多想一步「它真的會被誤翻嗎」。
|
||||
|
||||
## v0.11:Branches 頁的一片荒蕪
|
||||
|
||||
使用者貼了 `/branches` 的截圖:Default、Active、Stale、All、Updated、Behind、Ahead 全沒翻,還看到「Active 分支清單」這種慘劇(`Branches` 被翻了但 `Active branches` 沒整句)。
|
||||
|
||||
- 補了一堆詞
|
||||
- 把 `Branches` 的翻譯從 `分支清單` 改成 `分支` — 中文無複數差異,統一成單字更乾淨
|
||||
- 加整句 `Active branches` → `活躍分支`
|
||||
|
||||
然後處理相對時間,寫了 `TIME_AGO_REGEX`:
|
||||
|
||||
```js
|
||||
/\b(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago\b/gi
|
||||
```
|
||||
|
||||
`3 days ago` → `3 天前`。順手加了 `yesterday` / `last month` 等短語。
|
||||
|
||||
## v0.12:白名單策略徹底失敗
|
||||
|
||||
下一張截圖又是 Branches 頁:`Branch`(表頭)、`Updated`、`Check status`、`Pull request`、`last month`(在 `<relative-time>` 裡)、`Search branches...`(placeholder)全都沒翻。
|
||||
|
||||
檢視原因 — 這些文字在 `<th>`、`<td>`、`<relative-time>`、`<input>` 等標籤裡,而我的 `SCAN_SELECTORS` 是寫死的白名單:`span, a, button, summary, strong, b, em, h1-h4, li`。
|
||||
每次 GitHub 改用新標籤我就要補 — 這條路走不下去。
|
||||
|
||||
**大改**:
|
||||
|
||||
- 拿掉 SCAN_SELECTORS,改 `TreeWalker(NodeFilter.SHOW_TEXT)` 掃所有文字節點
|
||||
- `shouldSkipTextAncestor` 走 parent chain,祖先命中 SKIP_TAGS 就跳
|
||||
- 把屬性翻譯從文字節點跳過邏輯解耦 — `<input>` 文字不翻,但 `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 上沒有 `<code>` 包起來(那是我 skip 的 tag),跟 UI 的 `<a>` 長得一樣。
|
||||
新增一條 `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` 範本
|
||||
|
||||
但這些不急。現版已經在實際瀏覽可接受。
|
||||
Reference in New Issue
Block a user