Skip to main content

A Flutter string renders without its placeholder

An .arb translation drops a placeholder the English string defines, so the generated localizations return a sentence with the value missing. What causes it and how to check every .arb file you ship.

Flutter ARB

What you see

  • An error message, counter or title renders without the value it was supposed to include, in one locale.
  • `flutter gen-l10n` completes without complaint, because the key and its metadata are present.
  • The affected string is often a plural or an error path, which is exactly where nobody looks during review.

Why it happens

An .arb file pairs each message with a `@key` block that declares its placeholders. The generator wires those declarations into a typed method, but it does not verify that each translation actually uses them. A translation that drops `{error}` or `{count}` still compiles, still type-checks at the call site, and renders a sentence missing its subject.

1The placeholder is dropped from the translated message

Most common in error strings, where the translation reads as a generic apology instead of naming what failed. The user loses the only diagnostic they had.

KRTirtho/spotube35k★

The Korean `error` string dropped `{error}`, so the app could report that something failed but never what.

Our report — filed 2026-09-16 →

2A title or label loses the name it was describing

A screen heading or toast loses `{title}` or `{name}` and becomes a generic label, so several distinct messages collapse into the same text.

HemantKArya/BloomeeTunes1.1k★

German, Spanish, Japanese and Korean each dropped `{title}` or `{name}` from playback strings.

Our report — filed 2026-09-17 →

3A plural form loses the count

ICU plural branches are separate pieces of text, so one branch can lose `{count}` while the others keep it. The bug only appears at the quantity that selects the broken branch.

Anxcye/anx-reader8.9k★

Traditional Chinese rendered the "yesterday" statistic without `{count}`, while the simplified Chinese form kept it.

Our report — fix prepared →

Find every instance

Point the checker at the directory holding your .arb files:

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

The ARB grammar reads placeholders through the ICU parser, so arguments nested inside plural and select branches are counted, and `%{x}` sequences inside ARB text are not mistaken for placeholders.

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

How to fix it

  1. 1Restore the placeholder in the translated message using the exact name from the `@key` metadata.
  2. 2Check every plural branch, not just the one that was reported: `one` and `other` are separate strings and fail independently.
  3. 3Run the check in CI ahead of `gen-l10n`, so a translation that drops a declared placeholder fails the pull request.

The rules that catch this

How often this actually happens

Flutter projects in our scan were hand-maintained and generally accepted fixes quickly: https://shipi18n.com/oss