ICU MessageFormat vs gettext Comparison
Compare ICU MessageFormat with GNU gettext for internationalization. Covers syntax differences, plural handling, tooling, and when to use each approach.
Detailed Explanation
ICU MessageFormat vs GNU gettext
ICU MessageFormat and GNU gettext are the two most widely used internationalization systems. Understanding their differences helps teams choose the right approach for their project.
Syntax Comparison
Simple string:
| Feature | ICU | gettext |
|---|---|---|
| Variable | Hello, {name} |
Hello, %s or Hello, %(name)s |
| Plural | {n, plural, one {# file} other {# files}} |
ngettext("1 file", "%d files", n) |
| Gender | {g, select, male {He} other {They}} |
Not supported natively |
Plural Handling
ICU embeds all plural forms in a single message:
{count, plural,
=0 {No messages}
one {# message}
other {# messages}
}
gettext uses separate function calls:
ngettext("One message", "%d messages", count)
For languages with more than 2 plural forms, gettext uses a Plural-Forms header in PO files:
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n>=2 && n<=4 ? 1 : 2);\n"
ICU's approach is more powerful because:
- All plural forms are visible in one place
- Categories are named (one, few, many, other) not numbered (0, 1, 2)
- Exact matches (=0, =1) are supported inline
- Nesting with select/selectordinal is possible
Gender and Select
ICU natively supports select for arbitrary categories:
{gender, select,
male {He replied.}
female {She replied.}
other {They replied.}
}
gettext has no built-in mechanism for this. Teams typically work around it with:
- Multiple message IDs (
reply_male,reply_female,reply_other) - Custom context functions
- Post-processing string templates
Tooling Ecosystem
| Aspect | ICU | gettext |
|---|---|---|
| File format | JSON, XLIFF, ARB | PO/POT (purpose-built) |
| Extraction | Library-specific CLI | xgettext (universal) |
| Translation tools | Crowdin, Lokalise, Phrase | Poedit, Weblate, Transifex |
| Runtime overhead | Parsing at runtime | Pre-compiled catalogs |
| Framework support | React, Angular, Vue, Java | C, Python, PHP, Ruby |
When to Use ICU
- Web applications (React, Angular, Vue) -- native library support
- Mobile apps (iOS, Android) -- platform ICU support
- Complex messages with plural + select combinations
- New projects starting fresh with i18n
When to Use gettext
- C/C++ applications -- deeply integrated
- Python/Django/Flask -- mature ecosystem
- PHP -- built-in gettext extension
- Existing projects already using PO files
- Simple messages without complex plural/select needs
Migration Path
Many teams start with gettext and migrate to ICU as their i18n needs grow. The migration typically involves:
- Converting PO files to JSON with ICU syntax
- Replacing printf-style placeholders with named arguments
- Converting ngettext calls to ICU plural
- Adding select for gender-aware messages
- Updating extraction and build tooling
Key Takeaway
ICU MessageFormat is the more modern and capable system, particularly for complex messages involving multiple variables, plural rules, and categorical selections. gettext remains a solid choice for projects in its native ecosystems (C, Python, PHP) with simpler i18n requirements.
Use Case
Engineering leads evaluating internationalization approaches for a new project, or teams considering migration from gettext to ICU MessageFormat for better plural and gender support.