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-CA→fr→ default).providers— in order:'query:<name>','cookie:<name>'(the ASP.NET.Cultureformatc=de|uic=deis understood),'accept-language','header:<name>'(e.g.header:x-culture). Default:['query:culture', 'cookie:.Culture', 'accept-language'].resourcesDir— a folder of<culture>.jsonfiles;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-CAEvery 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.