我選的 Hexo 主題 FlatPaper 很合眼緣,但它只內建簡體中文和英文。加上我陸續要接留言系統、統計、CC 授權卡片——這些它也都沒有。
於是問題從「怎麼翻譯」變成一個更根本的:改了 vendor 進來的主題之後,日後怎麼升級? 這篇記錄我怎麼做繁中化(包含一個藏在 JS 裡的硬編碼白名單),以及怎麼把八處客製整理成日後升級時不會迷路的形式。
一、先決定:vendor 還是 npm 安裝
Hexo 主題有兩種安裝方式,這個選擇會直接決定後面所有事情:
| 方式 | 主題檔案在哪 | 能不能改 | 升級 |
|---|---|---|---|
| npm 安裝 | node_modules/(不進版控) |
改了會被覆蓋 | npm update 一行 |
vendor(放進 themes/) |
themes/<name>/(進版控) |
隨便改 | 手動合併 |
我用 vendor。理由是我確定要改主題(多語系、留言、統計都得動模板),而 npm 安裝的東西改了等於沒改——下次安裝就沒了。
vendor 有個一定要做的動作:
1 | git clone --depth 1 https://github.com/Homulilly/hexo-theme-flatpaper.git themes/flatpaper |
不刪掉巢狀的 .git,git 會把它當成「內嵌 repo」而只記錄一個指標、不記錄任何檔案內容。你本機看起來一切正常,推上去之後 Cloudflare Pages 建置時抓不到主題檔案,版面整個壞掉——而且錯誤訊息不會告訴你原因。
二、繁體中文化:翻譯只是第一步
語言檔
主題的語言檔在 themes/<name>/languages/,一個語言一個 YAML。FlatPaper 有 zh-CN.yml 和 en.yml,沒有繁體。做法很直觀——複製一份改成 zh-TW.yml,然後逐條翻:
1 | common: |
這裡是重點:不要用簡轉繁工具跑完就交差。 兩岸的技術用語差異比字形大得多:
| 簡中原文 | 機器轉換 | 台灣慣用 |
|---|---|---|
| 代码 | 代碼 | 程式碼 |
| 评论 | 評論 | 留言 |
| 关键词 | 關鍵詞 | 關鍵字 |
| 加载失败 | 加載失敗 | 載入失敗 |
| 刷新 | 刷新 | 重新整理 |
我這份 173 行的語言檔,真正花時間的不是打字,是決定這些詞。
然後在站台設定指定語言:
1 | # _config.yml |
然後就壞了:藏在 JS 裡的硬編碼白名單
設定完重新建置,介面還是簡體中文。語言檔明明在那裡。
翻主題的 scripts/i18n.js:
1 | const SUPPORTED_LANGUAGES = ['zh-CN', 'en']; |
主題把支援語言寫死在程式碼裡。我的 zh-TW 沒有通過 normalizeLanguage,回傳空字串,於是整個 fallback 回預設的 zh-CN——語言檔存在與否根本沒被問過。
修法很簡單,兩行:
1 | const SUPPORTED_LANGUAGES = ['zh-CN', 'zh-TW', 'en']; |
但這行修改的意義比它的長度大得多:它是我第一處「改到主題的程式邏輯、而非只是新增檔案」的地方。新增 zh-TW.yml 在升級時很安全(上游不會有同名檔),改 i18n.js 卻是實打實的分岔——上游改了這支檔案,我就得手動合併。
通用教訓:主題宣稱「支援 i18n」不代表你能自由新增語言。加語言檔之前先 grep 一下 SUPPORTED、LANGUAGES、locale 這類字眼,看看有沒有白名單。
三、其餘客製:優先用「新增」而不是「修改」
繁中化之後,我陸續加了留言、統計、CC 授權。做這些的時候我刻意遵守一個原則:
能新增檔案就不要改既有檔案;非改不可時,把改動壓到最小。
理由很現實:升級主題時,git merge 對「你新增的檔案」毫無意見,但對「你和上游都改過的檔案」就會產生衝突。改動範圍決定未來的痛苦程度。
實際成果——八處客製,其中五處是純新增:
| 檔案 | 性質 | 做什麼 |
|---|---|---|
languages/zh-TW.yml |
➕ 新增 | 繁中語言檔 |
layout/_partial/site-stats.ejs |
➕ 新增 | 不蒜子 + 在線人數 |
layout/_partial/cc-license.ejs |
➕ 新增 | 文章底部授權卡片 |
source/images/cc/*.svg |
➕ 新增 | CC 官方圖示(自架,不依賴外部圖床) |
scripts/i18n.js |
✏️ 修改 | 語言白名單加 zh-TW |
layout/_partial/comments.ejs |
✏️ 修改 | 加一個 giscus 分支 |
layout/layout.ejs |
✏️ 修改 | 一行:掛載 site-stats |
layout/post.ejs |
✏️ 修改 | 兩處:文章閱讀數、授權卡片 |
三個「修改」裡有兩個只是一行掛載——這是刻意的:功能寫在自己的新檔案裡,既有檔案只放一行 partial() 呼叫。這樣上游怎麼改 layout.ejs,我的衝突永遠只有那一行。
沿用主題自己的擴充點
有些客製甚至不用碰主題檔案。FlatPaper 提供了 inject 設定:
1 | # _config.flatpaper.yml |
我的 Mermaid 載入器就是這樣掛的——零主題檔案改動。裝任何東西之前,先翻主題設定檔看有沒有 inject、custom_css、custom_js 這類擴充點,能用就用。
設定與程式碼分離
每個自訂功能都給它一組設定,不要把值寫死在模板裡:
1 | # _config.flatpaper.yml |
好處有兩個:改設定不用碰程式碼(降低出錯機率),以及每個功能都能獨立關掉——enable: false 就消失,排查問題時可以快速二分法。
四、日後怎麼升級
vendor 主題的升級沒有魔法,就是手動合併。但只要前面的紀律有守住,流程是可控的:
1 | # 1. 確認自己改過哪些檔案(vendor 那個 commit 之後的所有變動) |
只要「純新增」的檔案佔多數,實際需要人工判斷的就只有那三、四個修改點。
我另外做的一件事是把客製清單寫進 commit 訊息,例如:
1 | Switch theme to flatpaper with zh-TW support |
半年後的自己不會記得改過什麼,但 git log 會記得。這比任何文件都可靠,因為它跟著程式碼一起走。
小結
改主題這件事真正的成本不在「改」,而在你從此接手了它的一部分維護責任。可以降低這個成本的四個習慣:
- vendor 時記得刪
.git——不然檔案根本不會進版控。 - 能新增就不要修改,非改不可時把改動壓成一行掛載。
- 先找主題自己的擴充點(inject / custom_js),能不碰模板最好。
- 把「我改了什麼」寫進 commit 訊息,不要指望自己記得。
至於繁中化,如果你也在用只有簡中的主題:翻譯是體力活,但先 grep 一下有沒有硬編碼的語言白名單,可以省下我那半小時的困惑。
留言