Skip to main content
shipi18n logo|Documentation

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.sarif

The structural checks need no API key. Findings of this rule link back to this page from the SARIF helpUri.

Related rules