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

The player sees {playerName} on screen instead of their name

A player takes a screenshot: the greeting line should read Welcome, Alex but instead shows the raw token, Welcome, {playerName}. Or a damage number renders as the raw format string, %1$s dealt %2$d damage, instead of a name and a number. The text is otherwise readable — this is not a broken string, it is a broken substitution. That distinction matters, because at least four unrelated bugs produce this exact symptom, and the fix is different for each.

Because the string itself displays fine outside this one spot, the bug is easy to miss in review and easy to reproduce only in specific menus or languages. This article walks through how to isolate which of the four causes you are looking at, working from the symptom alone.

First: is it every language, or just one?

This single question splits the four causes in half immediately. If the placeholder shows up literally in every locale, including the source language, the problem is upstream of translation — in the code that calls the string, or in the key itself. If it only happens in one or two translated languages, the problem was introduced during translation.

Cause 1: the token was altered in translation

The most common cause when only some languages are affected: a translator retyped the placeholder instead of copying it verbatim, and a full-width or visually similar character slipped in. { and } look almost identical to their full-width Unicode counterparts ( and )used in Japanese and Chinese text, and translation tools that do not protect placeholders will happily let a translator overwrite %s with %s or {playerName} with {playerName}.

The runtime's string formatter matches placeholders by exact character, so a full-width brace is simply not recognized as the start of a token — it gets printed as literal text instead of being replaced.

  • Fix: restore the exact source characters for every placeholder — copy-paste them, never retype
  • Prevention: a mechanical check that extracts every {token} / %s / %1$s from source and target and diffs the sets catches this before it ships
en: "Welcome, {playerName}"
ja (broken): "ようこそ、{playerName}さん"   // full-width braces, not recognized
ja (fixed):  "ようこそ、{playerName}さん"

Cause 2: the code never passed an argument

If the placeholder is literal in the source-language build too, the bug is not in the text at all. Somewhere in the code, the formatting function was called without its arguments, or with the wrong key, so the value the placeholder expects was never supplied. Some formatting libraries fail loudly in this case; many fail silently and just print the token as-is, because that is a safer default than crashing on missing data.

  • Fix: trace the call site for that string key and confirm every placeholder it declares is present in the arguments object
  • Prevention: a lint or test step that checks every string's placeholder set against the arguments passed at each call site
// Bug: playerName never passed in
formatMessage("welcome_line", {})
// → "Welcome, {playerName}"

// Fixed
formatMessage("welcome_line", { playerName: user.displayName })
// → "Welcome, Alex"

Cause 3: the format style does not match what the runtime expects

Different formatting systems use different placeholder syntax — {name}, %s, %1$s, {0}, and ICU's {name, plural, ...} are not interchangeable. If a string was written in one style but the runtime's formatter parses a different one, it will not recognize the token as a placeholder at all and will print it as literal text, even though the string looks correctly formatted to a human reader.

This shows up after a localization tool, template, or file format migration, when strings get copied between systems that expect different syntax — the text passes a visual review because it looks like a placeholder, it just is not one the code understands.

  • Fix: rewrite the placeholder in the syntax your specific formatter parses, not the syntax that merely looks right
  • Prevention: keep one placeholder style project-wide and validate it against the actual formatter, not by eye

Cause 4: the key was never localized and is falling back to raw

Occasionally the visible text is not a mistranslated string at all — it is the key or a fallback value being displayed because the actual localized string failed to load for that key. This usually looks slightly different from the other three: the whole line is wrong, not just the token, or the text matches the internal key name exactly.

  • Fix: confirm the key exists in the loaded locale file and that the load path or bundle actually contains it for that build
  • Prevention: a missing-key check as part of the build, not discovered by a player

Isolating the cause from a bug report alone

Ask three questions in order: does it happen in the source language too? If yes, it is cause 2 or 4 — a code or loading problem. If it is one language only, check whether the placeholder characters themselves look subtly different (full-width, spacing) — that is cause 1. If the characters look identical but still are not substituted, compare the exact placeholder syntax against what your formatter documents — that is cause 3. Working through these in order gets you to the right fix without touching the wrong layer of the codebase.

Related articles