skip to content

Locale & Time Zone Resolution

Resolving the request locale from the language header, a cookie, the session or a URL segment, message bundles, per-request formatting. Interviewers ask why time zones default to the server's own.

on this pageshow

questions

5

In a server-side web framework, how is a request's locale resolved, and what happens when no source supplies one?

level: juniorimportance: must knowfreq 66%

answer

  1. decided before the handler runs
  2. an ordered chain, first match wins
  3. explicit choice outranks the client header
  4. candidates matched against supported locales
  5. configured default terminates the chain

basics

~20 s

A locale resolver runs early in each request and takes the first source that yields a supported locale: a URL marker, a stored preference in a cookie or session, the client's language header, then a configured default.

solid answer

~40 s

Most frameworks resolve the locale once, in an early pipeline step, and attach it to the request so the handler, the view layer and every formatter read the same value. The resolver walks an ordered chain and stops at the first source that yields a locale the application supports: an explicit marker in the URL, a stored preference in a cookie or in the session, the client's language preference header, then a configured default that cannot fail. Candidates are matched against the supported set rather than trusted verbatim, and a region-qualified request usually narrows to the plain language before the chain moves on. The ordering is by how explicit the signal is, so a choice the user made knowingly outranks a setting they may never have touched.

go deeper

for a junior

Recall that the locale is a per-request value rather than a server-wide setting, and that it is decided before your handler runs. Know the usual sources: the URL, a saved preference, the client's language header, and a configured default.

for a middle

Explain why the chain is ordered by how explicit each signal is, why every candidate is matched against the supported set, and why the resolved value is stored on the request instead of re-derived by each formatter.

for a senior

Show the operating consequences: a resolver with nowhere to write cannot honour a language switch, an unsupported locale must degrade predictably, and mixed sources across surfaces make the language flip between pages.

for a principal

Own the precedence as a product decision - linkability and indexing against respecting a signed-in user's explicit choice - and require one resolver to implement it everywhere, with the fallback rate measured.

## What a locale is, and why it belongs to the request A **locale** is the identity a formatting layer uses to decide two things: which language the text is in, and which regional conventions apply to numbers, currency amounts, dates and sorting. A server answering users in several countries cannot fix that identity at startup, because every request may belong to a different user. The locale is therefore a **per-request value**, and the component that decides it is usually called a **locale resolver**. Most server-side web frameworks run the resolver as an early step in the request pipeline, before routing hands control to a handler. That ordering matters: everything downstream - the handler, the template or view layer, the number and date formatters, the message lookup - reads the already-resolved value instead of each deriving its own. One decision, one value, one request. ## The resolver chain Resolution is normally an **ordered chain of sources**, evaluated until one yields a locale the application actually supports: 1. **An explicit marker in the URL** - a path prefix or a query parameter. It is the most explicit signal available: it travels with the link, so a pasted or crawled URL renders the same page for whoever opens it. 2. **A stored preference** - a locale cookie, or an attribute held in the user's session. This is where a language switcher writes, and it is what makes a choice survive to the next request. 3. **The client's language preference header** - the languages the user's browser or operating system was configured with. A good first guess and a poor final answer: many users never set it, and a borrowed or shared device carries someone else's setting. 4. **A configured default** - the deployment's fallback. It never fails, which is what terminates the chain. | source | who sets it | survives a new device | visible in the link | |---|---|---|---| | URL marker | the link that was followed | travels with the URL | yes | | cookie or session | an explicit user action | no | no | | language header | the client's own configuration | yes | no | | configured default | the deployment | not applicable | no | Two details separate a real resolver from a naive one. First, each candidate is **matched against the set of locales the application supports** rather than used verbatim; a region-qualified request normally narrows to the plain language before the chain moves on. Second, the chain is ordered by **how explicit the signal is**, so a deliberate choice outranks an ambient setting. ## Resolving once, then carrying the result Once resolved, the locale is attached to the request and read from there. A formatter that re-derives the locale from the raw request every time it is called drifts from the resolved value as soon as two sources disagree, and it makes the locale impossible to override for a test, an administrative preview, or a server-rendered email that must use a different language from the browsing session. A resolver usually pairs with a **writer**. If its source is writable - a cookie, a session attribute - the framework can persist a new choice when the user switches language. If the only source is the client's header, the server has nothing to write to, and the switch is forgotten on the next request. That asymmetry, not translation quality, is the usual reason a language switcher appears not to work. ## What goes wrong - **An unsupported locale is not degraded.** Rejecting the request or emitting raw message keys turns a preference mismatch into a visible failure; falling through to the default keeps the page usable. - **Split sources.** One surface reads the URL while another reads the stored preference, so the language flips as the user navigates. - **Late resolution.** Setting the locale inside a handler leaves everything that already ran - earlier pipeline steps, early error rendering - on the default. - **Trusting the client string.** Skipping the supported-set match pushes a typo or an exotic tag into the formatting layer, where it fails far from its cause. - **No observability.** The share of requests that fall all the way through to the configured default is the most useful signal that the chain is mis-ordered, and it is free to record at the one place resolution happens. Frameworks differ in how the chain is assembled - some expose a list of resolver components tried in order, others a single configurable resolver with fixed precedence - but the shape is the same: ordered sources, matched against what the application supports, ending in a default that cannot fail.

  • Why can a locale resolved from a cookie or session support a language switcher when a header-only resolver cannot?
    Switching language has to outlive the current response. A cookie or session attribute is writable, so the resolver can store the new choice and read it back next request. The client's language preference header is set by the client and the server cannot change it, so a header-only resolver forgets the choice as soon as the redirect lands.
  • What should happen when a request asks for a locale the application has no translations for?
    Match, do not reject. The resolver narrows a region-qualified request to the plain language, and if nothing in the supported set matches it falls through to the configured default. The page still renders, in a predictable language. Failing the request, or emitting raw message keys, turns a preference mismatch into an outage.

saying these in an interview costs you the question

  • Says the client's language header alone determines the locale.
  • Trusts whatever locale string the client sends without matching the supported set.
  • Thinks the locale is re-read from the request at every formatting call.
  • Believes a missing preference leaves the response unformatted instead of defaulting.
  • Sets the locale inside the handler and expects earlier pipeline steps to see it.
open as a page

Why does a web service render timestamps in the server's own time zone, and how is a per-request zone resolved?

level: middleimportance: must knowfreq 70%

basics

~20 s

Because the request carries no time zone. The language header conveys language and region, not a zone, so formatting falls back to the process default - whatever the host is configured to. A per-request zone must be supplied explicitly.

open as a page

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%

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.

open as a page

For an appointment scheduled months ahead, why is storing a UTC instant plus a fixed offset not enough?

level: seniorimportance: should knowfreq 52%

basics

~20 s

An offset is a snapshot of one moment's rule. Zone offsets change at daylight-saving transitions and when governments rewrite the rules, so a future commitment must store the local date-time plus the zone identifier, converted to an instant at use.

open as a page

How would you order locale sources - URL marker, stored preference, language header - for a product with public pages and signed-in users?

level: principalimportance: should knowfreq 44%

basics

~20 s

Order by how explicit and how durable each signal is: an in-URL locale for public linkable pages, a signed-in user's stored preference for application surfaces, the client's language header only to seed a first visit, and the configured default last.

open as a page