Skip to main content

Your app shows {name} instead of the name

A translated string renders the placeholder literally instead of substituting the value. Why it happens, how to find every instance, and how to fix it.

JSON (vue-i18n)JSON (i18next)Rails YAMLFlutter ARB

What you see

  • •The UI prints `{name}`, `{{count}}` or `%{names}` as text, in one language only.
  • •English is fine. A bug report arrives from a user in another locale, or nobody reports it at all.
  • •Tests pass, the locale file is valid, and a key-diffing check finds nothing wrong.

Why it happens

The placeholder in the translation no longer matches the one the code passes. There are three ways that happens, and all three are invisible to a key-set diff: the variable name was translated along with the sentence, the source key was renamed and the translations were not, or the placeholder was simply dropped.

1The variable name got translated

A translator or a model treated the token as prose. `{name}` becomes `{naam}` in Afrikaans, `{名前}` in Japanese, `%{рецепт}` in Russian. The renderer has no variable by that name, so the raw token reaches the user.

hoppscotch/hoppscotch80k★

Afrikaans `state.connected_to` carried `{naam}` where the source has `{name}`.

Our report — merged 2026-09-21 →

2The source renamed the variable

English moved from `{team}` to `{workspace}` and the 30-odd translations kept `{team}`. Key parity is perfect, so a check that only compares key sets passes.

hoppscotch/hoppscotch80k★

`team.join_team` still read `{team}` in 21 locales after the source switched to `{workspace}` — German `{team} beitreten`, Spanish `Entrar al espacio de trabajo {team}`.

Our report — the Afrikaans fix merged; the other 25 locales are still open →

3The placeholder was dropped

The translation reads as a complete sentence, so nothing looks wrong, but the value it was supposed to name is gone. The user gets a generic message instead of a specific one.

solidusio/solidus5.3k★

Dutch and Polish dropped `%{names}` from the out-of-stock flash, so the message could not say which item became unavailable.

Our report — approved by two maintainers →

Find every instance

Point the checker at your locale directory. No API key, no account, nothing leaves your machine:

npx @shipi18n/cli@latest check ./locales -s en --severity 'missing-key=off,untranslated=off,orphan-key=off'

Those flags narrow the output to placeholder and plural problems. Drop them to see missing and untranslated keys too, which on a partly-translated project is a much longer list.

✗ es  coverage 100.0%  1 error(s), 0 warning(s)
    error  greeting  placeholder-missing — dropped {name}

How to fix it

  1. 1Restore the placeholder using the source spelling exactly. The token is an identifier, not prose: it is never translated, even when the surrounding sentence is.
  2. 2If the source renamed a variable, sweep every locale at once rather than the one that was reported. In our scan the reported locale was almost never the only broken one.
  3. 3Add the check to CI so the next one fails the pull request instead of shipping. `--baseline` records what exists today and fails only on newly-introduced drift.

The rules that catch this

How often this actually happens

Found in 21 of 64 public repositories we scanned, 119 strings, each read against the source string by hand: https://shipi18n.com/oss