MasterController

Localization

Resolve a culture per request and translate with a string localizer.

master.useRequestLocalization() is ASP.NET Core’s RequestLocalizationMiddleware plus IStringLocalizer: providers pick the request culture, JSON resource files (or inline dictionaries) hold the strings, controllers and minimal handlers get this.culture and this.localizer, and formatting goes through Intl.

Setup#

server.js
master.useRequestLocalization({
  defaultCulture: 'en',
  supportedCultures: ['en', 'de', 'fr-CA'],
  providers: ['query:culture', 'cookie:.Culture', 'accept-language'],   // resolution order
  resourcesDir: 'resources',                                             // resources/en.json, de.json, fr-CA.json
});

// programmatic resources (nested keys flatten to 'nav.home')
master.localization.addResources('de', { greeting: 'Hallo {name}', nav: { home: 'Start' } });
  • defaultCulture, supportedCultures — requested values are matched against the supported list with parent fallback (fr-CAfr → default).
  • providers — in order: 'query:<name>', 'cookie:<name>' (the ASP.NET .Culture format c=de|uic=de is understood), 'accept-language', 'header:<name>' (e.g. header:x-culture). Default: ['query:culture', 'cookie:.Culture', 'accept-language'].
  • resourcesDir — a folder of <culture>.json files; resources — an inline { culture: dict } object; master.localization.addResources(culture, dict) at any time.

Resource files#

resources/en.json
{
  "greeting": "Hello {name}",
  "items.count": "{count} items",
  "nav": { "home": "Home", "account": "Account" }
}

Nested objects flatten to dotted keys; placeholders use {name}.

In controllers and handlers#

homeController.js
export default class HomeController {
  async index() {
    this.culture;                                   // 'de'
    const hello = this.localizer('greeting', { name: 'Ann' });   // 'Hallo Ann' (falls back de-CH -> de -> en -> key)
    const price = this.localizer.formatCurrency(12.5, 'EUR');    // Intl with the request culture
    const when  = this.localizer.formatDate(new Date(), { dateStyle: 'long' });
    const n     = this.localizer.formatNumber(1234567.891);
    this.localizer.has('nav.home');                 // true
    this.ok({ hello, price, when, n, culture: this.localizer.culture });
  }
}

Lookup order: the request culture → its parent → defaultCulture → the key itself (so a missing translation never throws). this.localizer also exposes has(key), culture, formatNumber(n, opts), formatCurrency(n, code), formatDate(d, opts). In middleware the culture is ctx.culture.

On the wire#

text
GET /?culture=de
GET /            (Cookie: .Culture=c=de|uic=de)      # ASP.NET's cookie format is understood
GET /            (Accept-Language: fr-CA, fr;q=0.8)

HTTP/1.1 200 OK
Content-Language: fr-CA

Every response carries Content-Language with the resolved culture.

Remembering the choice
Set the .Culture cookie from a language switcher and keep cookie:.Culture ahead of accept-language in providers, so an explicit choice beats the browser default — the same pattern as ASP.NET’s CookieRequestCultureProvider.