Internationalization
Set the engine culture and time zone when JavaScript locale operations must not inherit the machine defaults:
var engine = new Engine(options =>
{
options.Culture = CultureInfo.GetCultureInfo("fr-FR");
options.TimeZone = TimeZoneInfo.Utc;
});
var text = engine.Evaluate("(1234.5).toLocaleString()").AsString();Culture affects locale-sensitive formatting. TimeZone affects date operations that use the engine's default zone. Prefer explicit values in deterministic services and tests.
Intl and Temporal data
Jint embeds the CLDR tables below and falls back to English-oriented defaults and BCL-backed timezone/calendar data for the rest. Hosts that need broader locale data or full historical IANA timezone behavior can replace:
Options.Intl.CldrProviderwith anICldrProviderOptions.Temporal.TimeZoneProviderwith anITimeZoneProviderOptions.Temporal.CalendarProviderwith anICalendarProvider
var engine = new Engine(options =>
{
options.Intl.CldrProvider = myCldrProvider;
options.Temporal.TimeZoneProvider = myTimeZoneProvider;
options.Temporal.CalendarProvider = myCalendarProvider;
});The calendar provider controls non-ISO arithmetic and the set of recognized calendar identifiers. The CLDR provider supplies localized names and patterns for those calendars.
The per-region tables are embedded, from CLDR 48.2: week data, the hour cycles in use, and the calendars in use. A CLDR provider can replace each of them, one member per Intl.Locale method:
| Member | Read by | Asked about |
|---|---|---|
GetWeekInfo | getWeekInfo | the whole tag |
GetHourCycles | getHourCycles, and Intl.DateTimeFormat's default hour cycle and the ones hour12 picks | the whole tag; the locale Intl.DateTimeFormat matched |
GetCalendars | getCalendars | the whole tag |
GetDefaultCalendar | Intl.DateTimeFormat's default calendar | the locale Intl.DateTimeFormat matched |
"The whole tag" keeps its -u-rg- and -u-sd- keywords, which can move the region, so the provider picks the region itself; the locale a formatter matched carries no Unicode extension. A provider that returns null leaves the answer to the embedded table, read for the region the specification picks, and DefaultCldrProvider answers every member from those tables. A -u-fw-, -u-hc- or -u-ca- keyword, or the matching option, still wins over the provider, and what a provider answers is held to what the algorithm allows: hour cycles are kept only if they are h11, h12, h23 or h24, calendars only if the engine can format in them.
One hour-cycle member means Intl.DateTimeFormat's default is always getHourCycles()[0] of the same locale. The calendar is two members, because the specification keys the formatter's default by the matched locale alone while getCalendars honours -u-rg- and -u-sd-. So a provider overriding only GetDefaultCalendar can see getCalendars()[0] disagree with the formatter's default calendar; one that wants them to agree overrides both:
sealed class HebrewByDefault : DefaultCldrProvider
{
public override string? GetDefaultCalendar(string locale) => "hebrew";
public override string[]? GetCalendars(string locale) => ["hebrew", "gregory"];
}Intl.DateTimeFormat resolves a bag of component options — { weekday: 'short', day: 'numeric', month: 'long' } and the like — through CLDR 48.2's Gregorian patterns, embedded for all 766 locales cldr-json carries, the way ICU does: the locale's availableFormats pattern nearest the request, fields it lacks appended through appendItems, a date and a time joined with dateTimeFormats ("at", "um", "à"), and CLDR's month, weekday, era and am/pm names in the context the pattern asks for. So de writes Sa., 24. Dezember and ja writes 12月24日(土), as V8 does, on every platform, and resolvedOptions() reports the fields of the pattern chosen. formatMatcher: 'basic' is answered the same way. formatRange() and formatRangeToParts() write such a bag with CLDR's intervalFormats, as ICU's DateIntervalFormat does: en writes Dec 24 – 27 (with CLDR's U+2009 THIN SPACE around the dash, as V8 writes it), de 24.–27. Dez., ja 12/24~12/27, with each part's source as the specification defines it. The data is one deflated block per language (about 215 KB in the assembly), and only the languages a process formats in are inflated.
dateStyle and timeStyle write the locale's CLDR dateFormats and timeFormats the same way, a date and a time joined with the same atTime connector (Saturday, December 24, 2022 at 3:07 PM, 24. Dezember 2022 um 15:07). Where the hour cycle the formatter resolved — from hourCycle, hour12, -u-hc- or the region — is not the one the locale's time pattern is written in, the pattern is matched again for the requested cycle, as V8 does: en with hourCycle: 'h23' writes 15:07, de with hour12: true writes 03:07 PM. A Temporal value without all of a style's fields — a PlainYearMonth under a dateStyle, a PlainTime under a long timeStyle, which has no zone — is written with the format the matcher chooses for the fields it has, as Temporal's AdjustDateTimeStyleFormat says. resolvedOptions() reports the styles, not the fields.
The dayPeriod option, and the flexible day period some locales write in their own time patterns (zh-Hant's 清晨6:05, 中午12:00, 晚上7:45), come from CLDR's day period rules and each locale's names, as ICU writes them: de writes nachts, morgens, vormittags, mittags, nachmittags and abends, ja 夜中 to 夜. Noon is written only for a time shown as exactly 12:00 (12 noon for an hour alone, 12:30 in the afternoon with its minute), midnight never, and a locale without rules, or without a name for the period, writes am/pm in its place.
The patterns are not replaceable. The names are: a CLDR provider's GetMonthNames, GetWeekdayNames, GetEraNames or GetDayPeriods answer (am/pm; the flexible day periods are not replaceable) takes the place of CLDR's, in both the format and stand-alone contexts, where it differs from DefaultCldrProvider.Instance's answer for the same arguments — so a provider that derives from DefaultCldrProvider, or delegates to it, without touching the names leaves CLDR's in place, in a range as in a single date. Time-zone names are not CLDR's: a long zone is written in English in every locale (Coordinated Universal Time). A dateStyle or timeStyle range is written with the same intervalFormats, for the skeleton of the style's pattern, as V8 does (de dateStyle: 'medium' writes 24.–27.12.2022). The Chinese and Dangi calendars still write .NET's patterns and names; they move onto CLDR in a later step of #4158.
The other calendars — buddhist, japanese, roc, hebrew, persian, indian, coptic, ethiopic, ethioaa and the Islamic ones — are written in their own CLDR shape, as ICU writes them: each calendar's availableFormats, dateFormats, intervalFormats, month names and eras, so en-u-ca-buddhist writes 12/24/2565 BE and fa-u-ca-persian names its months. A host provider's month names for a calendar counting months of its own still win, indexed by the calendar's month number; its era names reach the Gregorian calendar only. A Japanese date before Meiji is written in its Gregorian year, and a Hebrew date in he or yi in the formatter's digits where CLDR writes Hebrew numerals.
Choose providers before engine construction; the Options instance is frozen when an engine consumes it.