NumberFormat.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/GlobalObject.h>
  7. #include <LibJS/Runtime/Intl/AbstractOperations.h>
  8. #include <LibJS/Runtime/Intl/NumberFormat.h>
  9. #include <LibUnicode/CurrencyCode.h>
  10. #include <LibUnicode/Locale.h>
  11. namespace JS::Intl {
  12. Vector<StringView> const& NumberFormat::relevant_extension_keys()
  13. {
  14. // 15.3.3 Internal slots, https://tc39.es/ecma402/#sec-intl.numberformat-internal-slots
  15. // The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
  16. static Vector<StringView> relevant_extension_keys { "nu"sv };
  17. return relevant_extension_keys;
  18. }
  19. // 15 NumberFormat Objects, https://tc39.es/ecma402/#numberformat-objects
  20. NumberFormat::NumberFormat(Object& prototype)
  21. : Object(prototype)
  22. {
  23. }
  24. void NumberFormat::set_style(StringView style)
  25. {
  26. if (style == "decimal"sv)
  27. m_style = Style::Decimal;
  28. else if (style == "percent"sv)
  29. m_style = Style::Percent;
  30. else if (style == "currency"sv)
  31. m_style = Style::Currency;
  32. else if (style == "unit"sv)
  33. m_style = Style::Unit;
  34. else
  35. VERIFY_NOT_REACHED();
  36. }
  37. StringView NumberFormat::style_string() const
  38. {
  39. switch (m_style) {
  40. case Style::Decimal:
  41. return "decimal"sv;
  42. case Style::Percent:
  43. return "percent"sv;
  44. case Style::Currency:
  45. return "currency"sv;
  46. case Style::Unit:
  47. return "unit"sv;
  48. default:
  49. VERIFY_NOT_REACHED();
  50. }
  51. }
  52. void NumberFormat::set_currency_display(StringView currency_display)
  53. {
  54. if (currency_display == "code"sv)
  55. m_currency_display = CurrencyDisplay::Code;
  56. else if (currency_display == "symbol"sv)
  57. m_currency_display = CurrencyDisplay::Symbol;
  58. else if (currency_display == "narrowSymbol"sv)
  59. m_currency_display = CurrencyDisplay::NarrowSymbol;
  60. else if (currency_display == "name"sv)
  61. m_currency_display = CurrencyDisplay::Name;
  62. else
  63. VERIFY_NOT_REACHED();
  64. }
  65. StringView NumberFormat::currency_display_string() const
  66. {
  67. VERIFY(m_currency_display.has_value());
  68. switch (*m_currency_display) {
  69. case CurrencyDisplay::Code:
  70. return "code"sv;
  71. case CurrencyDisplay::Symbol:
  72. return "symbol"sv;
  73. case CurrencyDisplay::NarrowSymbol:
  74. return "narrowSymbol"sv;
  75. case CurrencyDisplay::Name:
  76. return "name"sv;
  77. default:
  78. VERIFY_NOT_REACHED();
  79. }
  80. }
  81. void NumberFormat::set_currency_sign(StringView currency_sign)
  82. {
  83. if (currency_sign == "standard"sv)
  84. m_currency_sign = CurrencySign::Standard;
  85. else if (currency_sign == "accounting"sv)
  86. m_currency_sign = CurrencySign::Accounting;
  87. else
  88. VERIFY_NOT_REACHED();
  89. }
  90. StringView NumberFormat::currency_sign_string() const
  91. {
  92. VERIFY(m_currency_sign.has_value());
  93. switch (*m_currency_sign) {
  94. case CurrencySign::Standard:
  95. return "standard"sv;
  96. case CurrencySign::Accounting:
  97. return "accounting"sv;
  98. default:
  99. VERIFY_NOT_REACHED();
  100. }
  101. }
  102. void NumberFormat::set_unit_display(StringView unit_display)
  103. {
  104. if (unit_display == "short"sv)
  105. m_unit_display = UnitDisplay::Short;
  106. else if (unit_display == "narrow"sv)
  107. m_unit_display = UnitDisplay::Narrow;
  108. else if (unit_display == "long"sv)
  109. m_unit_display = UnitDisplay::Long;
  110. else
  111. VERIFY_NOT_REACHED();
  112. }
  113. StringView NumberFormat::unit_display_string() const
  114. {
  115. VERIFY(m_unit_display.has_value());
  116. switch (*m_unit_display) {
  117. case UnitDisplay::Short:
  118. return "short"sv;
  119. case UnitDisplay::Narrow:
  120. return "narrow"sv;
  121. case UnitDisplay::Long:
  122. return "long"sv;
  123. default:
  124. VERIFY_NOT_REACHED();
  125. }
  126. }
  127. StringView NumberFormat::rounding_type_string() const
  128. {
  129. switch (m_rounding_type) {
  130. case RoundingType::SignificantDigits:
  131. return "significantDigits"sv;
  132. case RoundingType::FractionDigits:
  133. return "fractionDigits"sv;
  134. case RoundingType::CompactRounding:
  135. return "compactRounding"sv;
  136. default:
  137. VERIFY_NOT_REACHED();
  138. }
  139. }
  140. void NumberFormat::set_notation(StringView notation)
  141. {
  142. if (notation == "standard"sv)
  143. m_notation = Notation::Standard;
  144. else if (notation == "scientific"sv)
  145. m_notation = Notation::Scientific;
  146. else if (notation == "engineering"sv)
  147. m_notation = Notation::Engineering;
  148. else if (notation == "compact"sv)
  149. m_notation = Notation::Compact;
  150. else
  151. VERIFY_NOT_REACHED();
  152. }
  153. StringView NumberFormat::notation_string() const
  154. {
  155. switch (m_notation) {
  156. case Notation::Standard:
  157. return "standard"sv;
  158. case Notation::Scientific:
  159. return "scientific"sv;
  160. case Notation::Engineering:
  161. return "engineering"sv;
  162. case Notation::Compact:
  163. return "compact"sv;
  164. default:
  165. VERIFY_NOT_REACHED();
  166. }
  167. }
  168. void NumberFormat::set_compact_display(StringView compact_display)
  169. {
  170. if (compact_display == "short"sv)
  171. m_compact_display = CompactDisplay::Short;
  172. else if (compact_display == "long"sv)
  173. m_compact_display = CompactDisplay::Long;
  174. else
  175. VERIFY_NOT_REACHED();
  176. }
  177. StringView NumberFormat::compact_display_string() const
  178. {
  179. VERIFY(m_compact_display.has_value());
  180. switch (*m_compact_display) {
  181. case CompactDisplay::Short:
  182. return "short"sv;
  183. case CompactDisplay::Long:
  184. return "long"sv;
  185. default:
  186. VERIFY_NOT_REACHED();
  187. }
  188. }
  189. void NumberFormat::set_sign_display(StringView sign_display)
  190. {
  191. if (sign_display == "auto"sv)
  192. m_sign_display = SignDisplay::Auto;
  193. else if (sign_display == "never"sv)
  194. m_sign_display = SignDisplay::Never;
  195. else if (sign_display == "always"sv)
  196. m_sign_display = SignDisplay::Always;
  197. else if (sign_display == "exceptZero"sv)
  198. m_sign_display = SignDisplay::ExceptZero;
  199. else
  200. VERIFY_NOT_REACHED();
  201. }
  202. StringView NumberFormat::sign_display_string() const
  203. {
  204. switch (m_sign_display) {
  205. case SignDisplay::Auto:
  206. return "auto"sv;
  207. case SignDisplay::Never:
  208. return "never"sv;
  209. case SignDisplay::Always:
  210. return "always"sv;
  211. case SignDisplay::ExceptZero:
  212. return "exceptZero"sv;
  213. default:
  214. VERIFY_NOT_REACHED();
  215. }
  216. }
  217. // 15.1.1 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation ), https://tc39.es/ecma402/#sec-setnfdigitoptions
  218. ThrowCompletionOr<void> set_number_format_digit_options(GlobalObject& global_object, NumberFormat& intl_object, Object const& options, int default_min_fraction_digits, int default_max_fraction_digits, NumberFormat::Notation notation)
  219. {
  220. auto& vm = global_object.vm();
  221. // 1. Assert: Type(intlObj) is Object.
  222. // 2. Assert: Type(options) is Object.
  223. // 3. Assert: Type(mnfdDefault) is Number.
  224. // 4. Assert: Type(mxfdDefault) is Number.
  225. // 5. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1).
  226. auto min_integer_digits = TRY(get_number_option(global_object, options, vm.names.minimumIntegerDigits, 1, 21, 1));
  227. // 6. Let mnfd be ? Get(options, "minimumFractionDigits").
  228. auto min_fraction_digits = TRY(options.get(vm.names.minimumFractionDigits));
  229. // 7. Let mxfd be ? Get(options, "maximumFractionDigits").
  230. auto max_fraction_digits = TRY(options.get(vm.names.maximumFractionDigits));
  231. // 8. Let mnsd be ? Get(options, "minimumSignificantDigits").
  232. auto min_significant_digits = TRY(options.get(vm.names.minimumSignificantDigits));
  233. // 9. Let mxsd be ? Get(options, "maximumSignificantDigits").
  234. auto max_significant_digits = TRY(options.get(vm.names.maximumSignificantDigits));
  235. // 10. Set intlObj.[[MinimumIntegerDigits]] to mnid.
  236. intl_object.set_min_integer_digits(*min_integer_digits);
  237. // 11. If mnsd is not undefined or mxsd is not undefined, then
  238. if (!min_significant_digits.is_undefined() || !max_significant_digits.is_undefined()) {
  239. // a. Set intlObj.[[RoundingType]] to significantDigits.
  240. intl_object.set_rounding_type(NumberFormat::RoundingType::SignificantDigits);
  241. // b. Let mnsd be ? DefaultNumberOption(mnsd, 1, 21, 1).
  242. auto min_digits = TRY(default_number_option(global_object, min_significant_digits, 1, 21, 1));
  243. // c. Let mxsd be ? DefaultNumberOption(mxsd, mnsd, 21, 21).
  244. auto max_digits = TRY(default_number_option(global_object, max_significant_digits, *min_digits, 21, 21));
  245. // d. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
  246. intl_object.set_min_significant_digits(*min_digits);
  247. // e. Set intlObj.[[MaximumSignificantDigits]] to mxsd.
  248. intl_object.set_max_significant_digits(*max_digits);
  249. }
  250. // 12. Else if mnfd is not undefined or mxfd is not undefined, then
  251. else if (!min_fraction_digits.is_undefined() || !max_fraction_digits.is_undefined()) {
  252. // a. Set intlObj.[[RoundingType]] to fractionDigits.
  253. intl_object.set_rounding_type(NumberFormat::RoundingType::FractionDigits);
  254. // b. Let mnfd be ? DefaultNumberOption(mnfd, 0, 20, undefined).
  255. auto min_digits = TRY(default_number_option(global_object, min_fraction_digits, 0, 20, {}));
  256. // c. Let mxfd be ? DefaultNumberOption(mxfd, 0, 20, undefined).
  257. auto max_digits = TRY(default_number_option(global_object, max_fraction_digits, 0, 20, {}));
  258. // d. If mnfd is undefined, set mnfd to min(mnfdDefault, mxfd).
  259. if (!min_digits.has_value())
  260. min_digits = min(default_min_fraction_digits, *max_digits);
  261. // e. Else if mxfd is undefined, set mxfd to max(mxfdDefault, mnfd).
  262. else if (!max_digits.has_value())
  263. max_digits = max(default_max_fraction_digits, *min_digits);
  264. // f. Else if mnfd is greater than mxfd, throw a RangeError exception.
  265. else if (*min_digits > *max_digits)
  266. return vm.throw_completion<RangeError>(global_object, ErrorType::IntlMinimumExceedsMaximum, *min_digits, *max_digits);
  267. // g. Set intlObj.[[MinimumFractionDigits]] to mnfd.
  268. intl_object.set_min_fraction_digits(*min_digits);
  269. // h. Set intlObj.[[MaximumFractionDigits]] to mxfd.
  270. intl_object.set_max_fraction_digits(*max_digits);
  271. }
  272. // 13. Else if notation is "compact", then
  273. else if (notation == NumberFormat::Notation::Compact) {
  274. // a. Set intlObj.[[RoundingType]] to compactRounding.
  275. intl_object.set_rounding_type(NumberFormat::RoundingType::CompactRounding);
  276. }
  277. // 14. Else,
  278. else {
  279. // a. Set intlObj.[[RoundingType]] to fractionDigits.
  280. intl_object.set_rounding_type(NumberFormat::RoundingType::FractionDigits);
  281. // b. Set intlObj.[[MinimumFractionDigits]] to mnfdDefault.
  282. intl_object.set_min_fraction_digits(default_min_fraction_digits);
  283. // c. Set intlObj.[[MaximumFractionDigits]] to mxfdDefault.
  284. intl_object.set_max_fraction_digits(default_max_fraction_digits);
  285. }
  286. return {};
  287. }
  288. // 15.1.2 InitializeNumberFormat ( numberFormat, locales, options ), https://tc39.es/ecma402/#sec-initializenumberformat
  289. ThrowCompletionOr<NumberFormat*> initialize_number_format(GlobalObject& global_object, NumberFormat& number_format, Value locales_value, Value options_value)
  290. {
  291. auto& vm = global_object.vm();
  292. // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  293. auto requested_locales = TRY(canonicalize_locale_list(global_object, locales_value));
  294. // 2. Set options to ? CoerceOptionsToObject(options).
  295. auto* options = TRY(coerce_options_to_object(global_object, options_value));
  296. // 3. Let opt be a new Record.
  297. LocaleOptions opt {};
  298. // 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
  299. auto matcher = TRY(get_option(global_object, *options, vm.names.localeMatcher, Value::Type::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
  300. // 5. Set opt.[[localeMatcher]] to matcher.
  301. opt.locale_matcher = matcher;
  302. // 6. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined).
  303. auto numbering_system = TRY(get_option(global_object, *options, vm.names.numberingSystem, Value::Type::String, {}, Empty {}));
  304. // 7. If numberingSystem is not undefined, then
  305. if (!numbering_system.is_undefined()) {
  306. // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
  307. if (!Unicode::is_type_identifier(numbering_system.as_string().string()))
  308. return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv);
  309. // 8. Set opt.[[nu]] to numberingSystem.
  310. opt.nu = numbering_system.as_string().string();
  311. }
  312. // 9. Let localeData be %NumberFormat%.[[LocaleData]].
  313. // 10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]], localeData).
  314. auto result = resolve_locale(requested_locales, opt, NumberFormat::relevant_extension_keys());
  315. // 11. Set numberFormat.[[Locale]] to r.[[locale]].
  316. number_format.set_locale(move(result.locale));
  317. // 12. Set numberFormat.[[DataLocale]] to r.[[dataLocale]].
  318. number_format.set_data_locale(move(result.data_locale));
  319. // 13. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
  320. number_format.set_numbering_system(result.nu.release_value());
  321. // 14. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
  322. TRY(set_number_format_unit_options(global_object, number_format, *options));
  323. // 15. Let style be numberFormat.[[Style]].
  324. auto style = number_format.style();
  325. int default_min_fraction_digits = 0;
  326. int default_max_fraction_digits = 0;
  327. // 16. If style is "currency", then
  328. if (style == NumberFormat::Style::Currency) {
  329. // a. Let currency be numberFormat.[[Currency]].
  330. auto const& currency = number_format.currency();
  331. // b. Let cDigits be CurrencyDigits(currency).
  332. int digits = currency_digits(currency);
  333. // c. Let mnfdDefault be cDigits.
  334. default_min_fraction_digits = digits;
  335. // d. Let mxfdDefault be cDigits.
  336. default_max_fraction_digits = digits;
  337. }
  338. // 17. Else,
  339. else {
  340. // a. Let mnfdDefault be 0.
  341. default_min_fraction_digits = 0;
  342. // b. If style is "percent", then
  343. // i. Let mxfdDefault be 0.
  344. // c. Else,
  345. // i. Let mxfdDefault be 3.
  346. default_max_fraction_digits = style == NumberFormat::Style::Percent ? 0 : 3;
  347. }
  348. // 18. Let notation be ? GetOption(options, "notation", "string", « "standard", "scientific", "engineering", "compact" », "standard").
  349. auto notation = TRY(get_option(global_object, *options, vm.names.notation, Value::Type::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv));
  350. // 19. Set numberFormat.[[Notation]] to notation.
  351. number_format.set_notation(notation.as_string().string());
  352. // 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
  353. TRY(set_number_format_digit_options(global_object, number_format, *options, default_min_fraction_digits, default_max_fraction_digits, number_format.notation()));
  354. // 21. Let compactDisplay be ? GetOption(options, "compactDisplay", "string", « "short", "long" », "short").
  355. auto compact_display = TRY(get_option(global_object, *options, vm.names.compactDisplay, Value::Type::String, { "short"sv, "long"sv }, "short"sv));
  356. // 22. If notation is "compact", then
  357. if (number_format.notation() == NumberFormat::Notation::Compact) {
  358. // a. Set numberFormat.[[CompactDisplay]] to compactDisplay.
  359. number_format.set_compact_display(compact_display.as_string().string());
  360. }
  361. // 23. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", undefined, true).
  362. auto use_grouping = TRY(get_option(global_object, *options, vm.names.useGrouping, Value::Type::Boolean, {}, true));
  363. // 24. Set numberFormat.[[UseGrouping]] to useGrouping.
  364. number_format.set_use_grouping(use_grouping.as_bool());
  365. // 25. Let signDisplay be ? GetOption(options, "signDisplay", "string", « "auto", "never", "always", "exceptZero" », "auto").
  366. auto sign_display = TRY(get_option(global_object, *options, vm.names.signDisplay, Value::Type::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv }, "auto"sv));
  367. // 26. Set numberFormat.[[SignDisplay]] to signDisplay.
  368. number_format.set_sign_display(sign_display.as_string().string());
  369. // 27. Return numberFormat.
  370. return &number_format;
  371. }
  372. // 15.1.3 CurrencyDigits ( currency ), https://tc39.es/ecma402/#sec-currencydigits
  373. int currency_digits(StringView currency)
  374. {
  375. // 1. If the ISO 4217 currency and funds code list contains currency as an alphabetic code, return the minor
  376. // unit value corresponding to the currency from the list; otherwise, return 2.
  377. if (auto currency_code = Unicode::get_currency_code(currency); currency_code.has_value())
  378. return currency_code->minor_unit.value_or(2);
  379. return 2;
  380. }
  381. // 15.1.13 SetNumberFormatUnitOptions ( intlObj, options ), https://tc39.es/ecma402/#sec-setnumberformatunitoptions
  382. ThrowCompletionOr<void> set_number_format_unit_options(GlobalObject& global_object, NumberFormat& intl_object, Object const& options)
  383. {
  384. auto& vm = global_object.vm();
  385. // 1. Assert: Type(intlObj) is Object.
  386. // 2. Assert: Type(options) is Object.
  387. // 3. Let style be ? GetOption(options, "style", "string", « "decimal", "percent", "currency", "unit" », "decimal").
  388. auto style = TRY(get_option(global_object, options, vm.names.style, Value::Type::String, { "decimal"sv, "percent"sv, "currency"sv, "unit"sv }, "decimal"sv));
  389. // 4. Set intlObj.[[Style]] to style.
  390. intl_object.set_style(style.as_string().string());
  391. // 5. Let currency be ? GetOption(options, "currency", "string", undefined, undefined).
  392. auto currency = TRY(get_option(global_object, options, vm.names.currency, Value::Type::String, {}, Empty {}));
  393. // 6. If currency is undefined, then
  394. if (currency.is_undefined()) {
  395. // a. If style is "currency", throw a TypeError exception.
  396. if (intl_object.style() == NumberFormat::Style::Currency)
  397. return vm.throw_completion<TypeError>(global_object, ErrorType::IntlOptionUndefined, "currency"sv, "style"sv, style);
  398. }
  399. // 7. Else,
  400. // a. If the result of IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
  401. else if (!is_well_formed_currency_code(currency.as_string().string()))
  402. return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, currency, "currency"sv);
  403. // 8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", "string", « "code", "symbol", "narrowSymbol", "name" », "symbol").
  404. auto currency_display = TRY(get_option(global_object, options, vm.names.currencyDisplay, Value::Type::String, { "code"sv, "symbol"sv, "narrowSymbol"sv, "name"sv }, "symbol"sv));
  405. // 9. Let currencySign be ? GetOption(options, "currencySign", "string", « "standard", "accounting" », "standard").
  406. auto currency_sign = TRY(get_option(global_object, options, vm.names.currencySign, Value::Type::String, { "standard"sv, "accounting"sv }, "standard"sv));
  407. // 10. Let unit be ? GetOption(options, "unit", "string", undefined, undefined).
  408. auto unit = TRY(get_option(global_object, options, vm.names.unit, Value::Type::String, {}, Empty {}));
  409. // 11. If unit is undefined, then
  410. if (unit.is_undefined()) {
  411. // a. If style is "unit", throw a TypeError exception.
  412. if (intl_object.style() == NumberFormat::Style::Unit)
  413. return vm.throw_completion<TypeError>(global_object, ErrorType::IntlOptionUndefined, "unit"sv, "style"sv, style);
  414. }
  415. // 12. Else,
  416. // a. If the result of IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
  417. else if (!is_well_formed_unit_identifier(unit.as_string().string()))
  418. return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, unit, "unit"sv);
  419. // 13. Let unitDisplay be ? GetOption(options, "unitDisplay", "string", « "short", "narrow", "long" », "short").
  420. auto unit_display = TRY(get_option(global_object, options, vm.names.unitDisplay, Value::Type::String, { "short"sv, "narrow"sv, "long"sv }, "short"sv));
  421. // 14. If style is "currency", then
  422. if (intl_object.style() == NumberFormat::Style::Currency) {
  423. // a. Let currency be the result of converting currency to upper case as specified in 6.1.
  424. // b. Set intlObj.[[Currency]] to currency.
  425. intl_object.set_currency(currency.as_string().string().to_uppercase());
  426. // c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
  427. intl_object.set_currency_display(currency_display.as_string().string());
  428. // d. Set intlObj.[[CurrencySign]] to currencySign.
  429. intl_object.set_currency_sign(currency_sign.as_string().string());
  430. }
  431. // 15. If style is "unit", then
  432. if (intl_object.style() == NumberFormat::Style::Unit) {
  433. // a. Set intlObj.[[Unit]] to unit.
  434. intl_object.set_unit(unit.as_string().string());
  435. // b. Set intlObj.[[UnitDisplay]] to unitDisplay.
  436. intl_object.set_unit_display(unit_display.as_string().string());
  437. }
  438. return {};
  439. }
  440. }