架站筆記

Hexo 主題繁中化與客製維護:改了主題之後,你就是它的維護者

2026-08-09 #Hexo#教學#主題客製#i18n#繁體中文

我選的 Hexo 主題 FlatPaper 很合眼緣,但它只內建簡體中文和英文。加上我陸續要接留言系統、統計、CC 授權卡片——這些它也都沒有。

於是問題從「怎麼翻譯」變成一個更根本的:改了 vendor 進來的主題之後,日後怎麼升級? 這篇記錄我怎麼做繁中化(包含一個藏在 JS 裡的硬編碼白名單),以及怎麼把八處客製整理成日後升級時不會迷路的形式。

一、先決定:vendor 還是 npm 安裝

Hexo 主題有兩種安裝方式,這個選擇會直接決定後面所有事情:

方式 主題檔案在哪 能不能改 升級
npm 安裝 node_modules/(不進版控) 改了會被覆蓋 npm update 一行
vendor(放進 themes/ themes/<name>/(進版控) 隨便改 手動合併

我用 vendor。理由是我確定要改主題(多語系、留言、統計都得動模板),而 npm 安裝的東西改了等於沒改——下次安裝就沒了。

vendor 有個一定要做的動作:

1
2
git clone --depth 1 https://github.com/Homulilly/hexo-theme-flatpaper.git themes/flatpaper
rm -rf themes/flatpaper/.git # ← 這行不能省

不刪掉巢狀的 .git,git 會把它當成「內嵌 repo」而只記錄一個指標、不記錄任何檔案內容。你本機看起來一切正常,推上去之後 Cloudflare Pages 建置時抓不到主題檔案,版面整個壞掉——而且錯誤訊息不會告訴你原因。

二、繁體中文化:翻譯只是第一步

語言檔

主題的語言檔在 themes/<name>/languages/,一個語言一個 YAML。FlatPaper 有 zh-CN.ymlen.yml,沒有繁體。做法很直觀——複製一份改成 zh-TW.yml,然後逐條翻:

1
2
3
4
5
6
7
8
9
10
11
12
common:
posts: 文章
categories: 分類 # 简→繁 不只是字形:分类→分類
tags: 標籤
comments: 留言 # 简中「评论」,台灣習慣說「留言」
post:
back_to_top: 回到頂部
related_posts: 相關文章
search:
placeholder: 輸入關鍵字,按 Esc 關閉 # 「关键词」→「關鍵字」
code:
copy: 複製程式碼 # 「代码」→「程式碼」,不是「代碼」

這裡是重點:不要用簡轉繁工具跑完就交差。 兩岸的技術用語差異比字形大得多:

簡中原文 機器轉換 台灣慣用
代码 代碼 程式碼
评论 評論 留言
关键词 關鍵詞 關鍵字
加载失败 加載失敗 載入失敗
刷新 刷新 重新整理

我這份 173 行的語言檔,真正花時間的不是打字,是決定這些詞。

然後在站台設定指定語言:

1
2
# _config.yml
language: zh-TW

然後就壞了:藏在 JS 裡的硬編碼白名單

設定完重新建置,介面還是簡體中文。語言檔明明在那裡。

翻主題的 scripts/i18n.js

1
2
3
4
5
6
7
8
9
10
const SUPPORTED_LANGUAGES = ['zh-CN', 'en'];
const DEFAULT_LANGUAGE = 'zh-CN';

function normalizeLanguage(value) {
const lang = String(value || '').trim();
if (!lang) return '';
if (lang === 'zh-CN' || lang.toLowerCase() === 'zh-cn') return 'zh-CN';
if (lang === 'en') return 'en';
return ''; // ← zh-TW 掉進這裡
}

主題把支援語言寫死在程式碼裡。我的 zh-TW 沒有通過 normalizeLanguage,回傳空字串,於是整個 fallback 回預設的 zh-CN——語言檔存在與否根本沒被問過。

修法很簡單,兩行:

1
2
3
const SUPPORTED_LANGUAGES = ['zh-CN', 'zh-TW', 'en'];
// ...
if (lang === 'zh-TW' || lang.toLowerCase() === 'zh-tw') return 'zh-TW';

但這行修改的意義比它的長度大得多:它是我第一處「改到主題的程式邏輯、而非只是新增檔案」的地方。新增 zh-TW.yml 在升級時很安全(上游不會有同名檔),改 i18n.js 卻是實打實的分岔——上游改了這支檔案,我就得手動合併。

通用教訓:主題宣稱「支援 i18n」不代表你能自由新增語言。加語言檔之前先 grep 一下 SUPPORTEDLANGUAGESlocale 這類字眼,看看有沒有白名單。

三、其餘客製:優先用「新增」而不是「修改」

繁中化之後,我陸續加了留言、統計、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
2
3
4
# _config.flatpaper.yml
inject:
bottom:
- <script type="module" src="/js/mermaid-init.js?v=3"></script>

我的 Mermaid 載入器就是這樣掛的——零主題檔案改動。裝任何東西之前,先翻主題設定檔看有沒有 injectcustom_csscustom_js 這類擴充點,能用就用。

設定與程式碼分離

每個自訂功能都給它一組設定,不要把值寫死在模板裡:

1
2
3
4
5
6
7
8
9
10
11
# _config.flatpaper.yml
site_stats:
enable: true
busuanzi: true
online_api: 'https://xxx.workers.dev'

license:
enable: true
name: 'CC BY-NC 4.0'
url: 'https://creativecommons.org/licenses/by-nc/4.0/deed.zh-hant'
contact_email: [email protected]

好處有兩個:改設定不用碰程式碼(降低出錯機率),以及每個功能都能獨立關掉——enable: false 就消失,排查問題時可以快速二分法。

四、日後怎麼升級

vendor 主題的升級沒有魔法,就是手動合併。但只要前面的紀律有守住,流程是可控的:

1
2
3
4
5
6
7
8
# 1. 確認自己改過哪些檔案(vendor 那個 commit 之後的所有變動)
git diff --name-only <vendor提交> HEAD -- themes/flatpaper

# 2. 把新版拉到暫存區
git clone --depth 1 <主題repo> /tmp/theme-new && rm -rf /tmp/theme-new/.git

# 3. 對照上游有沒有動到你改過的那幾支
diff -r themes/flatpaper /tmp/theme-new | grep -E "i18n.js|comments.ejs|layout.ejs|post.ejs"

只要「純新增」的檔案佔多數,實際需要人工判斷的就只有那三、四個修改點。

我另外做的一件事是把客製清單寫進 commit 訊息,例如:

1
2
3
4
Switch theme to flatpaper with zh-TW support

Vendor hexo-theme-flatpaper, add zh-TW language file and patch its
hardcoded language whitelist, add categories/tags/404 pages.

半年後的自己不會記得改過什麼,但 git log 會記得。這比任何文件都可靠,因為它跟著程式碼一起走。

小結

改主題這件事真正的成本不在「改」,而在你從此接手了它的一部分維護責任。可以降低這個成本的四個習慣:

  1. vendor 時記得刪 .git——不然檔案根本不會進版控。
  2. 能新增就不要修改,非改不可時把改動壓成一行掛載。
  3. 先找主題自己的擴充點(inject / custom_js),能不碰模板最好。
  4. 把「我改了什麼」寫進 commit 訊息,不要指望自己記得。

至於繁中化,如果你也在用只有簡中的主題:翻譯是體力活,但先 grep 一下有沒有硬編碼的語言白名單,可以省下我那半小時的困惑。

Creative Commons 姓名標示 非商業性

本文採用 CC BY-NC 4.0 授權

歡迎轉載與引用,請標明出處(Hexo 主題繁中化與客製維護:改了主題之後,你就是它的維護者 — mur mur);禁止用於商業用途。

商業使用或合作提案,歡迎來信洽談:[email protected]

留言
分享

留言