craigthompson.dev

$ cat case-studies/i18n.md

One product in 36 languages, kept in step

// internationalisation · 2019 → 2026

One product in 36 languages, kept in step

Customers survey their people in their own language, so the interface and the questions have to work in every language they turn on. I’ve kept the platform’s 36 interface languages in step with English, and made translating customers’ own content cache-first and selective.

36
interface languages, including Welsh and Arabic
~116k
blank strings removed, so nothing renders empty
cache first
translations checked inside the VPC before any network call
Interface text, kept in step by the build
  1. messages in components
  2. extracted to English
  3. keys synced to every language
  4. gaps fall back to English
Customer content, translated at runtime, cache first
  1. survey question
  2. Redis cache inside the VPC
  3. translation service + DynamoDB
  4. Google Cloud Translation
areabeforeafter
language filesdrifted as keys changedEvery build adds and removes keys in every language to match English
missing textshown as a blankFalls back to the English message
new languageswired in by hand; three droppedGenerated from the language files present
translation callsa network round trip each, often timing outCache inside the VPC first, with one set of timeouts across services
what's translatedevery name, on every read and writeOnly content written to be read in other languages; place names stay as written
language pickereach language in its own scriptEvery language named in the reader’s own language
emojisent to the translator as-isSwapped for keywords and restored, so they come through translation intact
How it evolved: drifting files → in step on every build
  1. language service (2019)
  2. locale pipeline rebuilt
  3. translations in the survey builder
  4. cache-first translation
  5. synced on every build
# in practice
  • A changed or removed string updates every language in the same change, so no file falls behind.
  • Untranslated text shows in English rather than as a gap on screen.
  • Adding a language means adding its file; the build generates the rest.
  • Customer content is translated only when it should be, and served from a cache next to the services.
  • This site follows the same ideas on the visitor’s own device: English fills any gap, translations are cached, and names and file names are never translated. See this-site.md.

$ ls case-studies/

Search and jump