Tuesday, June 30, 2026
Read This in Two Languages: How This Site Does Multilingual

The article you're reading exists in English and in French. Same page, same layout, same author—two languages. If the language switcher in the header is set to French, you're reading a fully translated version of this post. Click the flag up top and watch the page swap languages without losing your place.
That small interaction hides a few decisions worth explaining, because multilingual is one of the things teams underestimate until they're three markets deep and copying content between spreadsheets.
One content item, many languages
In Agility, this post is a single content item with one ID. The English and French versions share that ID; they're two locales of the same record, not two separate posts stapled together. That matters: when an editor opens the item, they see every locale in one place, and our code can ask for this post in French without guessing which row is the translation.
The benefit shows up everywhere downstream. The author, the category, the publish date—anything that isn't language—stays linked across locales. Translators only touch the words that actually change.
Localized URLs, resolved from the sitemap
The English version lives at a clean path. The French version lives under a /fr prefix. Some pages even have different slugs per language, because a good French URL isn't always a word-for-word translation of the English one. The site doesn't hardcode any of this—it reads the sitemap Agility generates for each locale and resolves the right path at request time.
That's also how the flag in the header works. When you switch languages, the site looks up the page you're on by its ID, finds the matching page in the other locale's sitemap, and sends you there. If a translation genuinely doesn't exist, you get a proper 404 instead of a broken half-translated page. The switch happens on the server, so the link you click is already the correct destination.
Why do it this way
Because the alternative—managing languages as disconnected copies—falls apart quietly. Slugs drift. A post gets updated in one language and not the other. Someone ships a page that exists in English but 404s in French, and nobody notices for a month.
Tying every locale to one content item, and resolving every URL from the sitemap, means the structure keeps the languages honest. The site can always answer two questions: does this page have a version in that language, and what's its address there. Everything the reader experiences—the flag, the clean URLs, this very paragraph in two languages—falls out of those two answers.
Now switch the flag and read it again.