icu-invalid: translation is not valid ICU MessageFormat
error — fails the build
The source is an ICU MessageFormat message (a plural or select), but the translation does not parse as ICU — usually an unbalanced brace or a broken plural/select block introduced during translation. At runtime the ICU formatter throws or renders the raw markup.
What triggers it
// en.json (source)
{ "n": "{count, plural, one {# item} other {# items}}" }
// es.json — missing the closing brace
{ "n": "{count, plural, one {# elemento other {# elementos}}" }Fixed
// es.json
{ "n": "{count, plural, one {# elemento} other {# elementos}}" }Why it matters
A malformed ICU message is a hard runtime failure, not a cosmetic one — the whole string breaks. It is easy to introduce when a translator edits inside the braces without knowing the syntax.
How to fix it
Fix the ICU structure so it parses — balance the braces and keep the plural/select categories well-formed. The rule only fires when the source itself was valid ICU, so the source is a working template to compare against.
How to silence it
--ignore-keys 'path.to.key' — but a malformed ICU message is almost always a real bug.
Check for this in CI
npx @shipi18n/cli check ./locales -s en
# SARIF for inline PR annotations:
npx @shipi18n/cli check ./locales -s en -r sarif -o shipi18n.sarifThe structural checks need no API key. Findings of this rule link back to this page from the SARIF helpUri.
Related rules
- plural-category — ICU plural missing a CLDR category for the language
- placeholder-missing — placeholder dropped from a translation