[🛠] 多言語ブログのCodex Goalが13時間を超えた理由
✨ GPT-5.5の要約
hyuk.blogを/en/英語版から8つのlocale運用基準まで広げるCodex Goalを進めながら、翻訳品質、言語切り替え、閲覧数共有、pルール、使用量コストまで見直した記録。
最初は /en/ を選ぶだけだと思っていた
最初の問いは単純だった。
en.hyuk.blog がよいのか?
/en/ がよいのか?
SEO、GitHub Pagesの運用、原文と翻訳のつなぎ方、閲覧数共有、今後拡張する言語構造まで合わせて考えた結果、結論は /en/ だった。
このブログは英語版を完全に別プロダクトとして運営するものではない。韓国語の原文を基準に翻訳を付ける構造だ。ならば同じドメインの中で言語URLを分け、hreflangでつなぐ方が単純だった。
しかし、それで終わりではなかった。
/en/ を選んだ瞬間、ホーム、About、カテゴリ、検索、sitemap、language switcher、閲覧数、翻訳品質、これから記事をpushする方法まで一緒に動き始めた。
翻訳ファイルではなく collection の境界だった
英語記事を _posts の中に混ぜてはいけなかった。
Jekyllでは _posts が site.posts に入る。そこへ英語記事を混ぜると、韓国語ホーム、feed、pagination、related postsが英語記事まで静かに取り込む。記事が一つ増えただけに見えて、実際にはブログ全体の索引が汚れる。
だから翻訳記事はlocale別collectionに分けた。
_posts/... -> /daily-review/.../
_en_posts/... -> /en/daily-review/.../
_ja_posts/... -> /ja/daily-review/.../
_zh_hans_posts/... -> /zh-Hans/daily-review/.../
最初の教訓ははっきりしていた。
多言語ブログは翻訳ファイルを追加する作業ではない。collectionの境界を引く作業だ。
当時のGoalアーカイブ
作業は2026年6月7日に始まり、2026年6月8日まで続いた。
最初は英語版を付けるだけに見えた。しかしGoalはすぐにこう広がった。
hyuk.blogをkoを基準localeとし、en、ja、zh-Hans、es、pt-BR、fr、idを拡張localeとする運用可能な多言語ブログにする。
翻訳だけで終わらせず、UI、routing、SEO、sitemap、search、language switcher、閲覧数共有、today dedupeまで揃える。
Tadak Bibleの広報、ポートフォリオ価値、キリスト教人口、拡張性を考えて言語を選ぶ。
有料翻訳APIは使わない。
翻訳は最新GPT worker/subagent基準で進める。
低品質なローカル翻訳結果は信用しない。
韓国語原文が確定する前に翻訳しない。
記事を修正してpするときはactive locale翻訳も揃える。
buildは翻訳batchごとに回さず、最後に必要な範囲で確認する。
Goalそのものが間違っていたわけではない。
問題は、それが実行基準まで小さくならなかったことだ。状態報告、検査項目、翻訳範囲がどんどんくっつき、Goalが大きくなりすぎた。
翻訳品質で大きく痛い目を見た
最初に信頼が壊れたのは翻訳だった。
最初は多くの記事をまとめて翻訳すればよいと思っていた。しかしサンプルの中に、プロンプト指示がそのまま混ざったファイルが出てきた。
Return only the translated content. Do not add notes or fences.
これは数文が不自然という問題ではなかった。生成経路を信用できないという意味だった。
そこで、低品質翻訳をレビューして救うべきか、再生成すべきかをサンプルで見直した。結論は再生成だった。OllamaやArgosのようなローカル翻訳結果は、公開記事の基準では信頼しにくかった。速く出ることより、どのモデルで作られ、どの基準を通ったかの方が重要だった。
残った基準は明確だ。
翻訳は完了率より信頼経路が先。
原文が確定する前に翻訳しない。
公開記事の翻訳を低品質ローカルMTで埋めない。
言語切り替えと閲覧数も一緒に揺れた
英語ページは直接URLでは開けた。
しかしユーザーは韓国語/英語の切り替えを見つけられなかった。
最初は English / Korean を通常メニューに入れた。HTMLには存在したが、ユーザーには見えなかった。モバイルではさらに悪かった。そこで、言語切り替えはメニュー項目ではなくglobal controlだという基準ができた。
閲覧数も言うほど単純ではなかった。
英語記事は別記事ではない。同じ記事の翻訳だ。/daily-review/x/ と /en/daily-review/x/ が別の閲覧数keyを使ってはいけない。だからHTMLの data-page-view-path、クライアントJS、Cloudflare Workerのすべてが、locale prefixを取り除いたcanonical path基準で閲覧数を数えるようにした。
ここでも作業は大きくなった。Workerコードだけ直せば終わりではなかった。Wrangler CLIでデプロイする必要があり、dry-runではD1 DB bindingが抜ける可能性も見えた。そこで wrangler.toml にWorker entrypointとD1 bindingをrepo設定として固定し、bindingが入っていることを確認してからデプロイした。
特にtoday dedupeが重要だった。
同じ記事を韓国語で読み、英語へ切り替えたからといってtodayが二回増えてはいけない。canonical pageが同じならdedupe keyも同じでなければならない。
Codex Goalの達成まで13時間を超えた理由
この作業そのものの純粋な開発時間だけが13時間だったという意味ではない。
問題は、CodexにかけたGoalが完了状態に到達するまで13時間を超えたことだった。
単に作業量が多かったからだけではない。判断が揺れた部分があった。
全体翻訳と検収を同時につかんだ。「全部生成してから検収する」のか、「進めながら検収する」のかで基準が揺れた。workerモデルを確認しないまま翻訳品質を信じようとし、悪い翻訳が出てから作り直した。
原文確定前に翻訳しようとしたのも問題だった。
公開する韓国語記事が変わり続けるなら、先に作った翻訳は当然ずれる。結局、原文を書き直し、既存翻訳を捨て、また翻訳することになった。
buildの判断も揺れた。
翻訳batchごとにbuildを回すと作業は終わらない。buildは重要な検査だが、毎回繰り返す儀式ではない。原文と翻訳範囲を確定し、終盤で必要な範囲を確認すべきだ。
pの意味も遅れて明確になった。
今は、post変更があるときのpは単なるcommit/pushではない。確定した原文に対してactive locale翻訳を揃え、その後でpushする流れだ。
使用量もコストだった
今回の翻訳作業は、有料APIを避ければ終わる問題ではなかった。
前日に決済したばかりのPro x20の週間使用枠は、二日で100%から50%まで減った。
これは翻訳をむやみに並列生成し、失敗した翻訳を作り直し、原文が変わってからまた翻訳した判断コストだった。有料翻訳APIを使わなかったからといって、コストが0になるわけではない。モデル使用量、時間、集中力、検収疲れも全部コストだった。
だから先に固定すべきものがある。
原文確定
翻訳範囲
検収方式
build時点
push基準
この五つが曖昧なら、多言語作業はすぐにまた大きくなる。
今回残した運用基準
今回残した基準は、機能そのものより重要だ。
言語URLは同じドメイン内で分ける。
翻訳記事はlocale collectionに分離する。
翻訳は完了率より信頼経路を先に見る。
原文確定前には翻訳しない。
言語切り替えは常に見えるglobal controlであるべきだ。
閲覧数とtoday dedupeはcanonical page基準で見る。
postをpするときはactive locale翻訳同期まで見る。
buildはbatchごとではなく、最後に必要な範囲で確認する。
Goalは長い状態報告ではなく、実行基準まで小さくする。
英語版を付けたことも大事だった。
しかし、より重要な成果は、ブログを多言語状態で運用し続けるための基準を作ったことだった。
高くついた。
それでも必要な基準だった。
コメントする