如何检查格式化器实际使用的语言环境和选项?

使用 resolvedOptions() 方法检查任何 Intl 格式化器的实际配置

介绍

当您在 JavaScript 中创建一个 Intl 格式化器时,您请求的选项并不总是您最终得到的选项。浏览器会执行区域设置协商、填充默认值,并规范化您的设置以创建最终配置。resolvedOptions() 方法允许您准确检查格式化器实际使用的内容。

Intl API 中的每个格式化器都有一个 resolvedOptions() 方法。这包括 Intl.DateTimeFormatIntl.NumberFormatIntl.ListFormatIntl.PluralRulesIntl.Collator 等。该方法返回一个对象,其中包含格式化器在处理您的输入后最终采用的所有配置详细信息。

此方法主要用于调试、了解浏览器行为以及检测当前环境中可用的功能。

基本语法

resolvedOptions() 方法不接受任何参数。您可以在任何格式化器实例上调用它,它会返回一个对象。

const formatter = new Intl.DateTimeFormat('en-US');
const options = formatter.resolvedOptions();

console.log(options);
// {
//   locale: 'en-US',
//   calendar: 'gregory',
//   numberingSystem: 'latn',
//   timeZone: 'America/Los_Angeles',
//   ...
// }

返回的对象至少包括日期格式化器的 localecalendarnumberingSystem 属性,或数字格式化器的 localenumberingSystem 属性。其他属性取决于您指定的选项以及格式化器类型支持的内容。

为什么请求的选项与解析的选项不同

请求的选项可能与解析的选项不同的原因主要有三个。

首先,当您的确切请求不受支持时,区域设置协商会找到最佳可用区域设置。如果您请求 de-AT,但浏览器只有 de,解析的区域设置将是 de

const formatter = new Intl.DateTimeFormat('de-AT-u-ca-buddhist');
const options = formatter.resolvedOptions();

console.log(options.locale);
// 可能输出:'de-AT' 或 'de'

console.log(options.calendar);
// 可能输出:'gregory'(如果不支持佛教日历)

其次,浏览器会为您未指定的任何选项填充默认值。这些默认值是特定于区域设置的。

const formatter = new Intl.NumberFormat('en-US');
const options = formatter.resolvedOptions();

console.log(options.style);
// 输出:'decimal'

console.log(options.minimumFractionDigits);
// 输出:0

console.log(options.maximumFractionDigits);
// 输出:3

第三,浏览器会将某些选项规范化为其规范形式。如果您使用 dateStyletimeStyle,浏览器不会在解析的选项中包含这些选项。相反,它会包含它们扩展到的各个组件选项。

检查实际使用的语言环境

resolvedOptions 中的 locale 属性会准确告诉您格式化器正在使用的语言环境。这是语言环境协商的结果。

const formatter = new Intl.DateTimeFormat(['zh-TW', 'zh-CN', 'en-US']);
const options = formatter.resolvedOptions();

console.log(options.locale);
// 输出列表中第一个支持的语言环境

如果您请求的语言环境包含 Unicode 扩展关键字,而这些关键字不被支持或作为单独的选项应用,则解析后的语言环境可能不包含这些关键字。

const formatter = new Intl.NumberFormat('en-US-u-nu-arab');
const options = formatter.resolvedOptions();

console.log(options.locale);
// 可能输出:'en-US'

console.log(options.numberingSystem);
// 可能输出:'arab' 或 'latn',取决于支持情况

检查日期和时间格式化选项

对于 Intl.DateTimeFormat,解析后的选项包括将显示哪些日期和时间组件以及如何显示的详细信息。

const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  timeZone: 'America/New_York'
});

const options = formatter.resolvedOptions();

console.log(options.year);
// 输出:'numeric'

console.log(options.month);
// 输出:'long'

console.log(options.day);
// 输出:'numeric'

console.log(options.timeZone);
// 输出:'America/New_York'

console.log(options.calendar);
// 输出:'gregory'

当您使用 dateStyletimeStyle 时,这些快捷方式不会包含在解析后的选项中。浏览器会根据语言环境将它们扩展为单独的组件选项。

const formatter = new Intl.DateTimeFormat('en-US', {
  dateStyle: 'full'
});

const options = formatter.resolvedOptions();

console.log(options.dateStyle);
// 输出:undefined

console.log(options.weekday);
// 输出:'long'

console.log(options.year);
// 输出:'numeric'

console.log(options.month);
// 输出:'long'

console.log(options.day);
// 输出:'numeric'

如果您创建了一个没有任何选项的日期格式化器,解析后的选项会显示浏览器为该语言环境选择的默认值。

const formatter = new Intl.DateTimeFormat('ja-JP');
const options = formatter.resolvedOptions();

console.log(options);
// 显示日本语言环境的默认日期组件选项

检查数字格式化选项

对于 Intl.NumberFormat,解析的选项会告诉您样式、精度、分组和其他格式化细节。

const formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});

const options = formatter.resolvedOptions();

console.log(options.style);
// 输出: 'currency'

console.log(options.currency);
// 输出: 'USD'

console.log(options.currencyDisplay);
// 输出: 'symbol'

console.log(options.minimumFractionDigits);
// 输出: 2

console.log(options.maximumFractionDigits);
// 输出: 2

您可以看到,即使您只指定了货币,浏览器也会为 currencyDisplay 和小数位数填充默认值。

当您使用舍入选项时,解析的选项会准确显示数字将如何舍入。

const formatter = new Intl.NumberFormat('en-US', {
  minimumSignificantDigits: 3,
  maximumSignificantDigits: 5
});

const options = formatter.resolvedOptions();

console.log(options.minimumSignificantDigits);
// 输出: 3

console.log(options.maximumSignificantDigits);
// 输出: 5

检查其他格式化器类型

resolvedOptions() 方法在所有 Intl 格式化器上工作方式相同。

对于 Intl.ListFormat,它会显示类型和样式。

const formatter = new Intl.ListFormat('en-US', {
  style: 'long',
  type: 'conjunction'
});

const options = formatter.resolvedOptions();

console.log(options.locale);
// 输出: 'en-US'

console.log(options.style);
// 输出: 'long'

console.log(options.type);
// 输出: 'conjunction'

对于 Intl.PluralRules,它会显示类型以及最小/最大位数。

const formatter = new Intl.PluralRules('en-US', {
  type: 'ordinal'
});

const options = formatter.resolvedOptions();

console.log(options.locale);
// 输出: 'en-US'

console.log(options.type);
// 输出: 'ordinal'

console.log(options.minimumIntegerDigits);
// 输出: 1

resolvedOptions() 的常见用例

最常见的用例是调试。当格式化的输出与您的预期不符时,resolvedOptions() 可以帮助您了解格式化器实际在做什么。

const formatter = new Intl.DateTimeFormat('en-US', {
  dateStyle: 'medium'
});

console.log(formatter.format(new Date()));
// 检查输出

console.log(formatter.resolvedOptions());
// 查看生成该输出的确切选项

另一个用例是功能检测。您可以通过请求特定的日历、数字系统或其他功能并查看实际解析的结果来检查是否支持该功能。

const formatter = new Intl.DateTimeFormat('en-US', {
  calendar: 'islamic'
});

const options = formatter.resolvedOptions();

if (options.calendar === 'islamic') {
  console.log('支持伊斯兰日历');
} else {
  console.log('不支持伊斯兰日历,使用 ' + options.calendar);
}

您还可以使用 resolvedOptions() 获取用户的区域设置偏好。当您创建一个没有区域设置参数的格式化器时,浏览器会使用用户的偏好。

const formatter = new Intl.DateTimeFormat();
const options = formatter.resolvedOptions();

console.log(options.locale);
// 输出: 用户的首选区域设置

console.log(options.timeZone);
// 输出: 用户的时区

console.log(options.hourCycle);
// 输出: 用户的小时制偏好 (12 或 24 小时制)

最后,您可以使用解析的选项重新创建一个相同的格式化器。返回的对象可以传递回构造函数。

const formatter1 = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});

const options = formatter1.resolvedOptions();

const formatter2 = new Intl.NumberFormat(options.locale, options);

// formatter2 将以与 formatter1 相同的方式格式化数字

关键要点

resolvedOptions() 方法返回一个对象,其中包含格式化器实际使用的配置。这些配置可能由于语言环境协商、默认值和规范化而与您请求的配置有所不同。

每个 Intl 格式化器都有此方法。您无需传递参数即可调用它,并接收一个包含 localecalendarnumberingSystem 以及格式化器特定选项等属性的对象。

主要使用 resolvedOptions() 方法来调试格式化器行为、检测可用功能以及了解浏览器如何解释您的选项。返回的对象还可以用于重新创建相同的格式化器或检查用户偏好。