[๐ ] Why the multilingual blog Codex Goal took more than 13 hours
โจ GPT-5.5โs Summary ใ
A record of running the Codex Goal that expanded hyuk.blog from a /en/ English version into eight-locale operating rules, while rethinking translation quality, language switching, shared view counts, the p rule, and usage cost.
At first, I thought I only had to choose /en/
The first question was simple.
Would en.hyuk.blog be better?
Would /en/ be better?
After weighing SEO, GitHub Pages operations, how originals and translations should connect, shared view counts, and the language structure for future expansion, the answer was /en/.
I was not trying to run the English version as a completely separate product. This blog has Korean originals, with translations attached to them. In that case, splitting language URLs inside the same domain and connecting them with hreflang is simpler.
But it did not end there.
Once I chose /en/, the home page, About page, categories, search, sitemap, language switcher, view counts, translation quality, and even the way future posts are pushed all started moving together.
It was a collection boundary, not a translation file problem
English posts could not be mixed into _posts.
In Jekyll, _posts goes into site.posts. If English posts are mixed there, the Korean home, feed, pagination, and related posts quietly consume them too. It looks like one more post, but the whole blog index is contaminated.
So translated posts were separated into locale collections.
_posts/... -> /daily-review/.../
_en_posts/... -> /en/daily-review/.../
_ja_posts/... -> /ja/daily-review/.../
_zh_hans_posts/... -> /zh-Hans/daily-review/.../
The first lesson was clear.
A multilingual blog is not about adding translated files. It is about drawing collection boundaries.
The Goal archive from that run
The work started on June 7, 2026 and continued into June 8, 2026.
At first it looked like I was only adding an English version. The Goal quickly grew into this.
Turn hyuk.blog into an operable multilingual blog with ko as the source locale and en, ja, zh-Hans, es, pt-BR, fr, and id as expanded locales.
Do not stop at translation. Align UI, routing, SEO, sitemap, search, language switcher, shared view counts, and today dedupe.
Choose languages with Tadak Bible promotion, portfolio value, Christian populations, and expansion potential in mind.
Do not use paid translation APIs.
Use the latest GPT worker/subagent standard for translation.
Do not trust low-quality local translation output.
Do not translate before the Korean source is confirmed.
When modifying a post and running p, synchronize active-locale translations too.
Run build checks at the end, not after every translation batch.
The Goal itself was not wrong.
The problem was that it did not shrink into execution rules. Status reports, review items, and translation scope kept sticking to it until it became too large.
Translation quality hit hard
Translation was the first place where trust broke.
At first I thought I could translate many posts in bulk. Then a sample file contained prompt instructions as translated content.
Return only the translated content. Do not add notes or fences.
That was not a few awkward sentences. It meant the generation path could not be trusted.
So I sampled whether low-quality translations should be reviewed and salvaged or regenerated. The conclusion was regeneration. Local translation output from tools like Ollama or Argos was not trustworthy enough for public posts. Speed mattered less than which model produced the text and which gate it passed.
The rule left from this is clear.
For translation, the trust path comes before completion rate.
Do not translate before the source is confirmed.
Do not patch public post translation with low-quality local MT.
Language switching and view counts shook too
The English pages opened by direct URL.
But users could not find the Korean/English switch.
At first I put English / Korean inside the normal menu. It existed in the HTML, but users could not see it. Mobile was worse. That made the rule clear: language switching is not a menu item. It is a global control.
View counts were not simple either.
An English post is not a different post. It is a translation of the same post. /daily-review/x/ and /en/daily-review/x/ must not use different view-count keys. So the HTML data-page-view-path, client JS, and Cloudflare Worker all count views by canonical path after removing locale prefixes.
This also grew. Fixing only the Worker code was not enough. It had to be deployed with the Wrangler CLI, and dry-run showed a signal that the D1 DB binding could be missing. So I pinned the Worker entrypoint and D1 binding in wrangler.toml, verified that the binding was present, and only then deployed it.
The important part was today dedupe.
Reading a post in Korean and then switching to English must not increment today twice. If the canonical page is the same, the dedupe key must also be the same.
Why Codex Goal completion took more than 13 hours
This does not mean the pure development work alone took 13 hours.
The problem was that the Goal running in Codex took more than 13 hours to reach completion.
It was not only because there was a lot to do. Some judgments kept moving.
I tried to hold full translation and review at the same time. The standard kept wavering between โgenerate everything first and review laterโ and โreview as we go.โ I trusted translation quality before confirming the worker model, and when bad translations appeared, they had to be made again.
Translating before confirming the source was also a problem.
If the public Korean post keeps changing, translations made first will obviously drift. That led to rewriting the source, throwing away existing translations, and translating again.
Build judgment also drifted.
If a build runs after every translation batch, the work never ends. Build is an important check, but it is not a ritual to repeat every time. The source and translation scope must be locked first, then the needed checks should run near the end.
The meaning of p also became clear late.
Now, when post changes are involved, p does not mean a simple commit and push. It means synchronizing active-locale translations for the confirmed source, then pushing.
Usage was also a cost
This translation work was not solved merely by avoiding paid APIs.
The Pro x20 weekly usage allowance I had paid for just yesterday dropped from 100% to 50% in two days.
That consumption was the cost of blindly generating translations in parallel, regenerating failed translations, and translating again after the source changed. Avoiding paid translation APIs did not make the cost zero. Model usage, time, focus, and review fatigue were all costs.
So the following must be locked first.
source confirmation
translation scope
review method
build timing
push criteria
If these five are vague, multilingual work grows again very quickly.
The operating rules left behind
The rules left by this work matter more than the feature itself.
Language URLs stay inside the same domain.
Translated posts live in locale collections.
For translation, the trust path comes before completion rate.
Do not translate before the source is confirmed.
Language switching must be an always-visible global control.
View counts and today dedupe use the canonical page.
When running p for posts, include active-locale translation sync.
Run builds at the end for the needed scope, not after every batch.
Goals must shrink into execution rules, not grow into long status reports.
Adding the English version mattered.
But the more important output was a standard for keeping the blog operable while it becomes multilingual.
I learned it expensively.
It was still a necessary standard.
Leave a comment