Skip to main content

Rails renders %{name} instead of the value

A Rails locale file shows the literal %{name}, or a sentence with the value missing, in one language. Why I18n.t cannot substitute it, and how to find every instance across your locales.

Rails YAML

What you see

  • A flash message or mailer prints `%{name}` as text, or reads as a complete sentence with the specific value gone.
  • English is correct. The broken locale often looks fluent, which is why review passes it.
  • `i18n-tasks` reports nothing, because every key is present on both sides.

Why it happens

Rails interpolates by name: `t("...", names: items)` substitutes `%{names}` and nothing else. If the translation spells the variable differently, translates it, or simply leaves it out, Rails either raises `I18n::MissingInterpolationArgument` or renders a sentence that has lost the thing it was supposed to name. Key-set comparison cannot see any of it, because the key is right there.

1The variable was dropped and the sentence rewritten around it

The translator produced a generic sentence rather than a template. It reads well, it passes review, and it can no longer tell the user which item, order or amount the message is about.

solidusio/solidus5.3k★

Dutch and Polish rendered the out-of-stock flash without `%{names}`, so a shopper was told something became unavailable but never which item. The call site passes `names: out_of_stock_items`.

Our report — merged 2026-09-22 with three approvals →

2The source renamed the variable and the translations kept the old one

English moves from `%{commentable_id}` to `%{typename}` and forty locale files still reference the retired name. Rails raises on a missing interpolation argument, so this is the version that shows up as an exception rather than bad copy.

ifmeorg/ifme1.6k★

Catalan, Spanish, Argentinian Spanish and Brazilian Portuguese still used `%{commentable_id}`; Swedish used `%{commented_on}`. Hindi, Indonesian, Vietnamese and Chinese had gone further and translated the variable name itself.

Our report — ten locales, filed 2026-09-21 →

3A link or fragment interpolation disappears entirely

Sibling keys that hold a link label are a common casualty: the sentence survives, the anchor does not, and the page quietly loses a route to its own documentation.

24pullrequests/24pullrequests1.7k★

Thirteen locales rewrote the homepage line as plain prose and dropped `%{contributing_path}`, so the link to the contributing primer never rendered in those languages.

Our report — merged about two hours after it was opened →

Find every instance

Point the checker at your locale directory. It unwraps the Rails root key, so trees compare key for key:

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

Pipes are not plural separators in Rails, and strftime patterns under `date.formats` are not placeholders; the Rails grammar knows both, so neither shows up as noise.

✗ nl  coverage 100.0%  1 error(s), 0 warning(s)
    error  spree.inventory_error_flash_for_insufficient_quantity  placeholder-missing — dropped %{names}

How to fix it

  1. 1Restore the variable using the source spelling exactly. `%{names}` is an identifier; it is never translated, even when the sentence around it is.
  2. 2When the source renames a variable, update every locale in the same change. In all three cases above the reported locale was not the only one affected.
  3. 3Add the check to CI so the next rename fails the pull request. `--baseline` freezes what exists today and fails only on new drift, which keeps a large tree green on the first run.

The rules that catch this

How often this actually happens

Rails projects were a blind spot in our first scan and turned out to be among the most affected once the checker learned the format: https://shipi18n.com/oss