Explaining the new internationalization features in Safari 15.4
Tags: javascript, webdev, i18n, safari
Published: 2022-03-18 09:05:36

[Safari 15.4 released recently](https://webkit.org/blog/12445/new-webkit-features-in-safari-15-4/) and among many things it includes a few new internationalization features. And while the blog post does explain which ones they are, it doesn't really mention what they do. So, I'll give you a brief summary for all of them.

## `Intl.Locale`

### `calendars/collations/hourCycles/numberingSystems/timeZones`

All of these properties will return an array of the things the locale supports. Here are some examples of what each one will return so that you can get an idea of what they're used for.

```js
// calendars for Japanese (Japan) will return the Gregorian calendar and the Japanese calendar
new Intl.Locale('ja-JP').calendars; // ['gregory', 'japanese']

// collations A.K.A. ordering rules for Spanish (Mexico) will return traditional style ordering, European ordering rules, and emoji
new Intl.Locale('es-MX').collations; // ['trad', 'emoji', 'eor']

// hourCycles for Traditional Chinese (China) will be a 23 hour cycle
new Intl.Locale('zh-Hant-CN').hourCycles; // ['h23']
// but for English (USA) it will be a 12 hour cycle
new Intl.Locale('en-US').hourCycles; // ['h12']

// numberingSystems for Arabic (Bahrain) will return Arabic-Indic digits
new Intl.Locale('ar-BH').numberingSystems; // ['arab']
// but for Portuguese (Brazil) it will return Latin digits
new Intl.Locale('pr-BR').numberingSystems; // ['latn']

// timeZones for English (New Zealand) will return Auckland and Chatham
new Intl.Locale('en-NZ').timeZones; // ['Pacific/Auckland', 'Pacific/Chatham']
```

Previous versions of the spec supported the non-plural versions of each of these properties. However, they will be undefined unless they are set through the `options` parameter of the `Locale` constructor.

```js
// not setting with options
new Intl.Locale('ja-JP').calendar; // undefined
new Intl.Locale('ja-JP').calendars; // ['gregory', 'japanese']

// setting with options
new Intl.Locale('ja-JP', {calendar: 'gregory'}).calendar; // 'gregory'
new Intl.Locale('ja-JP', {calendar: 'gregory'}).calendars; // ['gregory'] as the 'japanese' one will get removed due to the options

// you can also set other calendars not there by default on the locale so be careful
new Intl.Locale('ja-JP', {calendar: 'buddhist'}).calendar; // 'buddhist'
new Intl.Locale('ja-JP', {calendar: 'buddhist'}).calendars; // ['buddhist']
```

### `textInfo`

The `textInfo` property currently contains an object with a single `direction` property which serves to indicate whether the locale's text is written right-to-left or left-to-right.

```js
// Arabic
new Intl.Locale("ar").textInfo; // { direction: 'rtl'}
// Spanish
new Intl.Locale("es").textInfo; // { direction: 'ltr'}
```

### `weekInfo`

The `weekInfo` currently contains an object with various information regarding how weeks work on that region. It's especially useful when creating calendar UIs.

```js
// week info for the UK
const gb = new Intl.Locale("en-GB").weekInfo;
gb.firstDay; // 1 - week starts on Monday
gb.weekend; // [6, 7] - weekend is Saturday and Sunday
gb.minimalDays; // 4 - for a week to be shown as the first week of a month it needs to be at least 4 days long

// week info for Algeria
const dz = new Intl.Locale("ar-DZ").weekInfo;
dz.firstDay; // 6 - week starts on Saturday
dz.weekend; // [5, 6] - weekend is Friday and Saturday
dz.minimalDays; // 1 - for a week to be shown as the first week of a month it needs to be at least 1 days long
```

### Browser Support

[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale#browser_compatibility)

All the above features are supported in the following browsers: 

- Safari: 15.4 - supported
- Chrome/Edge: 92* - supported (MDN says only with a flag but it worked in Edge 99 with no flags)
- Firefox: 99 - not supported

## Intl.DisplayNames

### `type: 'calendar'`

This type option will allow you to get the localized name for any of the supported calendar types.

```js
new Intl.DisplayNames(['en'], { type: 'calendar' }).of('gregory'); // 'Gregorian Calendar'
new Intl.DisplayNames(['en'], { type: 'calendar' }).of('japanese'); // 'Japanese Calendar'
```

### `type: 'dateTimeField'`

With this type option you can get localized strings for many different common words related to dates and time. Some examples include:

```js
new Intl.DisplayNames(['en'], { type: 'dateTimeField' }).of('year'); // 'year'
new Intl.DisplayNames(['en'], { type: 'dateTimeField' }).of('minute'); // 'minute'                                               
new Intl.DisplayNames(['en'], { type: 'dateTimeField' }).of('weekday') // 'day of the week'
```

### `languageDisplay` option

The `languageDisplay` option is an option that can only be used for `type: 'language'` that determines the format for the string representing the language. It can be either 'dialect' or 'standard'.

```js
new Intl.DisplayNames(['en'], { type: 'language', languageDisplay: 'dialect' }).of('en-AU'); // Australian English
new Intl.DisplayNames(['en'], { type: 'language', languageDisplay: 'standard' }).of('en-AU'); // English (Australia)
```

### Browser Support

No [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) data for these features specifically, but I tested them in the following browsers:

- Safari: 15.4 - supported
- Chrome/Edge: 99 - supported
- Firefox: 99 developer edition - supported

## Intl.DateTimeFormat

### New `timeZoneName` types

Four new types of `timeZoneName` were added: 'shortOffset', 'longOffset', 'shortGeneric', and 'longGeneric'.


```js
const date = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));

new Intl.DateTimeFormat('en', { timeZone: 'JST', timeZoneName: 'shortOffset'}).format(date); // '12/20/2020, GMT+9'
new Intl.DateTimeFormat('en', { timeZone: 'JST', timeZoneName: 'longOffset'}).format(date); // '12/20/2020, GMT+09:00'
new Intl.DateTimeFormat('en', { timeZone: 'JST', timeZoneName: 'shortGeneric'}).format(date); // '12/20/2020, Japan Time'
new Intl.DateTimeFormat('en', { timeZone: 'JST', timeZoneName: 'longGeneric'}).format(date); // '12/20/2020, Japan Standard Time'
```

### Browser Support

[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#browser_compatibility)

- Safari: 15.4 - supported
- Chrome/Edge: 99* - supported (MDN doesn't list this as supported but it worked in my tests. It might work in earlier versions. [MDN issue](https://github.com/mdn/browser-compat-data/issues/15396))
- Firefox: 91 - supported

## Intl.NumberFormat / Intl.PluralRules

Safari 15.4's release notes mention that it added support for `formatRange()` and `formatRangeToParts()` in `NumberFormat` and for `selectRange()` in `PluralRules`. However, as the time of writing, those functions don't seem to be actually implemented in Safari 15.4 (Mac OS 10.15) nor have they been implemented in other browsers. 

```js
new Intl.NumberFormat('de-DE').formatRange; // undefined
new Intl.NumberFormat('de-DE').formatRangeToParts; // undefined

new Intl.PluralRules('de-DE').selectRange; // undefined
```

## Conclusion

Hopefully this article helped you understand better what all these new features were about and whether you can actually begin using them.

## Credits

Cover photo by [Nareeta Martin](https://unsplash.com/@splashabout?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/international?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText).