essaysJune 23, 20265 min read
By

A Ukrainian-language edition, on purpose

Most of my research is about Ukraine, and my partner is there. So 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 large part 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 read it. And my partner is in Ukraine, teaching. Yet every word of it 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, but a deliberate, growing surface. This is the build log for the whole thing, why it exists and what it actually is. The looping cover above was filmed straight off the running site (the pipeline is at the end).

Why Ukrainian, specifically

Localization is usually a checkbox: ship the framework, wire a few strings, call it international. This wasn't that. 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. Writing carefully about a place and then making that writing unreadable to the people who live there is its own small failure of legibility. There is already a private trip log on the site (the one whose blue-and-gold flag theme got a make it MORE Ukrainian note from the person actually living there). The public research deserved the same intention. That is the whole motivation: the work points at Ukraine, so the site should be able to speak Ukrainian back.

What /ua actually is

It is a full subtree, not a page. Under the hood it is a set of URL-prefix i18n primitives: canonical English at /path, Ukrainian at /ua/path, paired with hreflang so search engines treat them as twins. On top of that sit the real surfaces:

  • A translated landing at /ua, and locale-aware chrome everywhere: the nav, the footer, and an EN | UA language switcher that swaps any page for its twin.
  • Two fully interactive research instruments rebuilt in Ukrainian, The Legibility Gap and the Wartime Edition, live widgets and all, with every number still computed from 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/research and /ua/blog, so the whole thing is browsable rather than a drawer of loose URLs.
  • A bilingual blog pipeline: additive Ukrainian columns, a translator agent, and an admin editor, so any post here can carry a Ukrainian twin without forking the English one.
An English path enters the localizeIfAvailable rule, which checks LOCALIZED_PATHS. If a Ukrainian twin exists, the link resolves to the /ua page and is chipped 'Українська версія'; if not, it resolves to the English page and is chipped 'EN'. Below, two index hubs, /ua/research and /ua/blog, feed the three research companions.
One rule ties the whole surface together. A link either has a Ukrainian twin or it doesn't, and either way you never hit a dead end.

Curated, not machine-translated

The load-bearing decision is that nothing here is on-the-fly machine output. Every Ukrainian page is a curated artifact. The interactive instruments are translated string by string, with the data left untouched. The long essays become faithful companions: a forty-thousand-word piece does not need a forty-thousand-word translation to be legible to a Ukrainian reader, it needs an honest condensation that keeps every sourced figure and then links back to the full English interactive. Where a translation exists, you get it; where one doesn't yet, you get the English original with a small chip that tells you so before you click. The reader is always told the truth about what they are about to read.

The deliberate choices

A few decisions were made on purpose, and a couple of them cut against the textbook:

  • The locale code is ua, the country code, not the uk language code. The standards-correct tag is uk; I chose the flag's country code for brand consistency, knowing it costs a little machine-readability. A deliberate trade, documented so it can be reverted.
  • English stays byte-identical. The Ukrainian surfaces are separate, curated artifacts layered beside the English ones, never a fork of them. Adding the whole edition regressed the English site by zero bytes.
  • The fonts can carry Cyrillic. The edition is built around the four typefaces that actually ship Cyrillic glyphs, so nothing renders as tofu.
  • It is not the trip log. /ua is the public language edition; the private /ukraine trip log is a different surface with its own translator, deliberately kept separate.
  • No em dashes, in either language, scanned in CI.

A pipeline, not a one-off

The point of building it this way is that the next translation is cheap. A new essay companion is a content file plus a thirty-line page on a shared shell. A new bilingual blog post is a few Ukrainian fields on the existing row. One registry of translated paths drives the sitemap, the hreflang tags, and the dead-link-safe link rewriting all at once, so breadth never gets ahead of correctness. The edition is deliberately unfinished: most essays still open in English, and that is fine, because the front doors and the chips make the half-built state honest. More companions and more translated posts will land on the same rails.

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

The loop at the top isn't a mockup. The site has a /cover/<slug> surface, a full-bleed cinematic title card for any post, and a small recorder (scripts/covers/record-covers.mjs) opens it in a headless browser, captures exactly one seamless animation loop at 1080p, and encodes a VP9 webm, an H.264 mp4, and a poster frame straight into /public/covers/. The homepage feed and this post's hero pick it up automatically. Same pipeline that films the Studio reels, pointed at a cover instead of a walkthrough.

Experience it yourselfOpen the Ukrainian edition
ShareXLinkedInHacker NewsEmail

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 →