Glot — Free Online JSON Editor & i18n Translation Tool
By Glot Team

ICU Message Format: The Complete Guide for i18n Developers

Plurals, gender, and select patterns — ICU Message Format handles the hard parts of multilingual strings so you don't have to.

If you've ever tried to translate "You have 3 items in your cart" into a language where the plural rules are wildly different from English, you've felt the pain that ICU Message Format was designed to solve. Simple string concatenation falls apart the moment you deal with plurals, gender, or any kind of grammatical variation. ICU gives you a single, standardized syntax that handles all of it.

ICU Message Format is part of the International Components for Unicode (ICU) project — a battle-tested set of libraries that power internationalization in operating systems, browsers, and frameworks worldwide. If you're building a multilingual app, understanding ICU syntax isn't optional. It's the lingua franca of modern i18n.

Basic Syntax: Variables and Simple Messages

At its simplest, an ICU message is just plain text with placeholders wrapped in curly braces:

Hello, {name}! Welcome back.

At runtime, your i18n library replaces {name} with the actual value you pass in. Nothing fancy here — it works exactly like template literals. But the real power shows up when you need to handle different grammatical forms.

Plural Rules: Getting Numbers Right

English has two plural forms: singular and plural. But Arabic has six. Polish has four. Japanese has one. Hardcoding item + (count === 1 ? '' : 's') doesn't cut it when your app ships in 20 languages. ICU's plural type handles this cleanly:

{count, plural, one{You have # item} other{You have # items}}

The # symbol is automatically replaced with the numeric value. The categories (one, other) follow CLDR plural rules, which define the correct categories for every locale. For English you only need one and other, but for Russian you'd add few and many:

{count, plural, one{# товар} few{# товара} many{# товаров} other{# товара}}

You can also use exact-value matches like =0 for special cases:

{count, plural, =0{Your cart is empty} one{You have # item} other{You have # items}}

Select Patterns: Handling Gender and More

Many languages require different sentence structures based on gender. ICU's select type lets you branch on any string value — not just gender, but any category you define:

{gender, select, male{He liked your post} female{She liked your post} other{They liked your post}}

The other case is required and acts as the fallback. This is critical — if someone passes a value you didn't anticipate, the message still renders instead of crashing.

Nested Patterns and Selectordinal

ICU patterns can be nested. Need to combine gender and plurals in a single message? You can:

{gender, select, male{{count, plural, one{He bought # book} other{He bought # books}}} female{{count, plural, one{She bought # book} other{She bought # books}}} other{{count, plural, one{They bought # book} other{They bought # books}}}}

Yes, the nested curly braces get dense. This is exactly why a visual editor is so valuable — more on that in a moment.

ICU also supports selectordinal for ordinal numbers (1st, 2nd, 3rd, etc.):

{rank, selectordinal, one{#st place} two{#nd place} few{#rd place} other{#th place}}

This gives you proper ordinal suffixes that adapt per locale automatically.

Common Mistakes That Will Bite You

After working with thousands of ICU messages across projects, these are the errors we see most often:

  • Forgetting the other case — Every plural and select must have an other branch. Without it, your message will throw a runtime error when an unexpected value comes in.
  • Using wrong plural categories for a locale — English only needs one and other, but if you're writing Arabic messages without zero, two, few, and many, your translations will be grammatically wrong. Always check the CLDR plural rules for your target locale.
  • Mismatched curly braces — Nested patterns mean lots of { and }. One missing brace and the whole message breaks. Count them carefully, or better yet, use a visual tool that handles nesting for you.
  • Putting HTML or markup inside messages — While some libraries support rich text in ICU messages, mixing HTML with ICU syntax makes messages fragile and hard for translators to work with. Keep messages as plain text when possible.
  • Hardcoding locale-specific logic — Don't write custom plural logic per language. Let the ICU library and CLDR data handle it. That's the whole point.

Libraries That Use ICU Message Format

ICU Message Format isn't a niche standard — it's the default in many of the most popular i18n libraries:

  • React Intl / FormatJS — The go-to i18n solution for React apps. All message strings use ICU syntax natively.
  • messageformat.js — A standalone JS library for compiling ICU messages. Works with any framework or vanilla JS.
  • ICU4J / ICU4C — The original C++ and Java implementations from the ICU project. Used by Android, iOS, and countless backend services.
  • @nuxtjs/i18n and vue-i18n — Vue's i18n ecosystem supports ICU-style messages through linked message syntax and third-party integrations.
  • php-intl / Symfony Translation — PHP's intl extension and Symfony's translation component both support ICU message patterns.

If your project uses any of these, you're already working with ICU format whether you realize it or not.

Why a Visual Editor Beats Hand-Writing ICU Syntax

Let's be honest: writing complex ICU messages by hand is painful. Nested plural-inside-select patterns with four gender options and six plural categories? That's a wall of curly braces that no human should have to parse visually.

A visual ICU editor lets you build messages by selecting pattern types, adding branches, and filling in the text for each case. You see the structure as a tree instead of a flat string. You can test with different variable values and instantly see which branch gets selected. And you never have to count curly braces again.

This is especially valuable for teams where translators need to work with ICU messages but aren't developers. A visual editor makes the format accessible to everyone on the team, not just the engineers who set it up.


ICU Message Format is one of those tools that seems intimidating at first but becomes second nature once you understand the pattern. Start with simple variable substitution, add plural rules as your app grows, and reach for select and nested patterns when your content demands it. The syntax is consistent, the libraries are mature, and the CLDR data backing it covers every locale you'll ever need.

Don't hand-write complex ICU messages from scratch. Use a tool that shows you the structure, validates your syntax, and lets you test with real data.

Try Glot's ICU Editor

Build, test, and validate ICU Message Format patterns visually — no more counting curly braces by hand.

Try Glot's ICU Editor