VIEW THIS AS

Auto mode follows the Route Engine until you choose a viewpoint.

YOU ARE HERE

ROUTE CHECK

CONNECTED TO

WHAT NEXT

Use the canonical route for this room, or HELP if you are unsure.

How People Translate Quickly | Unicode MessageFormat 2 Migration QA: Move Dynamic Messages Without Losing Meaning or Fallbacks

To migrate translations to Unicode MessageFormat 2 quickly, treat every existing message as a small executable decision rather than a sentence that only needs rewriting. Preserve the external variables supplied by the application, identify which expressions select variants, rebuild those decisions using the actual MF2 grammar, and verify output for real values in every supported language. A translation is finished only when the new formatter produces the right text for zero, one, two, large numbers, missing values and the application’s documented error behaviour.

This guide tackles the practical job of upgrading a bilingual educational application from a previous ICU-style message system to MF2. The user sees lesson booking confirmations, attendance alerts, payment reminders and classroom feedback. Each contains a combination of human language and code-driven choices. Our goal is not to translate braces or copy plural rules blindly. It is to keep a learner’s understanding, a parent’s next action and the application’s data contract intact while the message technology changes.

MessageFormat 2 is specified in Unicode Technical Standard 35, Part 9. Its input declarations, local declarations, matchers, placeholders and markup are not a drop-in textual replacement for every legacy ICU MessageFormat string. A library supporting one syntax may reject the other, and target languages may require different variants. The safest approach combines a message inventory, parser checks, translation review and runtime rendering. The examples here are teaching specimens; a product release also needs tests against its exact formatter implementation and version.

The real translation problem is behavioural equivalence

A school application shows “You have 1 lesson” or “You have 4 lessons.” Parents do not care which expression engine generated those sentences. They care whether the number and noun agree, whether the statement describes booked lessons rather than completed lessons, and whether the app has accidentally promised something it cannot provide. During a migration, programmers may focus on converting symbols while translators focus on idiomatic wording. Neither role alone can establish that the behaviour remained equivalent.

Define the unit of work as one message identifier plus its argument schema and all possible outputs. For upcoming_lessons, that means knowing whether $count is an integer, whether a negative value can be passed, whether zero is a special empty-state instruction, and whether the user can switch locale after the message has been cached. Record each answer before editing the sentence. Without a schema, a fluent target sentence may describe the wrong underlying state.

Write a simple acceptance rule: for every supported locale and every representative set of inputs, the rendered message must state the same product fact and request the same safe action as the approved source. This rule permits natural word order and language-specific plural categories, but rejects a translation that changes “scheduled” to “attended,” hides a balance, or converts an unavailable appointment into an invitation to confirm. The end user must receive faithful meaning, not merely syntactically valid output.

Audit the old formatter before planning a new one

The phrase “ICU message” can conceal distinct production arrangements. One system may store classic apostrophe-sensitive ICU patterns in a JSON catalogue, another may use framework-specific wrappers, and a third may interpolate strings before applying plural selection. Even when their examples look alike, the parser, escaping conventions and error recovery may differ. Capture the package names and versions, original message keys, template strings, and a small execution trace from the existing system. Do not infer behaviour from punctuation alone.

For each legacy message, identify static text, variables, formatters, plural selectors, gender or state selectors, nested branches, rich-text tags and fallback strings. Ask whether formatting occurs in a server process, browser, mobile app or email generation service. A currency or date can appear correct on a developer machine but wrong after a server locale changes. Store approved baseline outputs for representative inputs so the migration has something independent to compare with the newly authored MF2 messages.

Inventory the workflow rather than a random hundred strings. Start with account creation, lesson registration, timetable changes, payments, cancellations and safety-critical notices. Mark which outputs affect a real action: a parent may make a payment, release a booking, call a tutor or ignore a warning based on a short sentence. Migrate these high-consequence messages first in a pilot release. Lower-risk decorative strings can then reuse lessons learned about variables, translators’ tooling, line length and the team’s review process.

Read MF2 syntax as a contract, not as decoration

A simple MF2 pattern may contain a placeholder such as {$student} inside ordinary prose. The braces and variable name are instructions to the formatter, while the surrounding words are available for translation. A complex MF2 message can declare input processing with .input, create local values with .local, and select a variant with .match. The selected variant is a quoted pattern delimited by double braces. Translators need to recognize these boundaries even when they will not write them from memory.

A declaration is not a sentence that happens to start with a dot. It describes how the formatter should obtain or transform a value. Renaming $count in a translated catalogue without updating the application arguments is a contract change, not localization. Likewise, changing :number to a translated function name may create a data-model error. Mark variables, function names, option keys, matcher syntax and the application’s markup names as protected tokens in the translation brief.

Some text inside a quoted literal can be user-facing, depending on the developer’s purpose. Never impose a universal rule that everything between vertical bars is untouchable. In one message, |2-digit| is an option value and must remain stable; in another, |Welcome back| could be a literal intended for display. The developer should tag the intended role and explain whether that literal is a grammatical sample, an internal enum or content. Translation speed increases when such ambiguity is resolved before assignment.

Build an executable baseline with a modest example

The following MF2 teaching example selects singular and fallback messages for an upcoming lesson count. The wildcard is part of the branch structure, not a license to ignore other target-language categories. A real project can add variants according to supported locale rules and product requirements. The example should be run through an MF2-compatible parser; ordinary JSON validation or a legacy ICU parser would not test its syntax.

.input {$count :number}
.match $count
0   {{No lessons are scheduled.}}
one {{You have {$count} lesson scheduled.}}
*   {{You have {$count} lessons scheduled.}}

For an input of zero, the explicit numeric key produces an empty-state sentence. For one, the singular category is selected when the locale’s rules support it. Other values use the wildcard, while target languages may require specific few, many or other variants for natural output. This does not mean every language must use exactly the same branch layout. It means the team must document intended outputs and test the formatter’s matching rules rather than assume English plural categories are universal.

A migration worksheet should contain the old template, the old rendered outputs, the new MF2 template, its new outputs, the target-language translation, the risk level and the person who approved the comparison. Keep the expected text separate from program execution results; otherwise a broken formatter can update the expected answer automatically and make the test meaningless. Include whether the output is intended for screen readers, push notifications or email, because those contexts have different punctuation and truncation risks.

Distinguish translation from rewriting the input schema

Suppose the application passes a decimal $balance and a string $currency. A translator can rearrange the sentence so that a currency expression appears naturally, but cannot silently change the type of $balance from a numeric value to a formatted English string. If developers preformat the balance in one locale before passing it to the target formatter, the result may show the wrong separators or duplicate currency symbols. The translation process needs typed inputs where the formatter’s supported functions can do locale-specific work.

Inspect the message’s argument schema, including names, types, nullability, units and semantic meaning. Record whether $dueDate is an instant, local date or already formatted text. A local date such as a school deadline is not necessarily a universal instant, while an appointment timestamp generally needs a known time zone. The translator should not be forced to repair a missing time-zone definition through words. Send contract defects to engineering and keep them separate from genuine target-language issues.

Watch for variables embedded in larger words or endings. In some languages, the grammar around a person’s name, amount or lesson count may depend on properties the application has not provided. The correct repair may be to change the message design, choose a neutral expression, or introduce a properly specified selector rather than ask a translator to guess. Record the decision in an accessible note so a later maintainer does not reintroduce the original assumption during another migration.

Treat number categories as linguistic behaviour

English singular and plural are a useful first demonstration but a poor universal design. Other languages classify numbers with categories that differ from English; some require forms for a few or many, while others use a general form regardless of count. The MF2 matcher should support the actual target language and its number-function behaviour. Translators should not be asked to fill an English two-column plural spreadsheet when the target language needs a different grammatical distinction.

Create a category matrix using the CLDR rules for the chosen locales. Test values that exercise every relevant category, along with explicit values such as zero if the product uses zero as an empty state. Test decimals when the application may pass them; a count of completed lessons is probably integral, but an estimated duration could be fractional. Keep the product’s numeric domain separate from the language’s grammatical possibilities, so invented test values do not create nonsensical real-world promises.

Review what the message means at zero. “You have zero absences” may be mathematically true but less encouraging than “No absences recorded.” Conversely, “You have no payment due” might be false if the system is still processing charges. The engineer must clarify the state transition, and the language reviewer must preserve it. An explicit zero branch is an editorial product choice; the wildcard ensures a fallback branch exists for unmatched selector values. Those two purposes should not be confused.

Migrate selections in stages, not in bulk guesswork

Start by converting a small message with one argument. Compare the old and new output for each relevant value, review the syntax with an MF2 implementation, and release the string only after the comparison is documented. Then migrate a message with a number selector, followed by a message with two independent selectors. This sequence reveals tooling issues before they reach complex templates where a single missing wildcard can make many outputs fail.

A script can identify likely legacy constructs, but a search-and-replace transformation is not a proof of equivalence. Legacy nested plural expressions may have a different selection order, quoting convention and fallback behaviour. When conversion changes the expression tree, record the intended meaning before changing implementation. A translator may see only rendered sentences, yet the engineer must verify that each possible branch has been carried across. Use the old output corpus as a reference, not as unchallengeable truth when it contained known mistakes.

Keep one version-controlled change per message family and attach input-output fixtures. A message family might consist of a short notification title, full in-app explanation and accessible announcement about the same lesson cancellation. These should agree semantically even though their lengths and punctuation differ. Migrate them together because one surviving legacy string in a mixed interface can create a visible contradiction. If the application supports staged rollout, include a straightforward rollback to the old engine while preserving user data.

Preserve the meaning of times, dates and currencies

A date placeholder can represent the day a lesson begins, the deadline for payment or the moment a server recorded a status update. Those are not interchangeable. When converting a template, verify the runtime type and locale-sensitive function settings before translating nearby words. A translated sentence that formats a server timestamp as a local classroom date may produce a different day around midnight. Word choice cannot fix a time-zone bug.

Test a Singapore school event close to midnight with a user viewing the schedule from another time zone. Decide whether the displayed time is the school’s local time or the viewer’s local time and explain that choice when necessary. Check daylight-saving transitions in relevant viewer locales; Singapore does not observe those changes, but international parents may. If the template refers to a school day rather than a precise instant, do not invent an offset. The message must be backed by the system’s scheduling model.

For payments, preserve the numerical amount, currency code and any tax or refund conditions. An MF2 translation might change the order in which the amount and label appear, but should not convert an SGD balance into a claim about another currency. If the application’s rules require a currency conversion, that is a separate documented calculation with an exchange rate and date. Keep financial validation outside the language file and test the exact final display where parents make decisions.

Inspect declarations, scope and duplicate names

A local declaration creates a value for use later in a complex message. The standard constrains how variables can be declared and reused; invalid redeclarations can produce data-model errors. Copying an old message fragment into a new one may accidentally declare the same variable twice, even if the visible text looks correct. A reviewer who has never seen .local may translate the literal words but overlook a variable collision that prevents the entire message from rendering.

Use a parser or implementation that reports syntax and data-model errors rather than a hand-built brace counter. A brace counter can detect an obvious imbalance but cannot establish whether a matcher is valid, whether declarations satisfy scope rules, or whether the chosen functions are supported by the runtime. Record the implementation version and any custom functions. If your product depends on extensions, show translators examples from your actual integration rather than claiming every compliant MF2 processor has identical capabilities.

An effective error report includes the message identifier, locale, source revision, parser version, offending expression and a minimal input set that reproduces the problem. Avoid storing real student names, phone numbers or payment details in fixtures. Synthetic strings can exercise long names, combined scripts and unusual punctuation without exposing personal information. Privacy-safe test data makes it easier to share evidence with vendors, translation reviewers and developers who do not need access to production accounts.

Understand markup without turning code into prose

MF2 supports markup markers, but it does not assign universal rendering semantics to every marker name. The application decides how a marker such as {#strong} is interpreted in a rich-text view. A translator should preserve the marker’s technical identity while moving the enclosed phrase where grammar requires it. The visible emphasis may be important because it distinguishes the deadline from explanatory text, yet moving a marker is different from renaming it to a translated word.

In a lesson reminder, bold emphasis around “Friday at 5 pm” helps a busy parent find the action deadline. In a target language the date expression may appear earlier in the sentence. A correct translation can move the emphasis boundaries so the same fact remains prominent. However, it should not swallow surrounding punctuation or accidentally emphasize the teacher’s name instead. Rendering tests need to inspect final text and emphasis placement in the actual application component.

Do not assume markup is safe HTML. The renderer maps marker names to components or formatting rules, and the translation string may contain characters that need escaping in the destination environment. Test the output for injection-like text, literal braces and bidirectional text handling. A text-only preview can miss these failures. Where an assistive reader receives a simplified or spoken rendering, verify that the emphasized instruction remains intelligible when style cues are absent.

Plan for bidirectional and mixed-script output

A parent may read an Arabic message containing a Latin-script student identifier, a number and a URL. Logical character order, visual placement and cursor movement are different concerns. The MF2 syntax has mechanisms and guidance relevant to bidirectional contexts, but the application still needs correct paragraph direction and safe interpolation rendering. Translators should not insert invisible direction controls at random to make one screenshot appear right.

Test a concrete message containing an Arabic sentence, the identifier SEC1-A, the amount S$48.00 and a short web address. Inspect it in the real browser or app using the intended locale. Check that the identifier is copied accurately, the amount remains the right amount, and the clickable URL points to the approved destination. A string that appears tidy in an editor can reorder punctuation or adjacent tokens when the actual component applies directionality.

Provide the translator with a preview that can switch paragraph direction, text length and sample argument values. Capture a screenshot and copyable plain text for review. If the runtime wraps placeholders with isolation mechanisms, understand and document them; avoid forcing the translator to simulate isolation through manual characters that later survive into emails. The objective is predictable reading and reliable copying, not pixel-perfect correspondence with the original English ordering.

Define fallback as a product decision

The wildcard variant * ensures a matching alternative exists in a matcher, but it is not the same thing as a missing-locale fallback. A runtime may choose a default language when a catalogue key is absent, use a last-resort message when formatting fails, or throw an error. These are separate behaviours that need different tests. If a child’s class cancellation is shown in English because a translated key was omitted, the product may be technically operational but still fail its accessibility promise.

Document at least three fallbacks: unmatched selector value, missing target translation, and formatter failure. For each, decide what the user sees and what the system logs. A silent empty string is seldom an acceptable fallback for a button controlling payment or registration. A clear approved default-language notice may be safer than a broken translated command, but whether that choice meets the product’s requirements depends on audience and context. Make the policy explicit and test it.

A late migration can be especially risky when some clients use the old formatter and others use MF2. Do not deliver MF2 syntax to a device that still runs an incompatible parser. Version the catalogue or negotiate capabilities, and maintain a release matrix showing the required app version for each message format. The language team needs that information because one translator’s correct new file may be unusable for a learner with an older installation.

Find defects through adversarial but realistic fixtures

Build test inputs around mistakes that have harmed actual localization projects: zero counts, very large counts, missing dates, unexpected selector values, extremely long names, Unicode combining marks, right-to-left punctuation and unrecognized custom functions. The purpose is not to invent impossible school states. It is to discover whether a failure appears as an honest error, a misleading sentence or a vanished instruction. Prioritize tests where the consequence is a wrong action rather than awkward typography.

For the attendance notice, test a student with one absence, zero absences and a count larger than the UI designer expected. Verify whether the resulting message means absences recorded or lessons missed. For a booking message, test a cancelled session and a session awaiting confirmation; count-based text alone may not convey the difference. For a fee reminder, test an amount with minor currency units and a user locale that uses different separators. These fixtures exercise meaning and rendering simultaneously.

Record failures with a reproducible chain: input fixture, locale, message key, rendered result, expected meaning, and relevant screenshot or log. Label each defect as parser syntax, data model, missing contract, language semantics, localization data, rendering layout or product logic. This classification prevents a linguist from being asked to rewrite a string when the formatter never received the right argument. Re-run the full fixture set after each repair, not only the single example that originally failed.

Diagnose a plural regression without guessing

Imagine a translated notice that correctly says “one assignment remains” for one task but produces “two assignment remains” for two tasks. The visible grammar error is a symptom; the cause might be missing variants, the wrong numeric type, an incorrect selector function, or a stale catalogue. First inspect the exact MF2 message used at runtime. Then run it under the chosen locale with one and two and compare the returned branch. Do not start by editing nouns in the source text.

If the wrong variant was selected, check declaration and matcher definitions against the official syntax and the target locale’s plural categories. If the right variant was selected but contains the wrong noun form, correct the translation and add a regression fixture. If the preview looks correct but production fails, compare library versions, cache keys and locale negotiation. Those diagnoses lead to different repairs and ownership assignments, making the team faster than a cycle of random copy edits.

After a fix, inspect four layers independently: parser acceptance, variant selection, rendered sentence and end-user action. A message can pass the first three and still instruct parents to visit the wrong page. Conversely, a correct business instruction can be wrapped in a pattern that silently falls back for certain values. The release record should state which layers were tested and which assumptions still depend on the application’s own integration tests.

Handle translator feedback as structured engineering evidence

Translators often discover that a perfectly valid source sentence cannot be translated naturally with the variables supplied. Give them a way to flag “needs selector,” “term ambiguous,” “source state unclear” or “placeholder position unsafe” rather than forcing a yes-or-no acceptance. Each flag should include an example of the target-language problem, the user context, and the minimum contract change required. That is actionable engineering evidence, not resistance to translation.

Suppose a message says “{$teacher} has updated their timetable.” In a language requiring grammatical distinctions not available from the teacher field, the translator may recommend a neutral construction or a differently structured message. If neutral wording loses no important information, it may be the simplest safe choice. If the application promises a personalized form, then additional agreed data may be necessary. Never infer protected personal attributes from a person’s name merely to satisfy grammar.

Once the team resolves a flag, update the message brief, fixtures and terminology notes. A fix made only in a conversation will be lost when another language is added. Preserve the reasoning behind choices such as using “scheduled lesson” instead of “confirmed lesson,” or showing the literal currency code near a price. These decisions become reusable teaching material for future translation work and reduce repetitive disputes during release review.

Compare old and new engines at the boundary

A migration shadow test can format the same synthetic inputs using both old and new systems and compare normalized meaning, not only character-for-character equality. Expected legitimate differences include word order, number separators and target-language plural constructions. Unexpected differences include an omitted cancellation condition, a date shifted to another day and a branch that cannot be reached. Keep a human reviewer in the loop for semantic comparisons where automated equality would reject valid translations.

For numeric outputs, log the input value and formatted text separately. For dates, record the source temporal type and intended display zone. For names, preserve the input unchanged even if surrounding words move. Build a small audit dashboard showing which message keys failed syntax checks, missed expected branch coverage or received unresolved translator comments. This is an engineering dashboard, not a public ranking of translators; the purpose is to direct review time to messages most likely to mislead users.

When releasing in stages, keep old and new catalogues from drifting. If the source meaning changes midway through the migration, mark a new semantic revision and have both implementations updated or explicitly retire the old path. A stale translation is not improved by flawless MF2 syntax. Version tracking matters because a parent’s action may depend on terms changed by policy, timetable rules or payment arrangements after the migration began.

Test educational comprehension rather than only appearance

Ask a student, parent or tutor representative to interpret a message without seeing the source. For a lesson change, they should identify what changed, which session is affected and what they should do next. For homework feedback, they should distinguish a suggestion to revise from a statement that a submission was rejected. For payment text, they should recognize the amount and deadline without assuming a charge has already occurred. These small comprehension probes can catch errors that language fluency reviews miss.

Avoid pressuring testers to agree that a sentence is understandable. Show alternative outputs in the natural target language and ask them to explain the practical consequence. If they disagree, look for missing context in the product message rather than immediately declaring one person unskilled. Test with longer names, different educational levels and users who rely on screen readers. A translation that works only for staff who know the hidden business rules is not ready for a public interface.

Release review should also inspect the nearby interface. A translated notification title might be accurate while its button says “Cancel” when the action actually confirms attendance. A plural branch may match correctly but display in a card with a hard-coded English status. Scope the QA around the user’s complete task, including button label, destination, fallback, and accessible announcement. The message is one component of an instruction system, not a detached paragraph.

A changed-context transfer exercise with a worked answer

Consider a school library application migrating a due-date notice. It must tell a borrower how many items are overdue. A junior engineer converts an old plural pattern into an MF2 message that has only a singular branch and a wildcard. A translator notices that one target language needs additional categories and that the word for “item” might mean “library book” rather than any borrowed device. The app also passes the due date as a preformatted English string. Your task is to decide what to protect, what to change and what to test.

A safe answer begins by protecting the message identifier and runtime argument names while documenting their types. Ask the product owner whether the count includes devices and books; choose a neutral term or a specified category accordingly. Replace the preformatted date with an agreed temporal value plus appropriate formatting rules. Add the target language’s needed matcher variants and retain a wildcard. Build fixtures for zero, one, two, several, a large count and a due date near midnight; then review the rendered instruction in context.

The expected outcome is not the same visible branch count in all languages. It is the same library fact and fair user action, expressed with each language’s grammatical resources. A final check should verify that the user’s borrowed items were not actually changed by the migration, the overdue state is computed from the correct clock and the message directs readers to the appropriate return policy. This transfer demonstrates the broader idea: changing text technology must not quietly change the business reality that text communicates.

Practical review checklist for an MF2 migration

Before marking a message approved, confirm its source revision, renderer/library version, argument schema, supported locales and fallback policy. Check that declarations and matchers parse, functions exist in the chosen runtime, and all required variants render with representative data. Read the resulting natural-language sentence with values inserted rather than approving a template in isolation. Reopen issues for missing context, incompatible clients and words that change a product promise. These checks can be recorded as reproducible fixtures rather than memory.

Also inspect the surrounding screen: button actions, accessible labels, truncation, mixed-script rendering, currencies, dates and names. Test a missing translation and parser failure deliberately so the fallback is known. Record who verified grammar, who verified the data contract and who tested the user action. A small pilot with high-consequence messages is more reliable than a wholesale conversion that reports success because a file compiled. The best outcome is a simpler, testable translation workflow for the next language.

Limits and what this guide does not certify

MF2 is a specification, while implementations differ in release maturity, custom functions, integration frameworks and supported tooling. An example that follows the documented syntax still needs testing against the version deployed by the application. Static brace checks, JSON validation and screenshot review cannot substitute for parser validation and real formatter execution. This article does not supply a universal converter between every historical ICU syntax and MF2 or promise that code from one language binding is portable without adjustment.

The examples use synthetic school messages rather than real user data. They do not establish compliance with privacy, payments or education regulations. A technical lead should verify the latest implementation guidance and security boundaries before an actual rollout. The narrow lesson is durable: preserve variables and decisions, adapt grammar intentionally, test representative values and inspect real user meaning. Translation becomes faster when ambiguity and failure are made visible instead of being concealed behind polished sentences.

Summary: make the new format earn the same trust

A good MF2 migration gives translators more structured freedom while giving developers better ways to validate dynamic messages. Start with an inventory and old outputs, protect the argument contract, author the new pattern under the official grammar, add necessary target-language variants, and test its rendered behaviour. Treat missing locales, parser errors and product-specific claims as explicit risks. The reward is not merely a modern-looking catalogue; it is a message system that can explain the right lesson, amount, time and next action to each reader.

Frequently asked questions

Is MessageFormat 2 simply a different name for ICU MessageFormat?

No. MF2 has its own syntax and processing model. A conversion requires inspecting the original engine and rebuilding equivalent decisions, not assuming identical parsing.

Why is a wildcard variant necessary?

The wildcard provides a fallback for selector combinations not otherwise matched. It does not replace missing-language fallback or the need for target-specific grammatical variants.

Can the translator rename $count to a target-language word?

Not without a matching application contract change. Variable names are technical identifiers supplied by the caller; translate surrounding human prose instead.

Must every target language have the same plural branches?

No. Relevant CLDR plural categories vary. Preserve the business meaning while using the target language’s needed variants and representative tests.

Can a legacy ICU message be converted by a regular expression?

Simple patterns can be candidates for automated conversion, but syntax, declarations, quoting and selection need a real parser and semantic review.

What should happen when a translation key is missing?

Follow a documented and tested product fallback, typically an approved understandable language or safe error state. A selector wildcard does not solve missing catalogue entries.

Do MF2 markup markers automatically become safe HTML?

No. The application defines what markers mean and how they render. Test the actual component and keep unsafe markup processing out of the translation catalogue.

How should we test a date that crosses midnight?

Specify whether it represents a local date or timestamp, document the display time zone, and test with user locales where the date may differ.

Should translator feedback change the application schema?

Sometimes. When natural grammar requires an absent distinction or a source message is ambiguous, engineering and product owners should review a scoped contract change or choose neutral wording.

What evidence is enough to sign off a migration?

Combine parser acceptance, branch fixtures, rendered target-language review, surrounding UI testing, explicit fallback checks and a recorded semantic owner. No single check is sufficient.

Authoritative sources and verification scope