The translation was already done
I had a daily fortune post publishing automatically in Korean. The goal was simple: publish the same post at the same time to an English account and a Japanese account. No new accounts. I would reuse the three existing accounts and their existing tokens.
I expected a translation job. But the fortune data itself (band copy, lucky colors) already existed in ko, en, and ja. Pass a locale in, and the copy switched on its own.
So translation was not the bottleneck. There were two other ones. First, the assumption 'this is Korean' was hidden in many layers of the generator. Second, some content means nothing to readers in another language, even when translated perfectly.
If you added one language to your project tomorrow, could you list every place, beyond the string files, that assumes a language?
Where Korean was hiding
Threading a locale through the generator touched these: the page lang attribute and font, template labels, spec functions, app list loading, narration text, and the TTS voice. All of them now take a locale parameter.
The font was not optional. Japanese renders use Hiragino. Draw kana with a Korean font and you get tofu, the empty boxes.
Some things were not in the data at all: names of star signs, Chinese zodiac animals, and seasons. The fortune copy was trilingual, but these names existed only in Korean, so I wrote en/ja mapping tables.
The quietest trap was file names. Three locales generating the same kind of asset on the same day would overwrite each other under one name. A per-locale suffix fixed the collision.
Content that should not be translated
This is where the real decision was. The Korean post rotates through several axes: Western star signs, Chinese zodiac animals, and the day pillar from Korean four-pillar astrology. Should all of it go to English?
What would you do: translate everything mechanically and post the same set to all three accounts, or cut the axes per language?
I cut. Korean keeps every axis. Japanese gets star signs and zodiac animals, without the day pillar. English gets star signs only. My judgment was that zodiac animals and four-pillar astrology don't fit a Western audience.
Hashtags followed the same logic. Captions and hashtags are generated per locale, and mega-tags (huge generic tags) are excluded.
The publish loop, and a one-line twist
Running three accounts in one loop means three sets of credentials. I reused a pattern from another automation: swap the env file path (ENV_PATH) the client reads before each account publishes. Accounts are staggered.
Then I tried to add a loop that adjusts itself from performance, and hit a wall. Insights come keyed by media ID, and my publish function was discarding that ID. There was no link between a post and which kind of content it was. The fix was one line: make publish() return media_id.
On top of that sits a learning step. learn() joins insight performance with the publish log's media_id-to-kind mapping and writes kind_weights.json. The daily planner reads that file to weight the app rotation, and falls back to uniform if the file is missing or broken. The publish path makes no synchronous API calls; learning runs on a separate schedule, so a failed learn cannot stop a publish.
Verification: 8 new unit tests, 19 passing overall, the three locale renders checked by eye, and a dry run across all three accounts passing end to end through 6 assets.
Self-check
- Beyond string files, have you listed every place that assumes a language: fonts, the
langattribute, TTS voice, proper-noun mappings, output file names? - Do you separate content that can be translated from content that actually means something in that language market?
- Does your publish function return and log the post ID the platform gives back, so you can join it to performance later?
The honest part
What this record covers is passing tests and a dry run. I don't know yet how the three accounts actually performed, or whether enough data has accumulated for the weights file to mean anything. Dropping zodiac animals and four-pillar content from English was a judgment, not a measurement, and so was dropping the day pillar from Japanese. The learning loop can only compare the kinds I chose to publish. Whether the axes I cut would have worked abroad is something this setup cannot tell me.