Last reviewed: 4 October 2026
Short answer
ICU MessageFormat describes a complete message together with runtime arguments and conditional wording. For localization, preserve argument names and syntax while allowing the translated sentence and relevant branches to follow the target language. Agree on the exact formatter implementation, then test the messages with real values. A translation can sound natural yet fail when a different count or customer category selects an unreviewed branch.
Key takeaways
- Translate complete messages rather than assembled fragments.
- Document each variable's meaning and expected type.
- Distinguish an exact number from a grammatical category.
- Keep a useful fallback branch for unfamiliar values.
- Review Vietnamese cardinal and ordinal behavior separately.
- Test the selected message before approving the screen.

What does the pattern actually control?
A message pattern describes text and arguments in braces. ICU's MessageFormat API permits arguments to move within the message, supporting different sentence structures.[1] Consider Thanks, {name}. and Cảm ơn {name}.: the name comes from application data, while the surrounding sentence belongs to the language resource.
The following examples concern the established ICU MessageFormat pattern syntax used by the tested FormatJS library. They are not a migration guide for another message language. Tell a vendor which parser and version will read the files; a product label saying “ICU support” is insufficient to establish compatibility with every formatting option.
For a quotation portal, resource ownership should be clear. Engineering owns the argument contract and runtime values. The content owner confirms the business meaning. A Vietnamese reviewer adapts the wording. QA checks the rendered outcome. Asking one person to infer all four responsibilities from a raw string creates avoidable rework.
How should a translator treat arguments?
Suppose name is the customer-provided display name, not necessarily a first name. Provide that context beside the message. Otherwise an apparently friendly rewrite might assume a title, gender or form of address that the application cannot justify.
Our proposed handoff matrix is a practical starting point, not a standard imposed by ICU.
| Message requirement | Pattern element | Information for the translator | Acceptance decision |
|---|---|---|---|
| Address a customer | {name} | Display name; may include spaces and accents | Do not rename the argument or infer gender |
| Show attached files | {count, plural, ...} | Nonnegative integer; count of accepted files | Wording matches accepted, not merely selected, files |
| Distinguish company requests | {audience, select, ...} | Application category, not a guessed identity | Unknown categories get appropriate generic text |
| Show request sequence | {position, selectordinal, ...} | Positive integer in one customer's sequence | Ordinal wording makes sense in the chosen language |
| Display a supplied number | {count, number} | Numeric value and intended unit | Locale formatting does not change the unit |
| Mention an example token | Quoted braces | Literal teaching example, not customer data | Braces remain visible in the final message |
Protect names such as count, position and audience. Translate the visible text within the agreed syntax. If a different argument is necessary, raise a resource-contract change rather than silently inventing it in the translated file.
Also document empty and unusually long values. A name containing accents, an organization name spanning several words, and an omitted optional name should each have an intentional outcome. The formatter should not be responsible for deciding whether a missing customer name is legally or commercially required.
When should you use plural and an exact-number branch?
FormatJS distinguishes locale-based plural categories from exact selectors such as =0; it also requires an other branch for the plural construct.[2] Use an exact zero case when the product needs a different message for an empty state.
Here is an original English attachment message:
{count, plural, =0 {No files attached.} one {# file attached.} other {# files attached.}}
The Vietnamese counterpart is:
{count, plural, =0 {Chưa đính kèm tệp.} other {Đã đính kèm # tệp.}}
With the tested formatter, English values zero, one and three produce “No files attached.”, “1 file attached.” and “3 files attached.” Vietnamese produces “Chưa đính kèm tệp.”, “Đã đính kèm 1 tệp.” and “Đã đính kèm 3 tệp.” These are results of the original examples, not quotations from documentation.
CLDR 48 lists Vietnamese cardinal numbers under other, but Vietnamese ordinal rules also include one for one.[3] Therefore, “Vietnamese has only other” is too broad unless the statement explicitly concerns cardinal plural selection. Do not copy every English branch into Vietnamese merely to make resource files look symmetrical.
The zero message here describes an attachment state, not a promise about upload success. In a real form, use the count the backend has accepted. A selected file that failed validation should not appear in the success message simply because its name was visible earlier.
How does select express business context?
Use a selector for a defined application category when that category changes the complete message. Our example uses business, with a generic fallback:
{audience, select, business {Your company request is ready for review.} other {Your request is ready for review.}}
A matching Vietnamese message is:
{audience, select, business {Yêu cầu của doanh nghiệp đã sẵn sàng để xem xét.} other {Yêu cầu của bạn đã sẵn sàng để xem xét.}}
Keep business unchanged when that is the value application code supplies. Translating it to doanhnghiep would change the contract, even though the visible Vietnamese sentence remains reasonable. An unrecognized value should reach the generic text in this example.
That fallback is not a replacement for data validation. If an impossible category indicates a programming error, record the error while presenting a suitable customer message. Avoid turning every unexpected value into a sales claim or an unsupported description of the customer's account.
Where do ordinal messages differ?
A request counter may need English wording such as “This is your 21st request.” Our original pattern is:
This is your {position, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} request.
For Vietnamese, a deliberate wording choice can be:
{position, selectordinal, one {Đây là yêu cầu thứ nhất của bạn.} other {Đây là yêu cầu thứ {position, number} của bạn.}}
The tested English examples include 1st, 2nd, 3rd, 11th, 12th, 13th and 21st. The Vietnamese examples include “thứ nhất”, “thứ 2” and “thứ 21”. A team can instead prefer numeric wording for every Vietnamese position; that is an editorial decision to document consistently.
Do not apply this pattern to an arbitrary identifier. A request numbered Q-104 is an identifier, not necessarily a customer's 104th request. A linguistically correct ordinal can still communicate the wrong product fact if the input field has been misunderstood.
How much nesting is useful?
A company-specific attachment sentence can combine a category and a count:
{audience, select, business {{count, plural, one {Your company attached # file.} other {Your company attached # files.}}} other {{count, plural, one {You attached # file.} other {You attached # files.}}}}
A simpler Vietnamese counterpart preserves both runtime arguments without needing separate cardinal branches:
{audience, select, business {Doanh nghiệp đã đính kèm {count, number} tệp.} other {Bạn đã đính kèm {count, number} tệp.}}
Keeping the whole conditional message visible helps a reviewer understand the output. ICU's guide recommends complete submessages and discusses placing a fixed-choice selector outside a nested plural.[4] For our own handoff process, add one screenshot and one expected output for each meaningful customer state.
Avoid nesting unrelated business rules merely because the syntax permits it. If payment state, account type, file count and approval status all enter one pattern, review becomes harder. Separate messages by genuine screen state when that produces clearer ownership and acceptance tests.

What do escaping and offsets require?
To show literal braces in a teaching message, the tested pattern Enter '{name}' as the example token. outputs Enter {name} as the example token. without requiring a name value. ICU exposes apostrophe-mode controls in its MessagePattern API, so record the actual parsing behavior rather than applying a blind apostrophe replacement.[5]
Quoting message syntax is separate from safe HTML rendering. Decide how the application renders user-supplied values and review that boundary with engineering. A name inserted into a message must not become executable markup because a resource was described as properly escaped.
Offsets need equally explicit context. This original example counts all reviewers, including the addressed customer:
{count, plural, offset:1 =0 {No reviewers assigned.} =1 {You are the only reviewer.} one {You and one other reviewer.} other {You and # other reviewers.}}
For a total of four, our tested result is “You and 3 other reviewers.” The offset is intentional subtraction, not a translation shortcut. The exact cases refer to the original count; the plural-category decision and # use the adjusted count. Preserve that meaning when adapting the wording, and reject this example if the actual system counts only other reviewers.
Which release checks catch useful failures?
We executed 30 local assertions using intl-messageformat 12.1.2 on Node 24.18.0. FormatJS documents the formatter's dependence on JavaScript Intl services.[6] Our checks validate these example patterns; they do not establish browser layout, mobile behavior or compatibility with ICU4J.
| Test family | Inputs or mutation | Expected evidence | Release owner |
|---|---|---|---|
| Basic variable | Name Lan in both languages | Correct complete greeting | Language reviewer |
| Cardinal states | Counts 0, 1 and 3 | Empty state and quantity text | Product and QA |
| Ordinal boundaries | English 1, 2, 3, 11, 12, 13, 21 | Correct tested suffixes | Engineering |
| Vietnamese ordinals | Positions 1, 2 and 21 | Agreed Vietnamese sequence wording | Language reviewer |
| Unknown category | Unrecognized audience | Generic fallback selected | Product owner |
| Nested condition | Business audience, three files | Full company-specific sentence | QA |
| Literal syntax | Quoted {name} without input | Visible braces, no variable lookup | Engineering |
| Offset semantics | Total counts 0, 1, 2 and 4 | Addressed reviewer counted correctly | Product and QA |
| Missing argument | Greeting without name | Error caught before release | Engineering |
| Missing fallback | Plural pattern without other | Invalid resource rejected | Engineering |
Run resource validation after translation import, not only before sending the English file out. Test the final artifact that ships. Then inspect representative screens with long values, narrow viewports and actual Vietnamese fonts. Automated formatting checks and visual language QA solve different problems.
FAQ
Must every English branch appear in Vietnamese?
No. Preserve required runtime meaning and valid target-language structure. Some English cardinal branches are unnecessary in Vietnamese, while a business-specific exact-number message may still be useful.
Can a translator change an argument name?
Only through an agreed application change. A name that looks technical may still be the exact key supplied at runtime. Keep an argument inventory with the translation brief.
Is an exact zero branch always required?
No. Add it when the product needs distinct zero-state wording. A generic quantity sentence may be acceptable if it communicates the state clearly.
Does select determine the customer's gender?
No. It selects among supplied values. Avoid inferring gender or titles from a customer's name; choose neutral wording when the product lacks reliable context.
Will an ICU-compatible library accept every ICU option?
Do not assume so. Validate the constructs, skeletons and runtime capabilities your application uses against its actual library and version.
What should we send for a localization quotation?
Provide resource samples, formatter details, supported locales, argument notes and screenshots. Add the release deadline and tell us which messages affect a critical customer action.
Sources and methodology
Official ICU, CLDR and FormatJS material supports the syntax and locale distinctions cited above. Patterns, ownership tables and release recommendations are original examples for a hypothetical quotation workflow. Thirty local checks cover selected formatting and error cases. No customer deployment, cross-browser interface or ICU4J runtime was tested for this article.
References
[1] Unicode ICU — MessageFormat API, patterns and argument ordering. [2] FormatJS — ICU Message Syntax, selectors and plural arguments. [3] Unicode CLDR 48 — Language Plural Rules, Vietnamese cardinal and ordinal entries. [4] Unicode ICU — Formatting Messages, complete and nested messages. [5] Unicode ICU — MessagePattern API, apostrophe modes and pattern parsing. [6] FormatJS — Intl MessageFormat, runtime requirements and formatter API.
Plan a resource review
Send a representative resource file through our quotation form or discuss scope on the contact page. Our software localization service can help align wording, resource contracts and language QA before your next release.
Related guides
- JSON Localization Guide: Strings, Variables and Common Mistakes
- XLIFF vs JSON vs PO vs ARB: Localization File Formats Compared
- XLIFF Localization Guide for Developers and Localization Managers
- Flutter Localization with ARB: A Practical Guide
- i18next Localization Best Practices for Production Apps
- Vietnamese Localization Style Guide for Software and SaaS
