Localization QA: the validations that catch broken strings

The mechanical checks that catch broken translations before release — placeholders, plurals, HTML, character limits — and why review alone never finds them.

Localization QA divides cleanly in two, and conflating the halves is why teams end up doing neither well.

Linguistic QA asks whether the translation is accurate, natural and appropriately registered. It requires a human who speaks the language.

Functional QA asks whether the translation will break the product. It requires a parser, and it should never be a human’s job — because a human reading for meaning cannot reliably see that %{count} became %{compte}.

This page is about the second kind. It is the half that is fully automatable, and the half that causes production incidents.

Why review does not catch these

A reviewer opens a French translation and reads it. It says what it should say. It reads well. They approve it.

They did not notice that the placeholder is now %{nom} instead of %{name}, because in French nom is simply the correct word and their eye read the sentence, not the punctuation. In production that string renders with a literal %{nom} in it, or throws, depending on the framework.

This is the general shape: the errors that break software are the ones that look like correct language. Reviewing harder does not help. Parsing does.

The checks worth running

Placeholder integrity

The single highest-value check. Compare the set of placeholders in the source against the set in the target: same syntaxes, same names, same count, same indices.

source:  Hello %{name}, you have %{count} messages
target:  Bonjour %{nom}, vous avez %{count} messages
                     ^^^ not in source

Catches translated placeholder names, deleted placeholders, invented ones, mangled positional indices, and whitespace inserted inside the delimiters (%{ name } is not %{name}). See the placeholder formats cheat sheet for the syntaxes involved.

Plural categories

Verify the translation supplies exactly the categories the target language’s CLDR rules require — no more, no fewer. English gives you two; Polish needs four; Arabic needs six. A Polish translation with only one and other will fall back or fail at runtime for most numbers. See plural rules by language.

ICU MessageFormat syntax

If you use ICU MessageFormat, parse the target. The failures are specific and common: the keywords plural, select, one, other translated into the target language, a missing other branch, a dropped #, an unescaped apostrophe silently swallowing the rest of the message. WebTranslateIt detects mistranslated ICU keywords across 12 languages and offers to correct them automatically.

HTML tags

Tags present in the source must be present, balanced and correctly nested in the target. Translators legitimately reorder tagged phrases because word order differs — the check is that the tags survive, not that they stay in place.

Character limits

Where a string has a maximum length — a button, a mobile label, a subtitle cue — enforce it as the translator types rather than discovering the overflow in a screenshot review. This is the one check that genuinely changes the translator’s behaviour, because compression is a task they can only do while composing.

The smaller checks

Individually minor, collectively responsible for a lot of noise:

  • Leading and trailing whitespace, which is meaningful when strings are concatenated.
  • Double spaces, usually a typo, occasionally intentional.
  • Line breaks — count preserved, since a \n often maps to a layout break.
  • Numbers present in the source and preserved in the target. A price or version number silently changed is a serious bug.
  • Punctuation and brackets balanced; a missing closing parenthesis reads as sloppiness.
  • Ellipsis consistency — ... versus matters for width-constrained UI.
  • Keyboard accelerators — the & in &File marks the access key and must survive.
  • CDATA and array structure for formats that carry them.
  • Capitalization conventions, which differ by language: German capitalises all nouns, French does not capitalise days or months.
  • Terminology — flagging a segment where a term base entry has been rendered differently from the approved form.

Where the checks should run

In the editor, as the translation is typed. This is the argument worth making. A check that fires in CI has found the error after the translator has finished, been paid and moved on — so fixing it means reopening the task, explaining the problem, and waiting. A check that fires in the editor is fixed in four seconds by the one person who can fix it correctly, while the string is still in their head.

WebTranslateIt highlights the offending part of the string inline rather than showing a message alongside it, and offers AutoCorrect for the mechanical cases — restoring a mangled placeholder or repairing an ICU keyword. That closes the loop entirely for the class of error where there is only one correct answer.

In CI as a backstop. Not instead of the editor, but as the guarantee that nothing ships broken regardless of where it came from — a direct file edit, a bulk import, a machine translation batch.

Turn checks off deliberately. Some are wrong for some projects: a project that never uses HTML does not need tag balance, and capitalization rules are genuinely different for some content. A check that fires constantly and is always wrong trains people to ignore all checks, which is worse than not having it.

What still needs a human

The functional checks say nothing about whether the translation is any good. Reserve human attention for the things only a human can judge:

  • Accuracy. Does it mean the same thing?
  • Register and tone. Formal or informal address, and consistently so.
  • Context correctness. The classic case is a single word — Open translated as an adjective when it labels a button.
  • Cultural fit. Examples, idioms, imagery, anything referencing a holiday or a payment method that does not exist in the market.

The point of automating the functional half is precisely to protect this attention. A reviewer who is also mentally diffing placeholder syntax is doing neither job well.

Tuning out the false positives

A check that fires constantly and is usually wrong is worse than no check, because it teaches people to dismiss the whole panel without reading it. Budget time to tune, and expect these to need it:

Terminology. Morphology means an approved term legitimately appears inflected — German compounds it, Slavic languages decline it. A naive substring match flags all of these. Either allow inflected forms or accept that this check advises rather than blocks.

Capitalization. German capitalises every noun; French does not capitalise days, months or languages; title case is largely an English convention. A single rule across all languages is wrong for most of them.

Punctuation. French inserts a narrow no-break space before ?, !, : and ;. Spanish opens questions with ¿. CJK uses full-width punctuation. A check comparing target punctuation to source punctuation will flag every correct translation into those languages.

Numbers. Digits legitimately change form — Arabic-Indic numerals, or a spelled-out number where the source used a digit.

The right response to a consistently wrong check is to turn it off for that language, not to train the team to ignore the panel.

A minimum viable setup

If you are starting from nothing, in order of value:

  1. Placeholder validation. Highest value, lowest effort, catches the most damaging class of bug.
  2. Plural category completeness, if you support any language with more than two forms.
  3. Character limits on the strings that actually have them.
  4. HTML tag balance, if your strings contain markup.
  5. Everything else, tuned as you find out which checks earn their noise.

The first item alone eliminates most localization production incidents. It is worth doing before anything else on this page.

Frequently asked questions

What is localization QA?
Localization QA is the process of verifying that translated content is correct and will not break the product. It splits into linguistic QA, which is human review of meaning and tone, and functional QA, which is mechanical validation of placeholders, plural forms, markup and length.
What are the most common localization bugs?
Missing or mangled placeholders, missing plural categories for the target language, unbalanced HTML tags, and text exceeding a character limit. All four are mechanical, all four are invisible to a reviewer reading for meaning, and all four are caught reliably by a parser.
Should validation run in CI or in the translation editor?
In the editor, primarily. CI catches the error after the translator has moved on, so someone has to reopen the task and route it back. Validating as the translation is typed puts the error in front of the one person who can fix it immediately.
Can localization QA be fully automated?
The functional half can. Placeholder integrity, plural completeness, tag balance and length are all decidable by a parser. The linguistic half cannot — whether a translation is accurate, natural and correctly registered needs a human who speaks the language.

Keep reading

Translate your app without the spreadsheet round-trip

WebTranslateIt reads the file formats and placeholder syntax described on this page, validates them as translators work, and syncs the results straight back into your repository.