ICU MessageFormat Guide: Plurals, Selects, and Why Logic Belongs in Messages
How ICU MessageFormat handles placeholders, plurals, selects, and formatting logic, and why teams should keep grammar logic in messages instead of code.
If your localized messages depend on count, gender, date formatting, or sentence shape, ICU MessageFormat is usually the first syntax worth learning properly.
Many localization bugs are not translation bugs at all. They happen because developers try to assemble sentences in code with string concatenation, simple conditionals, or English-only assumptions about plural rules.
ICU MessageFormat exists to solve that class of problem. It is the syntax layer that lets developers describe variables, plurals, selections, numbers, and dates inside a message itself instead of scattering logic across the application.
Formats such as Flutter ARB and some JavaScript localization systems often use ICU inside a larger file format. That is why ICU is worth learning even if your app never stores translations in a file named .icu.
Quick answer ✅
ICU MessageFormat is worth using when translated messages need real logic, not just substituted words. It is especially valuable for plurals, selects, numbers, dates, and grammar-sensitive strings that would otherwise turn into fragile code-side conditionals.
If your app only needs static labels, ICU may be unnecessary. If your messages change shape across languages, ICU quickly stops being optional.
Reach for ICU when... 🧠
- messages depend on count, gender, or category
- you want grammar logic inside the message layer rather than scattered in code
- cross-platform portability matters
- localization bugs are coming from string assembly, not vocabulary
It may be overkill when... ⚠️
- the app only needs short static labels
- teams will not maintain logic-heavy messages carefully
- a richer translator-centric model like Fluent is actually the better fit
- the workflow still treats ICU syntax as ordinary prose
Message logic map
This diagram shows why plurals, selects, and formatting rules belong inside the message definition instead of being scattered through UI code.
What ICU MessageFormat actually solves
Developed by Unicode, ICU MessageFormat is a syntax that allows developers to write strings that contain logic. Instead of concatenating strings in code, you provide a single message with placeholders, plurals, selects, and locale-aware formatting rules.
That sounds abstract until you localize beyond English. Suddenly a message may need different output depending on count, gender, grammatical role, or locale-specific number formatting. ICU puts those decisions in the message layer where translators and internationalization tooling can reason about them.
The Core Syntax: Braces and Keywords
At its simplest, ICU uses curly braces {} to denote variables. However, its real power lies in its Select and Plural arguments.
1. Simple Interpolation
Hello, {name}!2. The Plural Format
The plural keyword allows you to define different text based on a numeric value. It supports exact matches (like =0) and categories (one, few, many, other).
{count, plural, =0 {You have no notifications.} one {You have # notification.} other {You have # notifications.}}Note: The # symbol is a special character that automatically injects the count value into the string.
Plural handling is one of ICU’s biggest strengths because it maps to real language categories rather than to a naïve singular/plural split. That is essential for languages with several plural forms.
Handling Gender and Categorization
The select keyword acts like a switch statement. This is essential for languages that have gendered nouns or require different sentence structures based on a category.
{gender, select, male {He liked your photo.} female {She liked your photo.} other {They liked your photo.}}Advanced Formatting: Dates, Times, and Numbers
ICU isn’t just for text; it handles data localized to the user’s region. This ensures that a date looks like MM/DD/YYYY in the US but DD/MM/YYYY in the UK.
- Numbers:
{val, number, percent}converts0.5to50%. - Currency:
{val, number, currency}formats the value based on the locale’s currency symbol. - Dates:
{val, date, long}displays “January 26, 2026”.
Why Developers Reach for ICU
ICU solves a deeper problem than simple interpolation. It lets teams move linguistic logic out of UI code and into a format that can survive translation safely.
That gives teams three major benefits:
- better grammatical correctness across languages with different structure
- cleaner application code because message logic stays out of components and controllers
- cross-platform portability because ICU concepts appear in many ecosystems
ICU vs. Simpler Localization Formats
ICU is not always the easiest syntax to read, but it is often the right tool once messages contain real linguistic behavior.
Compared with other options:
- i18next JSON v4 improves plural naming at the file level, but ICU is stronger when the message itself carries more logic
- Flutter ARB often embeds ICU expressions inside a Flutter-specific metadata format
- Mozilla Fluent can be more expressive and translator-friendly for some advanced use cases, but it introduces a different message model entirely
If your app only needs static labels, ICU may be overkill. If your product has plurals, select logic, rich formatting, or cross-locale grammatical variation, ICU quickly becomes worthwhile.
Common ICU Mistakes ⚠️
Building sentences around placeholders in code
Developers sometimes keep the logic in code and use ICU only for a fragment of the sentence. That weakens the whole point of the format and often breaks localization quality.
Treating ICU syntax as plain prose
Generic translation tools may try to rewrite keywords such as plural or damage brace structure. ICU messages need syntax-aware handling.
That is one reason ICU becomes a buying problem as much as a developer problem. Once localization volume grows, teams need tooling that can preserve message logic consistently instead of relying on reviewers to catch broken braces after the fact.
Forgetting runtime review
Even a valid ICU string still needs UI review. Localized output may expand or reflow differently once rendered in the application.
Why ICU is still a must-know
- Portability: It is supported by almost every major programming language (Java, C++, JavaScript, Python).
- Grammatical Correctness: It prevents the “Frankenstein sentences” created by joining strings in code.
- Translator Friendly: Professional translation tools are built to recognize and protect ICU syntax, ensuring variables aren’t accidentally translated.
Practice and next steps
Mastering ICU syntax is one of the highest-leverage skills in software localization because it moves grammar-sensitive behavior into the message layer where it can actually be reviewed and translated well.
For hands-on practice, try the ICU MessageFormat Editor and test how the same message behaves across different counts, categories, and locales.
Where MetalGlot fits the ICU workflow
ICU is powerful, but it is also easy for general translation systems to break. A tool that treats the message as ordinary text may rewrite keywords, braces, or placeholder structure and leave you with output that looks translated but no longer runs.
MetalGlot handles ICU as structured message logic, not plain text.
- Logic isolation: Preserve
select,plural, and placeholder structure. - Placeholder management: Keep count insertion and variable references intact.
- Format-aware fluency: Translate the human language while respecting the message logic.
Final take
ICU MessageFormat remains one of the most important skills in software localization because it addresses the hardest part of the problem: messages that depend on grammar, not just vocabulary.
Once teams move beyond static labels, ICU is often the difference between software that merely supports multiple languages and software that actually sounds native in them.