Compare commits

..

3 Commits

Author SHA1 Message Date
f881124bdf fix: v0.18 — 搜尋語法 state:open 不再被翻(修功能性災難)+ 貢獻 banner 補第一段
搜尋框:新版 React SearchBar 用 <span data-type="filter-expression"> 包住
is:issue state:open,外層 form 只有 role="form" 不是 role="search",
既有 [role="searchbox"] / form[role="search"] 全部抓不到,導致 state:open
被翻成 state:開啟中,點擊會破壞搜尋功能。

新增 skip:
- [data-type="filter-expression"] / [data-type="filter"] / [data-type="filter-value"]
- .styled-input-container

貢獻 banner:整句詞庫條目永遠不匹配(contributing guidelines 在 <a> 裡,
跨不過節點邊界),實際只靠三個片段拼。原本缺前段「If you have a bug or an
idea, read the」對應,所以顯示半翻。補上該片段條目,移除無效的整句條目與
read the contributing guidelines 條目。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:03:11 +08:00
36cd2df55d fix: v0.17 — Copilot/+ 下拉補翻、擋下新版 React UI 的 repo 描述誤翻
v0.16 補翻(整句優先,不單獨加 New / Import 等通用短詞):
- `+` 下拉:New repository / Import repository / New codespace / New gist / New organization
- Copilot 下拉:Ask Copilot / About this page / In a space / Download for
- 搜尋框:Type / to search

v0.17 修 repo 描述誤翻:
- 原 `.BorderGrid-cell > p` 直接子代選擇器因 GitHub 新版多包一層 `<div class="hide-sm hide-md">` 而失效
- 原 `.f4.my-3` 亦因 class 改為 `f4 tmp-my-3` 失效
- 新增 `p.f4` 靠語意鎖定(Primer CSS 的 prose 字級),不依賴會變動的 tmp-* 前綴

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:38:02 +08:00
d23dda03a9 docs: 新增 CLAUDE.md — 給 Claude Code 的架構與不變條件備忘
聚焦三個區塊:
- 開發流程(單檔 UserScript、無 build/test、手動驗證、@version 同步)
- 核心架構(四個關鍵結構、三層替換順序、TreeWalker + MutationObserver + SPA hook)
- 不變條件(整句優先、同詞單譯、搜尋語法 / 使用者內容不可翻、不依賴 React hash class)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:37:54 +08:00
2 changed files with 94 additions and 3 deletions

68
CLAUDE.md Normal file
View File

@@ -0,0 +1,68 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 專案性質
單一檔案 UserScriptScriptCat / Tampermonkey把 GitHub 介面翻成台灣繁體中文。全部邏輯在 `github-zh-tw.user.js`**沒有** package.json、建置腳本、測試套件、lint 設定、相依套件。
## 開發流程
`github-zh-tw.user.js` 後:
1. **驗證只能手動**:在瀏覽器裝 ScriptCat/Tampermonkey把整份檔案貼進「新增腳本」存檔後強制重載 `https://github.com/*` 驗結果。沒有自動化測試可跑。
2. **發版**:改內容時同時修腳本檔開頭 `@version`UserScript header 用這個判斷更新)。`DEVELOPMENT.md` 記錄了每個版本的改動脈絡,重大改動順手補一段。
3. **不要**建立 `package.json` / 加 build 工具 / 加 npm 相依。檔案必須保持能直接貼進 Tampermonkey 就跑。
## 核心架構(動一行詞庫前先讀完)
所有邏輯在 IIFE 內,四個關鍵結構:
1. **`TRANSLATION_MAP`**`Map`)— 英→中詞庫,按語意分類排列。建構時會依字串長度排序成 `WORD_BOUNDARY_REGEX`**長詞優先**匹配。
2. **`LOWER_MAP`** — 小寫鍵的查表。regex 用 `gi` 旗標(大小寫不敏感)匹配後,以小寫查譯文。
3. **`SKIP_CONTEXT_SELECTOR`** — 使用者內容脈絡白名單檔名、commit 訊息、repo 描述、Topics、README、程式碼、Issue/PR 標題、使用者名稱、搜尋框語法…)。`shouldSkipTextAncestor``el.closest(...)` 判斷祖先是否落在這些 selector。
4. **`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`
- SPAMutationObserver`childList` + `attributes`+ hook `pushState`/`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` / `href` pattern
- **誤翻搜尋語法/程式碼** → 加 skip selector動詞庫不能解。
- **半翻**「Active 分支清單」)→ 補整句進詞庫,利用長詞優先規則蓋過去。

View File

@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name GitHub 中文化 (繁體) // @name GitHub 中文化 (繁體)
// @namespace https://github.com/scriptscat/scriptcat // @namespace https://github.com/scriptscat/scriptcat
// @version 0.15 // @version 0.18
// @description 幫 GitHub 導覽列、按鈕、屬性換成繁體中文,支援 SPA 動態更新,不亂翻、不卡頓。 // @description 幫 GitHub 導覽列、按鈕、屬性換成繁體中文,支援 SPA 動態更新,不亂翻、不卡頓。
// @match https://github.com/* // @match https://github.com/*
// @run-at document-idle // @run-at document-idle
@@ -135,6 +135,11 @@
// PR / Issue 常見按鈕 // PR / Issue 常見按鈕
['New issue', '開新問題'], ['New issue', '開新問題'],
['New pull request', '開新拉取請求'], ['New pull request', '開新拉取請求'],
['New repository', '新增倉庫'],
['Import repository', '匯入倉庫'],
['New codespace', '新增 codespace'],
['New gist', '新增 gist'],
['New organization', '新增組織'],
['Compare', '比較'], ['Compare', '比較'],
['Merge', '合併'], ['Merge', '合併'],
['Merge pull request', '合併拉取請求'], ['Merge pull request', '合併拉取請求'],
@@ -177,14 +182,23 @@
['Recently updated', '最近更新'], ['Recently updated', '最近更新'],
['Dismiss', '關閉提示'], ['Dismiss', '關閉提示'],
['Want to contribute to', '想貢獻給'], ['Want to contribute to', '想貢獻給'],
['If you have a bug or an idea, read the contributing guidelines before opening an issue', '若您發現錯誤或有新想法,請先閱讀貢獻指引再開啟問題'], // 此橫幅實際是三段文字節點:前段文字 + <a>contributing guidelines</a> + 後段文字。
['read the contributing guidelines', '請閱讀貢獻指引'], // 整句條目永遠不會匹配(跨不過 <a> 邊界),只靠三個片段湊。
['If you have a bug or an idea, read the', '若您發現錯誤或有新想法,請先閱讀'],
['contributing guidelines', '貢獻指引'], ['contributing guidelines', '貢獻指引'],
['before opening an issue', '再開啟問題'], ['before opening an issue', '再開啟問題'],
['Never', '從未'], ['Never', '從未'],
['Everyone', '所有人'], ['Everyone', '所有人'],
['Anyone', '任何人'], ['Anyone', '任何人'],
// Copilot / 搜尋框
['Ask Copilot', '詢問 Copilot'],
['About this page', '關於此頁'],
['In a space', '在 Space 中'],
['Download for', '下載'],
['Type', '輸入'],
['to search', '搜尋'],
// 全站導覽 / 使用者選單 // 全站導覽 / 使用者選單
['Pull', '拉取'], ['Pull', '拉取'],
['Marketplace', '市集'], ['Marketplace', '市集'],
@@ -278,6 +292,9 @@
'[itemprop="about"]', '[itemprop="about"]',
'.BorderGrid-cell > p', '.BorderGrid-cell > p',
'.f4.my-3', '.f4.my-3',
// 2026 新版 React UI描述 <p class="f4 tmp-my-3"> 包在 .hide-sm.hide-md 裡,原 `> p` 直接子代選擇器失效。
// 用 p.f4 靠語意f4 = 大型段落文字 = prose 描述),對未來 tmp-* 類別變動有抵抗力。
'p.f4',
// Topics 標籤 // Topics 標籤
'a.topic-tag', 'a.topic-tag',
'.topic-tag', '.topic-tag',
@@ -296,6 +313,12 @@
'.subnav-search-context', '.subnav-search-context',
'input[name="q"] ~ *', 'input[name="q"] ~ *',
'.pl-c1', '.pl-s', '.pl-en', '.pl-k', '.pl-v', '.pl-smi', '.pl-s1', '.pl-c1', '.pl-s', '.pl-en', '.pl-k', '.pl-v', '.pl-smi', '.pl-s1',
// 2026 新版 React SearchBarfilter 語法 token 用 data-type 標記is / state / open / issue 等),
// 外層 form 只有 role="form" 不是 role="search",原規則抓不到。
'[data-type="filter-expression"]',
'[data-type="filter"]',
'[data-type="filter-value"]',
'.styled-input-container',
// Labels使用者自定義 label 顏色塊) // Labels使用者自定義 label 顏色塊)
'a.IssueLabel', 'a.IssueLabel',
'.IssueLabel', '.IssueLabel',