skip to content

How does a framework resolve a message key against locale-specific bundles, and how do runtime values enter the message?

level: middleimportance: should knowfreq 58%

answer

  1. the key lives in code, the sentence does not
  2. narrowing lookup: region, language, default
  3. fallback is per key, not per bundle
  4. placeholders keep the sentence reorderable
  5. arguments formatted in the same resolved locale

basics

~20 s

Lookup narrows per key: the bundle for the full language-and-region locale, then the language-only bundle, then the default bundle. Runtime values are inserted through numbered or named placeholders and formatted in the same resolved locale.

solid answer

~50 s

A **message bundle** maps a stable key to display text, one bundle per locale, with the same keys across all of them. When the resolved locale is language-plus-region, lookup tries that bundle first, then the language-only bundle, then the default one - and crucially this fallback is evaluated **per key**, so a regional bundle can hold only the handful of entries that differ. Runtime values never get concatenated into the text; the stored message carries numbered or named **placeholders**, and the framework substitutes arguments at render time, formatting numbers and dates with the same resolved locale that chose the text. Languages order words differently and have different plural categories, so the whole sentence has to be one translatable unit. Frameworks differ on a total miss: some return the key, some raise - either way it must be detectable rather than silent.

go deeper

for a junior

Recall that code holds keys and bundles hold text, one bundle per locale. Know that values go into a message through placeholders rather than by joining strings together.

for a middle

Explain the narrowing lookup and that fallback happens per key, so a regional bundle holds only differences. Explain why the whole sentence must be one translatable unit with reorderable slots.

for a senior

Demonstrate that runtime fallback hides coverage gaps, and put a build-time key comparison plus a fallback counter in place. Watch for formatters reading a different locale from message lookup.

for a principal

Decide the translation contract: key naming and context for translators, what a total miss does, release gating on coverage, and how regional overlays stay thin instead of forking the whole key set.

## What a message bundle is A **message bundle** is a map from a stable **key** to a piece of display text, with one bundle per supported locale and the same key set across all of them. The code refers only to the key; the sentence lives in the bundle. That indirection is what makes a second language an added file rather than a rewrite, and it is why keys should be descriptive identifiers rather than the source-language sentence itself - using the sentence as the key means every copy edit silently invents a new key that no translation covers. ## How lookup narrows Given a resolved locale, lookup walks from most specific to least: 1. The bundle for the **fully qualified locale** - language plus region. 2. The bundle for the **language alone**. 3. The **default bundle** configured for the deployment. 4. A **miss**, if no bundle in the chain holds the key. The decisive property is that this is evaluated **per key, not per bundle**. A regional bundle is normally a thin overlay holding only the entries that genuinely differ from the language-level text; everything else falls through. A team that assumes fallback picks one bundle and stays there will duplicate every string into every regional file, and the copies drift. | step | what it holds in practice | typical size | |---|---|---| | language plus region | regional wording differences only | a few keys | | language | the bulk of the translated text | the full key set | | default bundle | the source language, complete | the full key set | | miss | nothing - handled by policy | none | ## Placeholders, not concatenation A message that has to include a value - a name, a count, an amount - stores the value's position as a **placeholder**, identified by number or by name, and the framework substitutes arguments when the message is rendered. Two rules follow, and both are about translation rather than about code style: - **The whole sentence is one unit.** Building text by joining translated fragments freezes the source language's word order. Translators routinely need the second argument ahead of the first, and a fragment has no grammatical context - the same word may need a different form depending on what surrounds it. - **Arguments are formatted in the resolved locale.** A number or date passed in already turned into text has been formatted by whatever locale that code used, usually the process default, and it will disagree with the sentence around it. Passing the raw value and letting the message formatter render it keeps one locale in charge of the whole output. Named or numbered slots also make the message **reorderable**: the translated string can reference the same arguments in any sequence. Positional-only substitution forces every language into the source language's order, which is the single most common cause of translations that are grammatical word by word and wrong as sentences. Count-dependent text needs more than a two-way singular-or-plural branch. Languages differ in how many plural categories they have, and some select on gender or case as well, so the selection has to live inside the message - one key whose stored text names the forms - rather than in an `if` statement in the handler. ## Handling a miss Frameworks differ here: some return the key itself as the rendered text, some raise an error, some emit a marker. Each is defensible at runtime, but none of them is a substitute for knowing about the gap beforehand. Per-key fallback is a **runtime safety net**, and it has a quiet failure mode: a page mostly in the user's language with two sentences in the default one, and nothing logged. The practical answer is a coverage check at build or release time - compare each bundle's key set against the default bundle's - plus a counter on fallbacks so the rate is visible after release. ## Operating the bundles - Bundles are usually **loaded once and cached**, since they change at release cadence, not per request; a reload path is useful in development and rarely worth the risk in production. - Keys benefit from **context for the translator**: a short comment or a naming convention that says where the string appears, because the same word is a noun in one place and a verb in another. - Escaping matters: text that legitimately contains the placeholder delimiter needs the documented escape, or substitution will mangle it. - Bundle lookup sits behind the same **resolved locale** as the rest of the response. If a formatter takes its own locale, the page can render text in one language and numbers in another - the giveaway that message lookup and value formatting are reading different sources.

  • Why do placeholders carry a number or a name instead of relying on their order in the sentence?
    Because translations reorder. The source language's argument order is not preserved, and a translator often needs the second value ahead of the first. Numbered or named slots let the translated string reference the same arguments in any sequence; positional-only substitution forces every language into one word order.
  • What is the risk of per-key fallback that silently reaches the default bundle?
    A half-translated page: most text in the user's language, isolated sentences in the default one, and nothing logged. The fallback is the right runtime behaviour, but it needs a coverage comparison at build or release time and a counter on fallback hits, so gaps surface before users find them.
  • Why is using the source-language sentence as the message key a problem?
    Every copy edit changes the key. The edited text has no translation under the new key, so it falls back to the default language while the old translations become orphans no report flags. Stable descriptive keys decouple wording changes from translation coverage.

saying these in an interview costs you the question

  • Builds a sentence by joining translated fragments in source-language word order.
  • Thinks a key missing from one bundle means no message can be produced.
  • Formats a number or date before passing it in, using the process default locale.
  • Treats plurals as a two-way singular-or-plural branch for every language.
  • Assumes fallback selects one bundle and stays there for the whole page.
  • Uses the source-language sentence itself as the message key.