A Ukrainian-language edition, on purpose
My partner (and secret best friend), Gina, is currently in Kyiv. In a few days, she'll train back to Lviv where she'll enroll in a 3-week intensive Ukrainian language class at Ukraine Catholic University. So, obviously, the site got a real Ukrainian-language edition at /ua: a translated landing, two fully interactive instruments, curated essay companions, browsable index hubs, and a bilingual blog pipeline. A build log on why, and on what the whole surface is.
This one started with a feeling that something was off. A big chunk of the research on this site is about Ukraine: the recovery, the registries, the legibility gap between a damaged home and a state that can actually read it. My partner is in Ukraine, teaching. And every word of the site was English-only. So over the last few weeks I built a real, public Ukrainian-language edition at /ua. Not a translate-button. Not a one-page gesture. A deliberate surface that keeps growing. This is the build log for the whole thing: why it exists, what it actually is. The looping cover above was filmed straight off the running site. The pipeline's at the end.
Why Ukrainian, specifically
Localization is usually a checkbox: ship the framework, wire a few strings, call it international. Not here. The Invisible Infrastructure series, the field data at The Legibility Gap, the Wartime Edition of the sorting-machine essay - all of it measures Ukraine's recovery from the inside. So write carefully about a place, then make that writing unreadable to the people who actually live there? That's its own small failure of legibility. There's already a private trip log on the site. It's the one whose blue-and-gold flag theme earned a make it MORE Ukrainian note from the person living there. The public research deserved that same intention. That's the whole point. The work points at Ukraine, so the site should be able to speak Ukrainian back.
What /ua actually is
It's a full subtree, not a single page. Underneath, a handful of URL-prefix i18n primitives do the work: canonical English lives at /path, Ukrainian at /ua/path, and hreflang tells search engines they're twins. The real surfaces sit on top of that.
- A translated landing at
/ua, plus locale-aware chrome everywhere: nav, footer, and anEN | UAswitcher that flips any page to its twin. - Two fully interactive research instruments rebuilt in Ukrainian, The Legibility Gap and the Wartime Edition. Live widgets and all. Every number still comes off the language-neutral dataset, so the figures can never drift from the English original.
- Curated essay companions: The Sorting Machine, The New Sorting Hat, Stance Design, and What the State Keeps.
- Two index hubs,
/ua/researchand/ua/blog, so you can actually browse it instead of digging through a drawer of loose URLs. - A bilingual blog pipeline: additive Ukrainian columns, a translator agent, and an admin editor. Any post here can carry a Ukrainian twin without forking the English one.
Curated, not machine-translated
The one decision holding all of this up is simple: none of it is machine output generated on the fly. Every Ukrainian page is a curated artifact. Interactive instruments get translated string by string, and the data stays exactly as it was. But the long essays work differently. They become faithful companions. A forty-thousand-word piece doesn't need a forty-thousand-word twin to be legible to a Ukrainian reader; it needs an honest condensation that keeps every sourced figure and links back to the full English interactive when you want it. Where I've finished a translation, that's what you see. Where I haven't yet, you get the English original with a small chip flagging it before you click through. The reader is never lied to about what they're about to read.
The deliberate choices
I made a few calls on purpose, and a couple of them go against the textbook:
- The locale code is
ua, the country code, not theuklanguage code. The standards-correct tag isuk. I picked the flag's country code for brand consistency, knowing it costs a little machine-readability. A deliberate trade, and I documented it so someone can revert it. - English stays byte-identical. The Ukrainian surfaces sit beside the English ones as separate, curated artifacts. They're never a fork. Adding the whole edition regressed the English site by zero bytes.
- The fonts can carry Cyrillic. I built the edition around the four typefaces that actually ship Cyrillic glyphs, so nothing renders as tofu.
- It is not the trip log.
/uais the public language edition. The private/ukrainetrip log is a different surface with its own translator, kept separate on purpose. - No em dashes, in either language. CI scans for them.
A pipeline, not a one-off
I built it this way so the next translation costs almost nothing. A new essay companion? That's a content file plus a thirty-line page riding on a shared shell. A new bilingual blog post is a handful of Ukrainian fields dropped onto the row that already exists. One registry of translated paths runs the sitemap, the hreflang tags, and the dead-link-safe link rewriting at the same time, which keeps breadth from outrunning correctness. The edition is unfinished on purpose. Most essays still open in English, and I'm fine with that, because the front doors and the chips keep the half-built state honest. More companions land on the same rails. More translated posts too.
Translation is the visible part. The harder half is making sure the page you haven't translated yet still has an honest door back to the one you have.
How the cover was filmed
That loop up top? Not a mockup. Every post gets a /cover/<slug> surface, a full-bleed cinematic title card. Here's how it works: a small recorder (scripts/covers/record-covers.mjs) opens the card in a headless browser and captures exactly one seamless loop at 1080p. Out come three files, straight into /public/covers/ - a VP9 webm, an H.264 mp4, and a poster frame. The homepage feed and this post's hero grab them without me lifting a finger. Same pipeline I use to film the Studio reels. I just aimed it at a cover instead of a walkthrough.
Get the next one
An occasional note when something genuinely new ships here — essays, free tools, projects. No schedule, no filler, easy out.
Need something like this built?
I design and ship AI tools, full-stack apps, and data pipelines — end to end, to production. Tell me the problem in a sentence; I'll give you an honest read on fit within a day.
Work with me →