// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_INTL_SUPPORT #error Internationalization is expected to be enabled. #endif // V8_INTL_SUPPORT #include "src/objects/js-relative-time-format.h" #include #include #include #include "src/execution/isolate.h" #include "src/heap/factory.h" #include "src/objects/intl-objects.h" #include "src/objects/js-number-format.h" #include "src/objects/js-relative-time-format-inl.h" #include "src/objects/managed-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/option-utils.h" #include "unicode/decimfmt.h" #include "unicode/numfmt.h" #include "unicode/reldatefmt.h" #include "unicode/unum.h" namespace v8 { namespace internal { namespace { // Style: identifying the relative time format style used. // // ecma402/#sec-properties-of-intl-relativetimeformat-instances enum class Style { LONG, // Everything spelled out. SHORT, // Abbreviations used when possible. NARROW // Use the shortest possible form. }; UDateRelativeDateTimeFormatterStyle toIcuStyle(Style style) { switch (style) { case Style::LONG: return UDAT_STYLE_LONG; case Style::SHORT: return UDAT_STYLE_SHORT; case Style::NARROW: return UDAT_STYLE_NARROW; } UNREACHABLE(); } Style fromIcuStyle(UDateRelativeDateTimeFormatterStyle icu_style) { switch (icu_style) { case UDAT_STYLE_LONG: return Style::LONG; case UDAT_STYLE_SHORT: return Style::SHORT; case UDAT_STYLE_NARROW: return Style::NARROW; case UDAT_STYLE_COUNT: UNREACHABLE(); } UNREACHABLE(); } } // namespace MaybeHandle JSRelativeTimeFormat::New( Isolate* isolate, Handle map, Handle locales, Handle input_options) { // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); MAYBE_RETURN(maybe_requested_locales, Handle()); std::vector requested_locales = maybe_requested_locales.FromJust(); // 2. Set options to ? CoerceOptionsToObject(options). Handle options; const char* service = "Intl.RelativeTimeFormat"; ASSIGN_RETURN_ON_EXCEPTION( isolate, options, CoerceOptionsToObject(isolate, input_options, service), JSRelativeTimeFormat); // 4. Let opt be a new Record. // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", « // "lookup", "best fit" », "best fit"). // 6. Set opt.[[localeMatcher]] to matcher. Maybe maybe_locale_matcher = Intl::GetLocaleMatcher(isolate, options, service); MAYBE_RETURN(maybe_locale_matcher, MaybeHandle()); Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); // 7. Let _numberingSystem_ be ? GetOption(_options_, `"numberingSystem"`, // `"string"`, *undefined*, *undefined*). std::unique_ptr numbering_system_str = nullptr; Maybe maybe_numberingSystem = Intl::GetNumberingSystem( isolate, options, service, &numbering_system_str); // 8. If _numberingSystem_ is not *undefined*, then // a. If _numberingSystem_ does not match the // `(3*8alphanum) *("-" (3*8alphanum))` sequence, throw a *RangeError* // exception. MAYBE_RETURN(maybe_numberingSystem, MaybeHandle()); // 9. Set _opt_.[[nu]] to _numberingSystem_. // 10. Let localeData be %RelativeTimeFormat%.[[LocaleData]]. // 11. Let r be // ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], // requestedLocales, opt, // %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData). Maybe maybe_resolve_locale = Intl::ResolveLocale(isolate, JSRelativeTimeFormat::GetAvailableLocales(), requested_locales, matcher, {"nu"}); if (maybe_resolve_locale.IsNothing()) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError), JSRelativeTimeFormat); } Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); UErrorCode status = U_ZERO_ERROR; icu::Locale icu_locale = r.icu_locale; if (numbering_system_str != nullptr) { auto nu_extension_it = r.extensions.find("nu"); if (nu_extension_it != r.extensions.end() && nu_extension_it->second != numbering_system_str.get()) { icu_locale.setUnicodeKeywordValue("nu", nullptr, status); DCHECK(U_SUCCESS(status)); } } // 12. Let locale be r.[[Locale]]. Maybe maybe_locale_str = Intl::ToLanguageTag(icu_locale); MAYBE_RETURN(maybe_locale_str, MaybeHandle()); // 13. Set relativeTimeFormat.[[Locale]] to locale. Handle locale_str = isolate->factory()->NewStringFromAsciiChecked( maybe_locale_str.FromJust().c_str()); // 14. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]]. if (numbering_system_str != nullptr && Intl::IsValidNumberingSystem(numbering_system_str.get())) { icu_locale.setUnicodeKeywordValue("nu", numbering_system_str.get(), status); DCHECK(U_SUCCESS(status)); } // 15. Let dataLocale be r.[[DataLocale]]. // 16. Let s be ? GetOption(options, "style", "string", // «"long", "short", "narrow"», "long"). Maybe