QA & troubleshootingこの記事を日本語で読む

Detecting untranslated strings — and the false positives that come with it

An untranslated string is the simplest localization defect to define and, somehow, still one of the easiest to ship. It slips through because it does not crash anything and does not look obviously wrong in a file browser — it only becomes obvious when a player lands on that exact screen in that exact language. Detecting it reliably is less about finding a clever trick and more about being precise about what counts as untranslated and building a check that runs on every entry, every time.

The basic signal: target identical to source

The default check is straightforward: compare the target string to the source string for the same key, and flag an exact match. If a Japanese target for a key still reads word-for-word like the English source, it was very likely never translated. This one comparison catches the large majority of real cases and is cheap enough to run on every entry in every file, every time a build is checked.

The false positives worth knowing

A naive identical-to-source check will also flag strings that are correctly identical on purpose. Treating every one of these as a hard error trains people to ignore the check, so it is worth listing them explicitly:

  • Proper nouns — character names, brand terms, or in-world names that are meant to stay the same across languages
  • Short affirmatives and acronyms that are identical or near-identical across many languages ("OK", "HP", "Wi-Fi")
  • Pure numbers, currency symbols, or codes with no translatable content
  • Terms deliberately kept in the source language as a stylistic or brand choice

Empty targets are a different case, and worth checking separately

An empty target string is not caught by an identical-to-source check — an empty string is never equal to a non-empty source string — but it is arguably a more urgent bug, since it usually means the game will render literally nothing where text was expected, rather than falling back to readable (if wrong-language) text. Check for empty or whitespace-only targets as its own rule, not as a side effect of the identical-to-source check.

Fallback leakage: in the file versus at runtime

It is worth distinguishing two places an untranslated string can surface. The first is inside the localization file itself — the entry exists, but its content is the source text, either because it was never translated or because a build step deliberately copied source into missing targets as a safety fallback. The second is at runtime: the entry may be genuinely missing from the target file, and the game's own fallback logic substitutes the source-language string live, in front of the player.

Both end up looking the same to a player, but they are different bugs with different fixes. A check that only reads localization files will not see runtime fallback if the missing key never made it into the file at all — that case is really a missing-key bug wearing an untranslated-string costume, and it needs the key sets compared across languages, not just the string contents compared within one file.

Why per-entry status tracking beats eyeballing

Skimming a translated file to spot anything that still looks like English works passably on a small file and falls apart on a large one — attention drifts, and a string that is subtly wrong (translated three versions ago, technically not identical to the current source, but no longer quite matching it either) does not visually stand out the way an obviously untranslated line does. A per-entry status — translated, untranslated, needs-review, stale — checked mechanically against current source content scales in a way that skimming never will, and it produces a list a human can act on instead of a feeling that something might be off.

New source strings are untranslated until proven otherwise

The safest default for any newly added source string is to treat it as untranslated the moment it appears, rather than waiting for someone to notice it is missing from every target file. In practice this means the moment a key is added to the source file, every target language should show that key as an open item until a translation is actually entered for it — not silently pass a check just because nothing flagged it yet. Treating new and untranslated as the same state by default is what keeps a growing source file from quietly outrunning its translations.

Related articles