Placeholder Safety
The usual way machine translation breaks a locale file is that the model rewrites the parts that are not prose. Shipi18n extracts those before the request and verifies them afterwards.
What is protected
| Syntax | Example | Used by |
|---|---|---|
| Double brace | {{name}} | i18next, Handlebars |
| Single brace | {count} | ICU, vue-i18n, react-intl |
| printf | %s, %d, %1$s | gettext, sprintf |
| Nested reference | $t(common.greeting) | i18next |
| Ruby / Rails | %{name} | i18n-js |
| Inline HTML | <b>…</b> | Trans components |
How it works
- Placeholders are extracted from each source string before translation.
- The prompt tells the model to reproduce them exactly, unchanged and untranslated.
- The output is checked against the extracted set. Anything missing is reported in
stats.placeholderWarnings, and the CLI prints a warning.
Verifying an existing file
The MCP server exposes check_placeholders, which compares a source file to a translation and reports drift without calling a model at all — free, instant, and useful on files translated by something else.
Keeping strings untranslated
Placeholders are preserved automatically, but whole strings sometimes need to stay in the source language — brand names, legal copy, product identifiers. The GitHub Action supports skip-keys with glob patterns for exactly that.