A product that supports one language has strings. A product that supports ten has a supply chain. I’ve worked on a centralised translation service shared by many front ends, and on products with right-to-left scripts and per-market formatting, and the lesson is the same each time: the problems aren’t linguistic, they’re engineering.

Keys, not sentences

Code should reference transfer.review.fee_label, never the English sentence. Sentences change; keys are stable. Keys also carry context for translators — the same English word (“Send”, “Order”, “Close”) often needs different words in other languages depending on where it appears. A key per use, with a description and a screenshot, saves more translator time than any tool.

Plurals and grammar belong in the message

count + " items" breaks in most languages. English has two plural forms; Arabic has six (zero, one, two, few, many, other); some languages have none. Gender and case change words around the number too. Use ICU MessageFormat or an equivalent, so the translator controls the whole sentence:

{count, plural,
  =0    {No transfers yet}
  one   {# transfer}
  other {# transfers}
}

Never build sentences by concatenating fragments. Word order is the translator’s job, not the template’s.

Fallbacks are a chain, and they should be visible

Requests ask for ar-AE; you have ar; you definitely have en. Resolve along a declared chain per locale, at build or load time, and record when a fallback was used. A silent fallback to English is how a market launches half-translated and nobody notices until customers do.

Version translations with the release

If translations live in a database that anyone can edit at any time, the text in production is not the text you tested. Treat translation bundles as artifacts: pulled from the translation system at build, versioned with the release, cached at the edge with long TTLs, and rolled back with the code. Hot-fixing a typo is a release, just a small one — and it can be automated.

Test what humans won’t

  • Pseudo-localisation in CI: render every screen with expanded, accented strings ([!! Šéñd ţŕåñšƒéŕ !!]). It instantly reveals truncation, hard-coded strings that didn’t go through the system, and layouts that assume English lengths.
  • Right-to-left is not a mirror flag. Use logical CSS properties (margin-inline-start, not margin-left), check icons that imply direction, and keep numbers, phone numbers and code left-to-right inside RTL text.
  • Formatting — dates, numbers, currencies — comes from the locale (Intl in JavaScript), never from string templates.
  • Missing keys fail the build, not the user.

Internationalisation done this way stops being a project you do before entering a market and becomes a property of the platform. Adding the eleventh language is a translator’s job, not an engineer’s.