🌐 本文还有其它语言版本:中文English

Hexoアップグレード記:6年の歳月と多言語対応

一、背景と動機

私のブログ(misaka10013.cn)は開設以来ずっと Hexo 4.2.0 + NexT 6.0.0 で、6年間フレームワークに触っていなかった。最近新しい機能を追加したりページを調整しようと、AI に作業を依頼するたびに「バージョンが古すぎる」と言われた——依存関係が時代遅れ、プラグインが非互換、設定構文も変わっている。そろそろ上げるべきだと分かっていながら、ずっと後回しにしていた。

最近、主にいくつか新しいアイデアがある:

1. 多言語対応。 中英日の3言語を追加したい——一つは外国語の練習。自分の書いた記事を言語を切り替えて読み直す。もう一つは SEO の問題。国内外問わず、私のブログ記事は検索されにくく、多言語版は検索エンジンにとってよりフレンドリー。

2. 新しいテーマを試したい。 安知鱼(AnZhiYu)テーマに目をつけた。色が豊かで、角丸カード、グラデーションアニメーションなど、NexT のミニマルな「無関心」スタイルとは正反対。どうせ変えるなら、いっそ最新バージョンまで一気に上げてしまおう。

二、フレームワークアップグレード(Hexo 4→8 + NexT 6→8)

全体方針

AI との初回の打ち合わせとブログの現状確認を経て、実行計画を決めた。master ブランチから next8 ブランチを切り、ブランチ上でアップグレード・テーマ移行・機能移植・多言語開発をすべて行い、テストが全部通ってから master にマージして公開する。その間、本番で動いている旧バージョンには一切影響しない。

分担

  • 私(御坂):方針決定、手順の確認、最終判断
  • AI:具体的な実行、影響評価、落とし穴の報告

アップグレード一覧

項目 旧バージョン 新バージョン
Hexo 4.2.0 8.1.2
NexT 6.0.0(git clone) 8.29.0(npm パッケージ)
Node.js 16.x 22.22.2
デプロイ CNB クラウドビルド 同上(node:18→node:22 に変更)

三、多言語の仕組み

要件のすり合わせ

AI と協働する以上、要件の粒度を合わせる必要がある。まず AI にざっくりした要件から具体的な実装方法を出してもらい、その後ソクラテス式に質問を繰り返して、要件を徐々に固めていった:

  1. 3言語 UI(中英日)——✅ 必須
  2. サイト全体でサイドバーに常駐する言語切り替えボタン——✅ 必須
  3. 各言語サイトのトップページはその言語の記事のみ表示——✅ 必須
  4. 記事ページ:翻訳あり→ジャンプ、翻訳なし→ボタン無効化+記事内の案内表示——✅ 折衷案
  5. 翻訳はユーザーの仕事、AI はフレームワークのみ——✅ 明確化
  6. 日本語サイトは初期は空でも可——✅ 承諾

最終方針:単一ビルド + 薄いスクリプト

最終的には、単一ビルド + scripts/i18n-blog.js 1本で全ロジックを実現した。

  • 解決する問題:デフォルトでは全記事が同じ URL 構造になり、言語バージョンを区別できない。
  • スクリプトのやり方:Hexo が記事のパーマリンクを生成する時に横取りして書き換える。
    • デフォルト言語(例:zh-CN)の記事は元のパスを維持(例:/p/xxx.html)。
    • 翻訳記事(例:en)は強制的に /en/p/xxx.html に書き換える。

効果:同じ記事の異なる言語版が独立した整然とした URL を持ち、SEO と切り替えジャンプに有利。

2. 言語ごとの独立リストページ生成:index / archive / category / tag ジェネレーターのオーバーライド

  • 解決する問題:Hexo のデフォルトジェネレーターは全記事を混ぜてインデックスとアーカイブを生成するため、言語で分けられない。
  • スクリプトのやり方
    • これらのジェネレーターのロジックを書き換える。
    • 言語ごとに、その言語のトップ・アーカイブ・カテゴリ・タグページを生成する。
    • 生成時はその言語の記事のみをフィルタリングする。
    • 該当言語に記事が1件もない場合は、404 を返さずプレースホルダーページを生成する。

効果:

  • 各言語サイトが自分専用のトップページと一覧を持ち、互いに干渉しない。
  • /en/ にアクセスすると少なくともプレースホルダーが表示され、空ページエラーが出ない。ユーザー体験がより丁寧。

3.1 言語切り替え(Select ドロップダウン)と記事内の言語バナーの挿入

  • スクリプトが現在のページに他言語バージョンが存在するかを分析する。

  • 翻訳あり:切り替えオプションがハイライト/クリック可能になり、正しい翻訳 URL を指す。

  • 翻訳なし:切り替えオプションをグレーアウト(disabled)し、title 属性で「この記事には英語版がありません」等を表示する。

  • 記事に他言語バージョンが存在する場合、記事本文の先頭に案内バナーを挿入する。

  • 例:「本文の英語版:English Version」

  • 英語版の場合は「この記事の中国語版:中文原文」と表示する。

効果:ページ上の言語切り替えは実際にコンテンツが存在するかどうかで完全に決定される。存在しないページへのジャンプを防ぎ、インタラクション体験が非常にスマート。

4. 中核実装:i18n_map ジェネレーター

  • 解決する問題:フロントエンド JS が言語ジャンプを高速に行うための辞書が必要。
  • スクリプトのやり方:ビルド時に静的 JS ファイル /js/i18n-map.js を追加生成する。

このファイルにはマッピングテーブルが含まれる。例:

1
2
3
4
5
6
window.I18N_MAP = {
"my-post": {
"zh-CN": "/p/my-post.html",
"en": "/en/p/my-post.html"
}
};

効果:このデータが各記事の一意 ID(abbrlink)と全言語版のルートを結びつける。フロントエンドはこのテーブルを直接読み取って即座に切り替えができ、サーバーへのリクエスト不要で応答が速い。

5. 全体のワークフロー

このスクリプトの指揮の下、Hexo のビルド順序は:

1
2
3
4
5
6
7
graph TD
A[ビルド開始] --> B[Step 1: 翻訳記事のパーマリンク修正]
B --> C[Step 2: 言語ごとのリストページ生成]
C --> D[Step 3: 言語切り替えロジックと翻訳バナーの注入]
B --> E[Step 4: フロントエンド言語マップ i18n-map.js 生成]
D --> F[静的サイト生成完了]
E --> F
段階 技術ポイント 出力物 フロントエンドの成果
ルーティング post_permalink フィルター 記事の言語別 URL URL 構造が明確
リスト生成 4種ジェネレーターをオーバーライド 言語別トップ/アーカイブ/カテゴリ/タグ コンテンツが言語で分離、404なし
ページ装飾 after_render:html 修正済み HTML スマート切り替え + 翻訳バナー
データ層 i18n_map ジェネレーター /js/i18n-map.js フロントエンド用ルート辞書

翻訳ワークフロー(今後は私が実施)

1
2
3
AI が初稿を翻訳 → 私が精査 → source/_posts/en/ に配置
→ front-matter に lang: en + 原文と同じ abbrlink を記載
→ ローカルプレビューで検証 → git push で公開

切り替えボタンのインタラクションロジック

シチュエーション 動作
記事に中国語/英語版がある クリック可能。対応言語版へジャンプ
その言語版がない ボタンをグレーアウト無効化、ホバーで「この記事にはこの言語版がありません」
他言語版がある 記事上部にバナー:「🌐 この記事には他言語版もあります:English」
言語サイトのトップ その言語の記事一覧のみ表示

四、テーマ試乗(安知鱼)

ゼロ汚染の共存プラン

既存の NexT 設定を壊さず、ローカルで2台のサーバーを並行起動。ページの要件を見ながら、旧テーマのカスタム設定を少しずつ移行する:

1
2
ポート 4100 → NexT テーマ(hexo server -p 4100)
ポート 4200 → 安知鱼テーマ(hexo server --config "_config.yml,_config.anzhiyu_test.yml" -p 4200)

_config.anzhiyu_test.yml は1行の設定だけでテーマを切り替えられるようにしてあり、いつでもミニマルスタイルに戻せる:

1
theme: anzhiyu

起動時に Hexo が2つの設定ファイルをマージし、安知鱼が theme フィールドを上書きする。その他の設定(記事、多言語スクリプトなど)はメイン設定を共有する。

安知鱼の設定体系

重要: 安知鱼の設定はすべてブログルートの _config.anzhiyu.yml で変更する。themes/anzhiyu/ 内のファイルには触らない。

機能移行チェックリスト

旧ブログのカスタム小機能の移行——新テーマに残すもの、やめるもの。

機能 安知鱼での状態 備考
Live2D 看板娘 ✅ 残す autoload.js を注入。音楽プレイヤーは左上に移動して干渉を回避
多言語切り替え ✅ 移植 右側フローティングバーに注入。無効化/ジャンプのロジックを踏襲
コピーボタン ❌ 不要 新テーマに内蔵
クラッシュ演出 ❌ 不要 新テーマには別の形がある
読書進捗 ❌ 不要 新テーマに内蔵
コメント/フレンドリンク/メニュー等 手動で少しずつ NexT 設定から1項目ずつ移行

五、現在の設定と操作ガイド

多言語設定の説明

_config.yml の以下のフィールドを変更:

1
2
3
4
5
6
7
# 言語順序:最初がデフォルト言語(中国語)
language: [zh-CN, en, ja]

# 多言語プラグイン設定
i18n_blog:
default_language: zh-CN # デフォルト言語
langs: [en, ja] # 有効化する他の言語

新記事の書き方

中国語記事(デフォルト言語):

ファイルの場所:source/_posts/
例:source/_posts/我的新文章.md

front-matter 例:

1
2
3
4
5
6
7
8
9
---
title: 我的新文章
tags:
- 标签1
- 标签2
categories:
- 技术笔记
date: 2026-08-28 17:20:00
---

lang フィールドは不要。abbrlink はビルド時に自動生成される。

英語翻訳(中国語原文とセットで):

ファイルの場所:source/_posts/en/
例:source/_posts/en/my-new-article.md

front-matter 例:

1
2
3
4
5
6
7
8
9
10
11
---
title: My New Article
tags:
- tag1
- tag2
categories:
- Tech Notes
date: 2026-08-28 17:20:00
lang: en
abbrlink: 12345678 # 中国語版と同じ abbrlink
---

重要: lang: en の記載が必須。abbrlink は中国語版と同一にすること。

日本語記事(現在は空サイト、翻訳ができたら配置):

ファイルの場所:source/_posts/ja/
front-matter に lang: ja + 同じ abbrlink を記載。

ローカルプレビュー方法

NexT テーマ(ポート 4100):

ブログルートで実行:

1
2
cd D:\1\coding\hexo-blog-master
hexo server -p 4100

http://localhost:4100 にアクセス

安知鱼テーマ(ポート 4200):

ブログルートで実行:

1
2
cd D:\1\coding\hexo-blog-master
hexo server --config "_config.yml,_config.anzhiyu_test.yml" -p 4200

http://localhost:4200 にアクセス

注意: _config.anzhiyu.ymlsource/css/ などのファイルを変更した後は、サーバーの再起動が必要。Ctrl+C で停止してから上記コマンドを再実行する。

公開操作

CNB クラウドネイティブビルド。master ブランチに push すると自動デプロイされる。ローカルの hexo g は不要。

1
2
3
4
cd D:\1\coding\hexo-blog-master
git add -A
git commit -m "更新内容"
git push origin master

注意: サンドボックス環境の git push は認証エラーになるため、上記コマンドはローカル端末(cmd/PowerShell)で実行すること。

安知鱼設定移行期間中のプレビュー

現在の本番はまだ NexT テーマ。安知鱼の試乗設定は以下のファイルにあり、master には未コミット:

ファイル 説明
_config.anzhiyu.yml 安知鱼オーバーライド設定(1342行)
_config.anzhiyu_test.yml 試乗スイッチ(1行のみ theme: anzhiyu
source/css/anzhiyu-custom.css 安知鱼専用 CSS
source/js/i18n-switcher.js 言語切り替えボタン JS
themes/anzhiyu/ 安知鱼テーマ本体

メニュー・フレンドリンク・コメントなどの設定移行が完了したら、安知鱼を正式に本番にするか決める。

六、TODO と展望

  • SEO 専項:hreflang alternates、sitemap の多言語エントリ、robots.txt——今「misaka10013」で検索すると主に GitHub が出る。ブログの可視性を高めたい
  • 重点記事の翻訳:重要記事を選び、AI で初稿を翻訳して自分で精査し、英語版を徐々に充実させる
  • 安知鱼の正式公開:設定移行完了後に切り替えるか判断
  • OSS キーのローテーション:deploy セクションの平文キーが git 履歴に残っているため、ローテーションを推奨