mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 23:08:39 +09:00
Issue #2259 - Performance improvements in Locale
- Move BestAvailableLocale function to C++ - Move default locale computation to C++ - Add available-locales set to SharedIntlData - Remove separate sets for DateFormat and NumberFormat available locales. Based-on: m-c 1373089
This commit is contained in:
parent
c10a29d96f
commit
4ad4a82a10
28 changed files with 647 additions and 461 deletions
|
|
@ -24,7 +24,6 @@
|
|||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::ReportInternalError;
|
||||
using js::intl::SharedIntlData;
|
||||
|
|
@ -185,19 +184,6 @@ js::CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObjec
|
|||
return proto;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_Collator_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedValue result(cx);
|
||||
if (!GetAvailableLocales(cx, ucol_countAvailable, ucol_getAvailable, &result))
|
||||
return false;
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_availableCollations(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -52,17 +52,6 @@ CreateCollatorPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_Collator(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for collation
|
||||
* by having a true-valued property for each such locale with the
|
||||
* canonicalized language tag as the property name. The object has no
|
||||
* prototype.
|
||||
*
|
||||
* Usage: availableLocales = intl_Collator_availableLocales()
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_Collator_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an array with the collation type identifiers per Unicode
|
||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function resolveCollatorInternals(lazyCollatorData)
|
|||
var relevantExtensionKeys = Collator.relevantExtensionKeys;
|
||||
|
||||
// Step 17.
|
||||
var r = ResolveLocale(callFunction(Collator.availableLocales, Collator),
|
||||
var r = ResolveLocale("Collator",
|
||||
lazyCollatorData.requestedLocales,
|
||||
lazyCollatorData.opt,
|
||||
relevantExtensionKeys,
|
||||
|
|
@ -203,8 +203,7 @@ function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
|
|||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 1.
|
||||
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
|
||||
collatorInternalProperties);
|
||||
var availableLocales = "Collator";
|
||||
|
||||
// Step 2.
|
||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
|
@ -222,17 +221,6 @@ function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
|
|||
var collatorInternalProperties = {
|
||||
sortLocaleData: collatorSortLocaleData,
|
||||
searchLocaleData: collatorSearchLocaleData,
|
||||
_availableLocales: null,
|
||||
availableLocales: function()
|
||||
{
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
|
||||
locales = intl_Collator_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["co", "kn", "kf"]
|
||||
};
|
||||
|
||||
|
|
@ -245,10 +233,8 @@ function collatorActualLocale(locale) {
|
|||
|
||||
// If |locale| is the default locale (e.g. da-DK), but only supported
|
||||
// through a fallback (da), we need to get the actual locale before we
|
||||
// can call intl_isUpperCaseFirst. Also see BestAvailableLocaleHelper.
|
||||
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
|
||||
collatorInternalProperties);
|
||||
return BestAvailableLocaleIgnoringDefault(availableLocales, locale);
|
||||
// can call intl_isUpperCaseFirst. Also see intl_BestAvailableLocale.
|
||||
return BestAvailableLocaleIgnoringDefault("Collator", locale);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -83,33 +83,10 @@ js::intl::ReportInternalError(JSContext* cx)
|
|||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl::GetAvailableLocales(JSContext* cx, CountAvailable countAvailable,
|
||||
GetAvailable getAvailable, MutableHandleValue result)
|
||||
{
|
||||
RootedObject locales(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
|
||||
if (!locales)
|
||||
return false;
|
||||
const js::intl::OldStyleLanguageTagMapping
|
||||
js::intl::oldStyleLanguageTagMappings[] = {
|
||||
{"pa-PK", "pa-Arab-PK"}, {"zh-CN", "zh-Hans-CN"},
|
||||
{"zh-HK", "zh-Hant-HK"}, {"zh-SG", "zh-Hans-SG"},
|
||||
{"zh-TW", "zh-Hant-TW"},
|
||||
};
|
||||
|
||||
uint32_t count = countAvailable();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const char* locale = getAvailable(i);
|
||||
auto lang = DuplicateString(cx, locale);
|
||||
if (!lang)
|
||||
return false;
|
||||
char* p;
|
||||
while ((p = strchr(lang.get(), '_')))
|
||||
*p = '-';
|
||||
RootedAtom a(cx, Atomize(cx, lang.get(), strlen(lang.get())));
|
||||
if (!a)
|
||||
return false;
|
||||
if (!DefineProperty(cx, locales, a->asPropertyName(), TrueHandleValue, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result.setObject(*locales);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,32 @@ StringsAreEqual(JSAutoByteString& s1, const char* s2)
|
|||
return !strcmp(s1.ptr(), s2);
|
||||
}
|
||||
|
||||
/**
|
||||
* The last-ditch locale is used if none of the available locales satisfies a
|
||||
* request. "en-GB" is used based on the assumptions that English is the most
|
||||
* common second language, that both en-GB and en-US are normally available in
|
||||
* an implementation, and that en-GB is more representative of the English used
|
||||
* in other locales.
|
||||
*/
|
||||
static inline const char* LastDitchLocale() { return "en-GB"; }
|
||||
|
||||
/**
|
||||
* Certain old, commonly-used language tags that lack a script, are expected to
|
||||
* nonetheless imply one. This object maps these old-style tags to modern
|
||||
* equivalents.
|
||||
*/
|
||||
struct OldStyleLanguageTagMapping {
|
||||
const char* const oldStyle;
|
||||
const char* const modernStyle;
|
||||
|
||||
// Provide a constructor to catch missing initializers in the mappings array.
|
||||
constexpr OldStyleLanguageTagMapping(const char* oldStyle,
|
||||
const char* modernStyle)
|
||||
: oldStyle(oldStyle), modernStyle(modernStyle) {}
|
||||
};
|
||||
|
||||
extern const OldStyleLanguageTagMapping oldStyleLanguageTagMappings[5];
|
||||
|
||||
static inline const char*
|
||||
IcuLocale(const char* locale)
|
||||
{
|
||||
|
|
@ -129,25 +155,6 @@ CallICU(JSContext* cx, const ICUStringFunction& strFn)
|
|||
return NewStringCopyN<CanGC>(cx, chars.begin(), size_t(size));
|
||||
}
|
||||
|
||||
// CountAvailable and GetAvailable describe the signatures used for ICU API
|
||||
// to determine available locales for various functionality.
|
||||
using CountAvailable = int32_t (*)();
|
||||
using GetAvailable = const char* (*)(int32_t localeIndex);
|
||||
|
||||
/**
|
||||
* Return an object whose own property names are the locales indicated as
|
||||
* available by |countAvailable| that provides an overall count, and by
|
||||
* |getAvailable| that when called passing a number less than that count,
|
||||
* returns the corresponding locale as a borrowed string. For example:
|
||||
*
|
||||
* RootedValue v(cx);
|
||||
* if (!GetAvailableLocales(cx, unum_countAvailable, unum_getAvailable, &v))
|
||||
* return false;
|
||||
*/
|
||||
extern bool
|
||||
GetAvailableLocales(JSContext* cx, CountAvailable countAvailable, GetAvailable getAvailable,
|
||||
JS::MutableHandle<JS::Value> result);
|
||||
|
||||
} // namespace intl
|
||||
|
||||
} // namespace js
|
||||
|
|
|
|||
|
|
@ -138,78 +138,12 @@ function IsASCIIAlphaString(s) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// The last-ditch locale is used if none of the available locales satisfies a
|
||||
// request. "en-GB" is used based on the assumptions that English is the most
|
||||
// common second language, that both en-GB and en-US are normally available in
|
||||
// an implementation, and that en-GB is more representative of the English used
|
||||
// in other locales.
|
||||
function lastDitchLocale() {
|
||||
// Per bug 1177929, strings don't clone out of self-hosted code as atoms,
|
||||
// breaking IonBuilder::constant. Put this in a function for now.
|
||||
return "en-GB";
|
||||
}
|
||||
|
||||
|
||||
// Certain old, commonly-used language tags that lack a script, are expected to
|
||||
// nonetheless imply one. This object maps these old-style tags to modern
|
||||
// equivalents.
|
||||
var oldStyleLanguageTagMappings = {
|
||||
"pa-PK": "pa-Arab-PK",
|
||||
"zh-CN": "zh-Hans-CN",
|
||||
"zh-HK": "zh-Hant-HK",
|
||||
"zh-SG": "zh-Hans-SG",
|
||||
"zh-TW": "zh-Hant-TW",
|
||||
};
|
||||
|
||||
|
||||
var localeCandidateCache = {
|
||||
runtimeDefaultLocale: undefined,
|
||||
candidateDefaultLocale: undefined,
|
||||
};
|
||||
|
||||
|
||||
var localeCache = {
|
||||
runtimeDefaultLocale: undefined,
|
||||
defaultLocale: undefined,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compute the candidate default locale: the locale *requested* to be used as
|
||||
* the default locale. We'll use it if and only if ICU provides support (maybe
|
||||
* fallback support, e.g. supporting "de-ZA" through "de" support implied by a
|
||||
* "de-DE" locale).
|
||||
*/
|
||||
function DefaultLocaleIgnoringAvailableLocales() {
|
||||
const runtimeDefaultLocale = RuntimeDefaultLocale();
|
||||
if (runtimeDefaultLocale === localeCandidateCache.runtimeDefaultLocale)
|
||||
return localeCandidateCache.candidateDefaultLocale;
|
||||
|
||||
// If we didn't get a cache hit, compute the candidate default locale and
|
||||
// cache it. Fall back on the last-ditch locale when necessary.
|
||||
var candidate = intl_TryValidateAndCanonicalizeLanguageTag(runtimeDefaultLocale);
|
||||
if (candidate === null) {
|
||||
candidate = lastDitchLocale();
|
||||
} else {
|
||||
// The default locale must be in [[availableLocales]], and that list
|
||||
// must not contain any locales with Unicode extension sequences, so
|
||||
// remove any present in the candidate.
|
||||
candidate = removeUnicodeExtensions(candidate);
|
||||
|
||||
if (hasOwn(candidate, oldStyleLanguageTagMappings))
|
||||
candidate = oldStyleLanguageTagMappings[candidate];
|
||||
}
|
||||
|
||||
// Cache the candidate locale until the runtime default locale changes.
|
||||
localeCandidateCache.candidateDefaultLocale = candidate;
|
||||
localeCandidateCache.runtimeDefaultLocale = runtimeDefaultLocale;
|
||||
|
||||
assertIsValidAndCanonicalLanguageTag(candidate, "the candidate");
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the BCP 47 language tag for the host environment's current locale.
|
||||
*
|
||||
|
|
@ -221,29 +155,13 @@ function DefaultLocale() {
|
|||
return localeCache.defaultLocale;
|
||||
|
||||
// If we didn't have a cache hit, compute the candidate default locale.
|
||||
// Then use it as the actual default locale if ICU supports that locale
|
||||
// (perhaps via fallback). Otherwise use the last-ditch locale.
|
||||
var candidate = DefaultLocaleIgnoringAvailableLocales();
|
||||
var locale;
|
||||
if (BestAvailableLocaleIgnoringDefault(callFunction(collatorInternalProperties.availableLocales,
|
||||
collatorInternalProperties),
|
||||
candidate) &&
|
||||
BestAvailableLocaleIgnoringDefault(callFunction(numberFormatInternalProperties.availableLocales,
|
||||
numberFormatInternalProperties),
|
||||
candidate) &&
|
||||
BestAvailableLocaleIgnoringDefault(callFunction(dateTimeFormatInternalProperties.availableLocales,
|
||||
dateTimeFormatInternalProperties),
|
||||
candidate))
|
||||
{
|
||||
locale = candidate;
|
||||
} else {
|
||||
locale = lastDitchLocale();
|
||||
}
|
||||
var locale = intl_supportedLocaleOrFallback(runtimeDefaultLocale);
|
||||
|
||||
assertIsValidAndCanonicalLanguageTag(locale, "the computed default locale");
|
||||
assert(startOfUnicodeExtensions(locale) < 0,
|
||||
"the computed default locale must not contain a Unicode extension sequence");
|
||||
|
||||
// Cache the computed locale until the runtime default locale changes.
|
||||
localeCache.defaultLocale = locale;
|
||||
localeCache.runtimeDefaultLocale = runtimeDefaultLocale;
|
||||
|
||||
|
|
@ -251,31 +169,6 @@ function DefaultLocale() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add old-style language tags without script code for locales that in current
|
||||
* usage would include a script subtag. Also add an entry for the last-ditch
|
||||
* locale, in case ICU doesn't directly support it (but does support it through
|
||||
* fallback, e.g. supporting "en-GB" indirectly using "en" support).
|
||||
*/
|
||||
function addSpecialMissingLanguageTags(availableLocales) {
|
||||
// Certain old-style language tags lack a script code, but in current usage
|
||||
// they *would* include a script code. Map these over to modern forms.
|
||||
var oldStyleLocales = std_Object_getOwnPropertyNames(oldStyleLanguageTagMappings);
|
||||
for (var i = 0; i < oldStyleLocales.length; i++) {
|
||||
var oldStyleLocale = oldStyleLocales[i];
|
||||
if (availableLocales[oldStyleLanguageTagMappings[oldStyleLocale]])
|
||||
availableLocales[oldStyleLocale] = true;
|
||||
}
|
||||
|
||||
// Also forcibly provide the last-ditch locale.
|
||||
var lastDitch = lastDitchLocale();
|
||||
assert(lastDitch === "en-GB" && availableLocales["en"],
|
||||
"shouldn't be a need to add every locale implied by the last-" +
|
||||
"ditch locale, merely just the last-ditch locale");
|
||||
availableLocales[lastDitch] = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Canonicalizes a locale list.
|
||||
*
|
||||
|
|
@ -336,49 +229,6 @@ function CanonicalizeLocaleList(locales) {
|
|||
}
|
||||
|
||||
|
||||
function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLocale) {
|
||||
assertIsValidAndCanonicalLanguageTag(locale, "BestAvailableLocale locale");
|
||||
assert(startOfUnicodeExtensions(locale) < 0, "locale must contain no Unicode extensions");
|
||||
|
||||
// In the spec, [[availableLocales]] is formally a list of all available
|
||||
// locales. But in our implementation, it's an *incomplete* list, not
|
||||
// necessarily including the default locale (and all locales implied by it,
|
||||
// e.g. "de" implied by "de-CH"), if that locale isn't in every
|
||||
// [[availableLocales]] list (because that locale is supported through
|
||||
// fallback, e.g. "de-CH" supported through "de").
|
||||
//
|
||||
// If we're considering the default locale, augment the spec loop with
|
||||
// additional checks to also test whether the current prefix is a prefix of
|
||||
// the default locale.
|
||||
|
||||
var defaultLocale;
|
||||
if (considerDefaultLocale)
|
||||
defaultLocale = DefaultLocale();
|
||||
|
||||
var candidate = locale;
|
||||
while (true) {
|
||||
if (availableLocales[candidate])
|
||||
return candidate;
|
||||
|
||||
if (considerDefaultLocale && candidate.length <= defaultLocale.length) {
|
||||
if (candidate === defaultLocale)
|
||||
return candidate;
|
||||
if (callFunction(std_String_startsWith, defaultLocale, candidate + "-"))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
var pos = callFunction(std_String_lastIndexOf, candidate, "-");
|
||||
if (pos === -1)
|
||||
return undefined;
|
||||
|
||||
if (pos >= 2 && candidate[pos - 2] === "-")
|
||||
pos -= 2;
|
||||
|
||||
candidate = callFunction(String_substring, candidate, 0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares a BCP 47 language tag against the locales in availableLocales
|
||||
* and returns the best available match. Uses the fallback
|
||||
|
|
@ -388,16 +238,15 @@ function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLoca
|
|||
* Spec: RFC 4647, section 3.4.
|
||||
*/
|
||||
function BestAvailableLocale(availableLocales, locale) {
|
||||
return BestAvailableLocaleHelper(availableLocales, locale, true);
|
||||
return intl_BestAvailableLocale(availableLocales, locale, DefaultLocale());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identical to BestAvailableLocale, but does not consider the default locale
|
||||
* during computation.
|
||||
*/
|
||||
function BestAvailableLocaleIgnoringDefault(availableLocales, locale) {
|
||||
return BestAvailableLocaleHelper(availableLocales, locale, false);
|
||||
return intl_BestAvailableLocale(availableLocales, locale, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ using JS::TimeClip;
|
|||
|
||||
using js::intl::CallICU;
|
||||
using js::intl::DateTimeFormatOptions;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||
using js::intl::SharedIntlData;
|
||||
|
|
@ -228,19 +227,6 @@ js::AddMozDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl)
|
|||
return mozDateTimeFormatProto != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_DateTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedValue result(cx);
|
||||
if (!GetAvailableLocales(cx, udat_countAvailable, udat_getAvailable, &result))
|
||||
return false;
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,17 +54,6 @@ CreateDateTimeFormatPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for date and time
|
||||
* formatting by having a true-valued property for each such locale with the
|
||||
* canonicalized language tag as the property name. The object has no
|
||||
* prototype.
|
||||
*
|
||||
* Usage: availableLocales = intl_DateTimeFormat_availableLocales()
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_DateTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an array with the calendar type identifiers per Unicode
|
||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
|||
var localeData = DateTimeFormat.localeData;
|
||||
|
||||
// Step 11.
|
||||
var r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||
var r = ResolveLocale("DateTimeFormat",
|
||||
lazyDateTimeFormatData.requestedLocales,
|
||||
lazyDateTimeFormatData.localeOpt,
|
||||
DateTimeFormat.relevantExtensionKeys,
|
||||
|
|
@ -852,8 +852,7 @@ function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
|||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 1.
|
||||
var availableLocales = callFunction(dateTimeFormatInternalProperties.availableLocales,
|
||||
dateTimeFormatInternalProperties);
|
||||
var availableLocales = "DateTimeFormat";
|
||||
|
||||
// Step 2.
|
||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
|
@ -870,17 +869,6 @@ function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
|||
*/
|
||||
var dateTimeFormatInternalProperties = {
|
||||
localeData: dateTimeFormatLocaleData,
|
||||
_availableLocales: null,
|
||||
availableLocales: function()
|
||||
{
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
|
||||
locales = intl_DateTimeFormat_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["ca", "nu", "hc"]
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "unicode/udatpg.h"
|
||||
#include "unicode/udisplaycontext.h"
|
||||
#include "unicode/uenum.h"
|
||||
#include "unicode/uloc.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/unumsys.h"
|
||||
#include "unicode/upluralrules.h"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
|
|
@ -18,12 +21,15 @@
|
|||
#include "builtin/intl/Collator.h"
|
||||
#include "builtin/intl/CommonFunctions.h"
|
||||
#include "builtin/intl/DateTimeFormat.h"
|
||||
#include "builtin/intl/LanguageTag.h"
|
||||
#include "builtin/intl/ICUHeader.h"
|
||||
#include "builtin/intl/Locale.h"
|
||||
#include "builtin/intl/NumberFormat.h"
|
||||
#include "builtin/intl/PluralRules.h"
|
||||
#include "builtin/intl/RelativeTimeFormat.h"
|
||||
#include "builtin/intl/ScopedICUObject.h"
|
||||
#include "builtin/intl/SharedIntlData.h"
|
||||
#include "js/Result.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
|
@ -32,7 +38,6 @@ using namespace js;
|
|||
|
||||
using js::intl::CallICU;
|
||||
using js::intl::DateTimeFormatOptions;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||
using js::intl::StringsAreEqual;
|
||||
|
|
@ -407,6 +412,275 @@ js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
using SupportedLocaleKind = js::intl::SharedIntlData::SupportedLocaleKind;
|
||||
|
||||
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
|
||||
static JS::Result<JSString*>
|
||||
BestAvailableLocale(JSContext* cx, SupportedLocaleKind kind, HandleLinearString locale,
|
||||
HandleLinearString defaultLocale)
|
||||
{
|
||||
// In the spec, [[availableLocales]] is formally a list of all available
|
||||
// locales. But in our implementation, it's an *incomplete* list, not
|
||||
// necessarily including the default locale (and all locales implied by it,
|
||||
// e.g. "de" implied by "de-CH"), if that locale isn't in every
|
||||
// [[availableLocales]] list (because that locale is supported through
|
||||
// fallback, e.g. "de-CH" supported through "de").
|
||||
//
|
||||
// If we're considering the default locale, augment the spec loop with
|
||||
// additional checks to also test whether the current prefix is a prefix of
|
||||
// the default locale.
|
||||
|
||||
intl::SharedIntlData& sharedIntlData = cx->sharedIntlData;
|
||||
|
||||
auto findLast = [](const auto* chars, size_t length) {
|
||||
auto rbegin = std::make_reverse_iterator(chars + length);
|
||||
auto rend = std::make_reverse_iterator(chars);
|
||||
auto p = std::find(rbegin, rend, '-');
|
||||
|
||||
// |dist(chars, p.base())| is equal to |dist(p, rend)|, pick whichever you
|
||||
// find easier to reason about when using reserve iterators.
|
||||
ptrdiff_t r = std::distance(chars, p.base());
|
||||
MOZ_ASSERT(r == std::distance(p, rend));
|
||||
|
||||
// But always subtract one to convert from the reverse iterator result to
|
||||
// the corresponding forward iterator value, because reserve iterators point
|
||||
// to one element past the forward iterator value.
|
||||
return r - 1;
|
||||
};
|
||||
|
||||
// Step 1.
|
||||
RootedLinearString candidate(cx, locale);
|
||||
|
||||
// Step 2.
|
||||
while (true) {
|
||||
// Step 2.a.
|
||||
bool supported = false;
|
||||
if (!sharedIntlData.isSupportedLocale(cx, kind, candidate, &supported)) {
|
||||
return cx->alreadyReportedError();
|
||||
}
|
||||
if (supported) {
|
||||
return candidate.get();
|
||||
}
|
||||
|
||||
if (defaultLocale && candidate->length() <= defaultLocale->length()) {
|
||||
if (EqualStrings(candidate, defaultLocale)) {
|
||||
return candidate.get();
|
||||
}
|
||||
|
||||
if (candidate->length() < defaultLocale->length() &&
|
||||
HasSubstringAt(defaultLocale, candidate, 0) &&
|
||||
defaultLocale->latin1OrTwoByteChar(candidate->length()) == '-') {
|
||||
return candidate.get();
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.b.
|
||||
ptrdiff_t pos;
|
||||
if (candidate->hasLatin1Chars()) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
pos = findLast(candidate->latin1Chars(nogc), candidate->length());
|
||||
} else {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
pos = findLast(candidate->twoByteChars(nogc), candidate->length());
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 2.c.
|
||||
size_t length = size_t(pos);
|
||||
if (length >= 2 && candidate->latin1OrTwoByteChar(length - 2) == '-') {
|
||||
length -= 2;
|
||||
}
|
||||
|
||||
// Step 2.d.
|
||||
candidate = NewDependentString(cx, candidate, 0, length);
|
||||
if (!candidate) {
|
||||
return cx->alreadyReportedError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9.2.2 BestAvailableLocale ( availableLocales, locale )
|
||||
//
|
||||
// Carries an additional third argument in our implementation to provide the
|
||||
// default locale. See the doc-comment in the header file.
|
||||
bool
|
||||
js::intl_BestAvailableLocale(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 3);
|
||||
|
||||
SupportedLocaleKind kind;
|
||||
{
|
||||
JSLinearString* typeStr = args[0].toString()->ensureLinear(cx);
|
||||
if (!typeStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringEqualsAscii(typeStr, "Collator")) {
|
||||
kind = SupportedLocaleKind::Collator;
|
||||
} else if (StringEqualsAscii(typeStr, "DateTimeFormat")) {
|
||||
kind = SupportedLocaleKind::DateTimeFormat;
|
||||
} else if (StringEqualsAscii(typeStr, "NumberFormat")) {
|
||||
kind = SupportedLocaleKind::NumberFormat;
|
||||
} else if (StringEqualsAscii(typeStr, "PluralRules")) {
|
||||
kind = SupportedLocaleKind::PluralRules;
|
||||
} else {
|
||||
MOZ_ASSERT(StringEqualsAscii(typeStr, "RelativeTimeFormat"));
|
||||
kind = SupportedLocaleKind::RelativeTimeFormat;
|
||||
}
|
||||
}
|
||||
|
||||
RootedLinearString locale(cx, args[1].toString()->ensureLinear(cx));
|
||||
if (!locale) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
intl::LanguageTag tag(cx);
|
||||
bool ok;
|
||||
JS_TRY_VAR_OR_RETURN_FALSE(cx, ok, intl::LanguageTagParser::tryParse(cx, locale, tag));
|
||||
MOZ_ASSERT(ok, "locale is a structurally valid language tag");
|
||||
|
||||
auto isUnicodeExtension = [](const auto& extension) {
|
||||
return extension[0] == 'u';
|
||||
};
|
||||
MOZ_ASSERT(std::none_of(tag.extensions().begin(), tag.extensions().end(), isUnicodeExtension),
|
||||
"locale must contain no Unicode extensions");
|
||||
|
||||
if (!tag.canonicalize(cx, intl::LanguageTag::UnicodeExtensionCanonicalForm::No)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* tagStr = tag.toString(cx);
|
||||
if (!tagStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool canonical;
|
||||
if (!EqualStrings(cx, locale, tagStr, &canonical)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(canonical, "locale is a canonicalized language tag");
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(args[2].isNull() || args[2].isString());
|
||||
|
||||
RootedLinearString defaultLocale(cx);
|
||||
if (args[2].isString()) {
|
||||
defaultLocale = args[2].toString()->ensureLinear(cx);
|
||||
if (!defaultLocale) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JSString* result;
|
||||
JS_TRY_VAR_OR_RETURN_FALSE(cx, result, BestAvailableLocale(cx, kind, locale, defaultLocale));
|
||||
|
||||
if (result) {
|
||||
args.rval().setString(result);
|
||||
} else {
|
||||
args.rval().setUndefined();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_supportedLocaleOrFallback(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
|
||||
RootedLinearString locale(cx, args[0].toString()->ensureLinear(cx));
|
||||
if (!locale) {
|
||||
return false;
|
||||
}
|
||||
|
||||
intl::LanguageTag tag(cx);
|
||||
bool ok;
|
||||
JS_TRY_VAR_OR_RETURN_FALSE(cx, ok, intl::LanguageTagParser::tryParse(cx, locale, tag));
|
||||
|
||||
RootedLinearString candidate(cx);
|
||||
if (!ok) {
|
||||
candidate = NewStringCopyZ<CanGC>(cx, intl::LastDitchLocale());
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!tag.canonicalize(cx, intl::LanguageTag::UnicodeExtensionCanonicalForm::No)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The default locale must be in [[AvailableLocales]], and that list must
|
||||
// not contain any locales with Unicode extension sequences, so remove any
|
||||
// present in the candidate.
|
||||
tag.clearUnicodeExtension();
|
||||
|
||||
JSString* canonical = tag.toString(cx);
|
||||
if (!canonical) {
|
||||
return false;
|
||||
}
|
||||
|
||||
candidate = canonical->ensureLinear(cx);
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& mapping : js::intl::oldStyleLanguageTagMappings) {
|
||||
const char* oldStyle = mapping.oldStyle;
|
||||
const char* modernStyle = mapping.modernStyle;
|
||||
|
||||
if (StringEqualsAscii(candidate, oldStyle)) {
|
||||
candidate = NewStringCopyZ<CanGC>(cx, modernStyle);
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9.1 Internal slots of Service Constructors
|
||||
//
|
||||
// - [[AvailableLocales]] is a List [...]. The list must include the value
|
||||
// returned by the DefaultLocale abstract operation (6.2.4), [...].
|
||||
//
|
||||
// That implies we must ignore any candidate which isn't supported by all Intl
|
||||
// service constructors.
|
||||
//
|
||||
// Note: We don't test the supported locales of either Intl.PluralRules or
|
||||
// Intl.RelativeTimeFormat, because ICU doesn't provide the necessary API to
|
||||
// return actual set of supported locales for these constructors. Instead it
|
||||
// returns the complete set of available locales for ULocale, which is a
|
||||
// superset of the locales supported by Collator, NumberFormat, and
|
||||
// DateTimeFormat.
|
||||
bool isSupported = true;
|
||||
for (auto kind : {SupportedLocaleKind::Collator, SupportedLocaleKind::DateTimeFormat,
|
||||
SupportedLocaleKind::NumberFormat}) {
|
||||
JSString* supported;
|
||||
JS_TRY_VAR_OR_RETURN_FALSE(cx, supported, BestAvailableLocale(cx, kind, candidate, nullptr));
|
||||
|
||||
if (!supported) {
|
||||
isSupported = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSupported) {
|
||||
candidate = NewStringCopyZ<CanGC>(cx, intl::LastDitchLocale());
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
args.rval().setString(candidate);
|
||||
return true;
|
||||
}
|
||||
|
||||
const Class js::IntlClass = {
|
||||
js_Object_str,
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Intl)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,35 @@ intl_GetCalendarInfo(JSContext* cx, unsigned argc, JS::Value* vp);
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_ComputeDisplayNames(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
/**
|
||||
* Compares a BCP 47 language tag against the locales in availableLocales and
|
||||
* returns the best available match -- or |undefined| if no match was found.
|
||||
* Uses the fallback mechanism of RFC 4647, section 3.4.
|
||||
*
|
||||
* The set of available locales consulted doesn't necessarily include the
|
||||
* default locale or any generalized forms of it (e.g. "de" is a more-general
|
||||
* form of "de-CH"). If you want to be sure to consider the default local and
|
||||
* its generalized forms (you usually will), pass the default locale as the
|
||||
* value of |defaultOrNull|; otherwise pass null.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 9.2.2.
|
||||
* Spec: RFC 4647, section 3.4.
|
||||
*
|
||||
* Usage: result = intl_BestAvailableLocale("Collator", locale, defaultOrNull)
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_BestAvailableLocale(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
/**
|
||||
* Returns the input locale in its canonicalized form if ICU supports that
|
||||
* locale (perhaps via fallback, e.g. supporting "de-ZA" through "de" support
|
||||
* implied by a "de-DE" locale). Otherwise uses the last-ditch locale.
|
||||
*
|
||||
* Usage: result = intl_supportedLocaleOrFallback(locale)
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_supportedLocaleOrFallback(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* builtin_intl_IntlObject_h */
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ function Intl_getCalendarInfo(locales) {
|
|||
// 5. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]],
|
||||
// requestedLocales, localeOpt,
|
||||
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||
const r = ResolveLocale("DateTimeFormat",
|
||||
requestedLocales,
|
||||
localeOpt,
|
||||
DateTimeFormat.relevantExtensionKeys,
|
||||
|
|
@ -129,11 +129,11 @@ function Intl_getDisplayNames(locales, options) {
|
|||
|
||||
// 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
|
||||
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||
requestedLocales,
|
||||
localeOpt,
|
||||
DateTimeFormat.relevantExtensionKeys,
|
||||
localeData);
|
||||
const r = ResolveLocale("DateTimeFormat",
|
||||
requestedLocales,
|
||||
localeOpt,
|
||||
DateTimeFormat.relevantExtensionKeys,
|
||||
localeData);
|
||||
|
||||
// 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
|
||||
const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
|
||||
|
|
|
|||
|
|
@ -199,6 +199,15 @@ bool LanguageTag::setUnicodeExtension(UniqueChars extension) {
|
|||
return extensions_.append(std::move(extension));
|
||||
}
|
||||
|
||||
void LanguageTag::clearUnicodeExtension() {
|
||||
auto p = std::find_if(extensions().begin(), extensions().end(),
|
||||
[](const auto& ext) { return ext[0] == 'u'; });
|
||||
if (p != extensions().end()) {
|
||||
size_t index = std::distance(extensions().begin(), p);
|
||||
extensions_.erase(extensions_.begin() + index);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t InitialCapacity>
|
||||
static bool SortAlphabetically(JSContext* cx,
|
||||
Vector<UniqueChars, InitialCapacity>& subtags) {
|
||||
|
|
@ -754,8 +763,13 @@ bool LanguageTag::canonicalizeTransformExtension(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LanguageTag::appendTo(JSContext* cx, StringBuffer& sb) const {
|
||||
return LanguageTagToString(cx, *this, sb);
|
||||
JSString* LanguageTag::toString(JSContext* cx) const {
|
||||
StringBuffer sb(cx);
|
||||
if (!LanguageTagToString(cx, *this, sb)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sb.finishString();
|
||||
}
|
||||
|
||||
// Zero-terminated ICU Locale ID.
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ class JSString;
|
|||
|
||||
namespace js {
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
namespace intl {
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
@ -315,6 +313,11 @@ class MOZ_STACK_CLASS LanguageTag final {
|
|||
*/
|
||||
bool setUnicodeExtension(JS::UniqueChars extension);
|
||||
|
||||
/**
|
||||
* Remove any Unicode extension subtag if present.
|
||||
*/
|
||||
void clearUnicodeExtension();
|
||||
|
||||
/**
|
||||
* Set the private-use subtag. The input must be a valid, case-normalized
|
||||
* private-use subtag or the empty string.
|
||||
|
|
@ -374,10 +377,9 @@ class MOZ_STACK_CLASS LanguageTag final {
|
|||
}
|
||||
|
||||
/**
|
||||
* Append the string representation of this language tag to the given
|
||||
* string buffer.
|
||||
* Return the string representation of this language tag.
|
||||
*/
|
||||
bool appendTo(JSContext* cx, StringBuffer& sb) const;
|
||||
JSString* toString(JSContext* cx) const;
|
||||
|
||||
/**
|
||||
* Add likely-subtags to the language tag.
|
||||
|
|
|
|||
|
|
@ -106,12 +106,7 @@ static LocaleObject* CreateLocaleObject(JSContext* cx, HandleObject prototype,
|
|||
}
|
||||
}
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!tag.appendTo(cx, sb)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedString tagStr(cx, sb.finishString());
|
||||
RootedString tagStr(cx, tag.toString(cx));
|
||||
if (!tagStr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1320,12 +1315,7 @@ bool js::intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx, unsigned argc,
|
|||
return false;
|
||||
}
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!tag.appendTo(cx, sb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* resultStr = sb.finishString();
|
||||
JSString* resultStr = tag.toString(cx);
|
||||
if (!resultStr) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1358,12 +1348,7 @@ bool js::intl_TryValidateAndCanonicalizeLanguageTag(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!tag.appendTo(cx, sb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* resultStr = sb.finishString();
|
||||
JSString* resultStr = tag.toString(cx);
|
||||
if (!resultStr) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ using mozilla::IsNaN;
|
|||
using mozilla::IsNegativeZero;
|
||||
using js::intl::CallICU;
|
||||
using js::intl::DateTimeFormatOptions;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||
using js::intl::StringsAreEqual;
|
||||
|
|
@ -203,19 +202,6 @@ js::CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalO
|
|||
return proto;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_NumberFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedValue result(cx);
|
||||
if (!GetAvailableLocales(cx, unum_countAvailable, unum_getAvailable, &result))
|
||||
return false;
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_numberingSystem(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,17 +50,6 @@ CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObjec
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for number formatting
|
||||
* by having a true-valued property for each such locale with the
|
||||
* canonicalized language tag as the property name. The object has no
|
||||
* prototype.
|
||||
*
|
||||
* Usage: availableLocales = intl_NumberFormat_availableLocales()
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_NumberFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns the numbering system type identifier per Unicode
|
||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||
|
|
|
|||
|
|
@ -12,17 +12,6 @@
|
|||
*/
|
||||
var numberFormatInternalProperties = {
|
||||
localeData: numberFormatLocaleData,
|
||||
_availableLocales: null,
|
||||
availableLocales: function()
|
||||
{
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
|
||||
locales = intl_NumberFormat_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["nu"]
|
||||
};
|
||||
|
||||
|
|
@ -43,7 +32,7 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
|
|||
var localeData = NumberFormat.localeData;
|
||||
|
||||
// Step 8.
|
||||
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
|
||||
var r = ResolveLocale("NumberFormat",
|
||||
lazyNumberFormatData.requestedLocales,
|
||||
lazyNumberFormatData.opt,
|
||||
NumberFormat.relevantExtensionKeys,
|
||||
|
|
@ -396,8 +385,7 @@ function Intl_NumberFormat_supportedLocalesOf(locales /*, options*/) {
|
|||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 1.
|
||||
var availableLocales = callFunction(numberFormatInternalProperties.availableLocales,
|
||||
numberFormatInternalProperties);
|
||||
var availableLocales = "NumberFormat";
|
||||
|
||||
// Step 2.
|
||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ using namespace js;
|
|||
using mozilla::AssertedCast;
|
||||
|
||||
using js::intl::CallICU;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||
using js::intl::StringsAreEqual;
|
||||
|
|
@ -180,21 +179,6 @@ js::CreatePluralRulesPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalOb
|
|||
return proto;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_PluralRules_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedValue result(cx);
|
||||
// We're going to use ULocale availableLocales as per ICU recommendation:
|
||||
// https://ssl.icu-project.org/trac/ticket/12756
|
||||
if (!GetAvailableLocales(cx, uloc_countAvailable, uloc_getAvailable, &result))
|
||||
return false;
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This creates new UNumberFormat with calculated digit formatting
|
||||
|
|
|
|||
|
|
@ -49,17 +49,6 @@ CreatePluralRulesPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_PluralRules(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for plural rules
|
||||
* by having a true-valued property for each such locale with the
|
||||
* canonicalized language tag as the property name. The object has no
|
||||
* prototype.
|
||||
*
|
||||
* Usage: availableLocales = intl_PluralRules_availableLocales()
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_PluralRules_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns a plural rule for the number x according to the effective
|
||||
* locale and the formatting options of the given PluralRules.
|
||||
|
|
|
|||
|
|
@ -11,17 +11,6 @@
|
|||
*/
|
||||
var pluralRulesInternalProperties = {
|
||||
localeData: pluralRulesLocaleData,
|
||||
_availableLocales: null,
|
||||
availableLocales: function()
|
||||
{
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
|
||||
locales = intl_PluralRules_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: [],
|
||||
};
|
||||
|
||||
|
|
@ -50,7 +39,7 @@ function resolvePluralRulesInternals(lazyPluralRulesData) {
|
|||
var localeData = PluralRules.localeData;
|
||||
|
||||
// Step 11.
|
||||
const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules),
|
||||
const r = ResolveLocale("PluralRules",
|
||||
lazyPluralRulesData.requestedLocales,
|
||||
lazyPluralRulesData.opt,
|
||||
PluralRules.relevantExtensionKeys,
|
||||
|
|
@ -187,8 +176,8 @@ function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) {
|
|||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 1.
|
||||
var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales,
|
||||
pluralRulesInternalProperties);
|
||||
var availableLocales = "PluralRules";
|
||||
|
||||
// Step 2.
|
||||
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ using mozilla::Range;
|
|||
using mozilla::RangedPtr;
|
||||
|
||||
using js::intl::CallICU;
|
||||
using js::intl::GetAvailableLocales;
|
||||
using js::intl::IcuLocale;
|
||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||
using js::intl::StringsAreEqual;
|
||||
|
|
@ -164,22 +163,6 @@ js::CreateRelativeTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<G
|
|||
return proto;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_RelativeTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedValue result(cx);
|
||||
// We're going to use ULocale availableLocales as per ICU recommendation:
|
||||
// https://ssl.icu-project.org/trac/ticket/12756
|
||||
if (!GetAvailableLocales(cx, uloc_countAvailable, uloc_getAvailable, &result))
|
||||
return false;
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
enum class RelativeTimeNumeric
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -39,17 +39,6 @@ extern JSObject*
|
|||
CreateRelativeTimeFormatPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
||||
JS::Handle<GlobalObject*> global);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for relative time format
|
||||
* by having a true-valued property for each such locale with the
|
||||
* canonicalized language tag as the property name. The object has no
|
||||
* prototype.
|
||||
*
|
||||
* Usage: availableLocales = intl_RelativeTimeFormat_availableLocales()
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_RelativeTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns a relative time as a string formatted according to the effective
|
||||
* locale and the formatting options of the given RelativeTimeFormat.
|
||||
|
|
|
|||
|
|
@ -11,17 +11,6 @@
|
|||
*/
|
||||
var relativeTimeFormatInternalProperties = {
|
||||
localeData: relativeTimeFormatLocaleData,
|
||||
_availableLocales: null,
|
||||
availableLocales: function() // eslint-disable-line object-shorthand
|
||||
{
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
|
||||
locales = intl_RelativeTimeFormat_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: [],
|
||||
};
|
||||
|
||||
|
|
@ -41,7 +30,7 @@ function resolveRelativeTimeFormatInternals(lazyRelativeTimeFormatData) {
|
|||
var RelativeTimeFormat = relativeTimeFormatInternalProperties;
|
||||
|
||||
// Steps 7-8.
|
||||
const r = ResolveLocale(callFunction(RelativeTimeFormat.availableLocales, RelativeTimeFormat),
|
||||
const r = ResolveLocale("RelativeTimeFormat",
|
||||
lazyRelativeTimeFormatData.requestedLocales,
|
||||
lazyRelativeTimeFormatData.opt,
|
||||
RelativeTimeFormat.relevantExtensionKeys,
|
||||
|
|
@ -159,8 +148,8 @@ function Intl_RelativeTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
|||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 1.
|
||||
var availableLocales = callFunction(relativeTimeFormatInternalProperties.availableLocales,
|
||||
relativeTimeFormatInternalProperties);
|
||||
var availableLocales = "RelativeTimeFormat";
|
||||
|
||||
// Step 2.
|
||||
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "jsatom.h"
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
#include "builtin/intl/ScopedICUObject.h"
|
||||
#include "builtin/intl/TimeZoneDataGenerated.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
using js::HashNumber;
|
||||
using js::intl::StringsAreEqual;
|
||||
|
|
@ -278,6 +280,13 @@ js::intl::SharedIntlData::LocaleHasher::Lookup::Lookup(JSLinearString* locale)
|
|||
hash = mozilla::HashString(twoByteChars, length);
|
||||
}
|
||||
|
||||
js::intl::SharedIntlData::LocaleHasher::Lookup::Lookup(const char* chars,
|
||||
size_t length)
|
||||
: js::intl::SharedIntlData::LinearStringLookup(chars, length)
|
||||
{
|
||||
hash = mozilla::HashString(latin1Chars, length);
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl::SharedIntlData::LocaleHasher::match(Locale key, const Lookup& lookup)
|
||||
{
|
||||
|
|
@ -297,6 +306,173 @@ js::intl::SharedIntlData::LocaleHasher::match(Locale key, const Lookup& lookup)
|
|||
return EqualChars(keyChars, lookup.twoByteChars, lookup.length);
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl::SharedIntlData::getAvailableLocales(JSContext* cx, LocaleSet& locales,
|
||||
CountAvailable countAvailable,
|
||||
GetAvailable getAvailable)
|
||||
{
|
||||
auto addLocale = [cx, &locales](const char* locale, size_t length) {
|
||||
JSAtom* atom = Atomize(cx, locale, length);
|
||||
if (!atom)
|
||||
return false;
|
||||
|
||||
LocaleHasher::Lookup lookup(atom);
|
||||
LocaleSet::AddPtr p = locales.lookupForAdd(lookup);
|
||||
|
||||
// ICU shouldn't report any duplicate locales, but if it does, just
|
||||
// ignore the duplicated locale.
|
||||
if (!p && !locales.add(p, atom)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
js::Vector<char, 16> lang(cx);
|
||||
|
||||
int32_t count = countAvailable();
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const char* locale = getAvailable(i);
|
||||
size_t length = strlen(locale);
|
||||
|
||||
lang.clear();
|
||||
if (!lang.append(locale, length))
|
||||
return false;
|
||||
|
||||
std::replace(lang.begin(), lang.end(), '_', '-');
|
||||
|
||||
if (!addLocale(lang.begin(), length))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add old-style language tags without script code for locales that in current
|
||||
// usage would include a script subtag. Also add an entry for the last-ditch
|
||||
// locale, in case ICU doesn't directly support it (but does support it
|
||||
// through fallback, e.g. supporting "en-GB" indirectly using "en" support).
|
||||
|
||||
// Certain old-style language tags lack a script code, but in current usage
|
||||
// they *would* include a script code. Map these over to modern forms.
|
||||
for (const auto& mapping : js::intl::oldStyleLanguageTagMappings) {
|
||||
const char* oldStyle = mapping.oldStyle;
|
||||
const char* modernStyle = mapping.modernStyle;
|
||||
|
||||
LocaleHasher::Lookup lookup(modernStyle, strlen(modernStyle));
|
||||
if (locales.has(lookup)) {
|
||||
if (!addLocale(oldStyle, strlen(oldStyle)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Also forcibly provide the last-ditch locale.
|
||||
{
|
||||
const char* lastDitch = intl::LastDitchLocale();
|
||||
MOZ_ASSERT(strcmp(lastDitch, "en-GB") == 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
static constexpr char lastDitchParent[] = "en";
|
||||
|
||||
LocaleHasher::Lookup lookup(lastDitchParent, strlen(lastDitchParent));
|
||||
MOZ_ASSERT(locales.has(lookup),
|
||||
"shouldn't be a need to add every locale implied by the "
|
||||
"last-ditch locale, merely just the last-ditch locale");
|
||||
#endif
|
||||
|
||||
if (!addLocale(lastDitch, strlen(lastDitch)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
template <typename CountAvailable, typename GetAvailable>
|
||||
static bool
|
||||
IsSameAvailableLocales(CountAvailable countAvailable1,
|
||||
GetAvailable getAvailable1,
|
||||
CountAvailable countAvailable2,
|
||||
GetAvailable getAvailable2)
|
||||
{
|
||||
int32_t count = countAvailable1();
|
||||
if (count != countAvailable2()) {
|
||||
return false;
|
||||
}
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
if (getAvailable1(i) != getAvailable2(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
js::intl::SharedIntlData::ensureSupportedLocales(JSContext* cx)
|
||||
{
|
||||
if (supportedLocalesInitialized)
|
||||
return true;
|
||||
|
||||
// If ensureSupportedLocales() was called previously, but didn't complete due
|
||||
// to OOM, clear all data and start from scratch.
|
||||
if (supportedLocales.initialized())
|
||||
supportedLocales.finish();
|
||||
if (collatorSupportedLocales.initialized())
|
||||
collatorSupportedLocales.finish();
|
||||
if (!supportedLocales.init() ||
|
||||
!collatorSupportedLocales.init()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getAvailableLocales(cx, supportedLocales, uloc_countAvailable, uloc_getAvailable))
|
||||
return false;
|
||||
|
||||
if (!getAvailableLocales(cx, collatorSupportedLocales, ucol_countAvailable, ucol_getAvailable))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(IsSameAvailableLocales(uloc_countAvailable, uloc_getAvailable,
|
||||
udat_countAvailable, udat_getAvailable));
|
||||
|
||||
MOZ_ASSERT(IsSameAvailableLocales(uloc_countAvailable, uloc_getAvailable,
|
||||
unum_countAvailable, unum_getAvailable));
|
||||
|
||||
MOZ_ASSERT(!supportedLocalesInitialized, "ensureSupportedLocales is neither reentrant nor thread-safe");
|
||||
supportedLocalesInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl::SharedIntlData::isSupportedLocale(JSContext* cx,
|
||||
SupportedLocaleKind kind,
|
||||
HandleString locale,
|
||||
bool* supported)
|
||||
{
|
||||
if (!ensureSupportedLocales(cx))
|
||||
return false;
|
||||
|
||||
|
||||
RootedLinearString localeLinear(cx, locale->ensureLinear(cx));
|
||||
if (!localeLinear)
|
||||
return false;
|
||||
|
||||
LocaleHasher::Lookup lookup(localeLinear);
|
||||
switch (kind) {
|
||||
case SupportedLocaleKind::Collator:
|
||||
*supported = collatorSupportedLocales.has(lookup);
|
||||
return true;
|
||||
case SupportedLocaleKind::DateTimeFormat:
|
||||
case SupportedLocaleKind::NumberFormat:
|
||||
case SupportedLocaleKind::PluralRules:
|
||||
case SupportedLocaleKind::RelativeTimeFormat:
|
||||
*supported = supportedLocales.has(lookup);
|
||||
return true;
|
||||
}
|
||||
MOZ_CRASH("Invalid Intl constructor");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl::SharedIntlData::ensureUpperCaseFirstLocales(JSContext* cx)
|
||||
{
|
||||
|
|
@ -393,6 +569,8 @@ js::intl::SharedIntlData::destroyInstance()
|
|||
availableTimeZones.finish();
|
||||
ianaZonesTreatedAsLinksByICU.finish();
|
||||
ianaLinksCanonicalizedDifferentlyByICU.finish();
|
||||
supportedLocales.finish();
|
||||
collatorSupportedLocales.finish();
|
||||
upperCaseFirstLocales.finish();
|
||||
}
|
||||
|
||||
|
|
@ -404,6 +582,8 @@ js::intl::SharedIntlData::trace(JSTracer* trc)
|
|||
availableTimeZones.trace(trc);
|
||||
ianaZonesTreatedAsLinksByICU.trace(trc);
|
||||
ianaLinksCanonicalizedDifferentlyByICU.trace(trc);
|
||||
supportedLocales.trace(trc);
|
||||
collatorSupportedLocales.trace(trc);
|
||||
upperCaseFirstLocales.trace(trc);
|
||||
}
|
||||
}
|
||||
|
|
@ -414,5 +594,7 @@ js::intl::SharedIntlData::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
|
|||
return availableTimeZones.sizeOfExcludingThis(mallocSizeOf) +
|
||||
ianaZonesTreatedAsLinksByICU.sizeOfExcludingThis(mallocSizeOf) +
|
||||
ianaLinksCanonicalizedDifferentlyByICU.sizeOfExcludingThis(mallocSizeOf) +
|
||||
supportedLocales.sizeOfExcludingThis(mallocSizeOf) +
|
||||
collatorSupportedLocales.sizeOfExcludingThis(mallocSizeOf) +
|
||||
upperCaseFirstLocales.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ class SharedIntlData
|
|||
else
|
||||
twoByteChars = string->twoByteChars(nogc);
|
||||
}
|
||||
|
||||
LinearStringLookup(const char* chars, size_t length)
|
||||
: isLatin1(true), length(length)
|
||||
{
|
||||
latin1Chars = reinterpret_cast<const JS::Latin1Char*>(chars);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -161,6 +167,76 @@ class SharedIntlData
|
|||
*/
|
||||
bool tryCanonicalizeTimeZoneConsistentWithIANA(JSContext* cx, JS::HandleString timeZone,
|
||||
JS::MutableHandleString result);
|
||||
private:
|
||||
using Locale = JSAtom*;
|
||||
|
||||
struct LocaleHasher
|
||||
{
|
||||
struct Lookup : LinearStringLookup
|
||||
{
|
||||
explicit Lookup(JSLinearString* locale);
|
||||
Lookup(const char* chars, size_t length);
|
||||
};
|
||||
|
||||
static js::HashNumber hash(const Lookup& lookup) { return lookup.hash; }
|
||||
static bool match(Locale key, const Lookup& lookup);
|
||||
};
|
||||
|
||||
using LocaleSet = GCHashSet<Locale, LocaleHasher, SystemAllocPolicy>;
|
||||
|
||||
// Set of supported locales for all Intl service constructors except Collator,
|
||||
// which uses its own set.
|
||||
//
|
||||
// UDateFormat:
|
||||
// udat_[count,get]Available() return the same results as their
|
||||
// uloc_[count,get]Available() counterparts.
|
||||
//
|
||||
// UNumberFormatter:
|
||||
// unum_[count,get]Available() return the same results as their
|
||||
// uloc_[count,get]Available() counterparts.
|
||||
//
|
||||
// UPluralRules and URelativeDateTimeFormatter:
|
||||
// We're going to use ULocale availableLocales as per ICU recommendation:
|
||||
// https://unicode-org.atlassian.net/browse/ICU-12756
|
||||
LocaleSet supportedLocales;
|
||||
|
||||
// ucol_[count,get]Available() return different results compared to
|
||||
// uloc_[count,get]Available(), we can't use |supportedLocales| here.
|
||||
LocaleSet collatorSupportedLocales;
|
||||
|
||||
bool supportedLocalesInitialized = false;
|
||||
|
||||
// CountAvailable and GetAvailable describe the signatures used for ICU API
|
||||
// to determine available locales for various functionality.
|
||||
using CountAvailable = int32_t (*)();
|
||||
using GetAvailable = const char* (*)(int32_t localeIndex);
|
||||
|
||||
static bool getAvailableLocales(JSContext* cx, LocaleSet& locales,
|
||||
CountAvailable countAvailable,
|
||||
GetAvailable getAvailable);
|
||||
|
||||
/**
|
||||
* Precomputes the available locales sets.
|
||||
*/
|
||||
bool ensureSupportedLocales(JSContext* cx);
|
||||
|
||||
public:
|
||||
enum class SupportedLocaleKind {
|
||||
Collator,
|
||||
DateTimeFormat,
|
||||
NumberFormat,
|
||||
PluralRules,
|
||||
RelativeTimeFormat
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets |supported| to true if |locale| is supported by the requested Intl
|
||||
* service constructor. Otherwise sets |supported| to false.
|
||||
*/
|
||||
MOZ_MUST_USE bool isSupportedLocale(JSContext* cx, SupportedLocaleKind kind,
|
||||
JS::Handle<JSString*> locale,
|
||||
bool* supported);
|
||||
|
||||
private:
|
||||
/**
|
||||
* The case first parameter (BCP47 key "kf") allows to switch the order of
|
||||
|
|
@ -178,23 +254,6 @@ class SharedIntlData
|
|||
* track locales which use upper-case first as their default setting.
|
||||
*/
|
||||
|
||||
using Locale = JSAtom*;
|
||||
|
||||
struct LocaleHasher
|
||||
{
|
||||
struct Lookup : LinearStringLookup
|
||||
{
|
||||
explicit Lookup(JSLinearString* locale);
|
||||
};
|
||||
|
||||
static js::HashNumber hash(const Lookup& lookup) { return lookup.hash; }
|
||||
static bool match(Locale key, const Lookup& lookup);
|
||||
};
|
||||
|
||||
using LocaleSet = js::GCHashSet<Locale,
|
||||
LocaleHasher,
|
||||
js::SystemAllocPolicy>;
|
||||
|
||||
LocaleSet upperCaseFirstLocales;
|
||||
|
||||
bool upperCaseFirstInitialized = false;
|
||||
|
|
|
|||
|
|
@ -2462,12 +2462,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
// See builtin/intl/*.h for descriptions of the intl_* functions.
|
||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||
JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
|
||||
JS_FN("intl_BestAvailableLocale", intl_BestAvailableLocale, 3, 0),
|
||||
JS_FN("intl_supportedLocaleOrFallback", intl_supportedLocaleOrFallback, 1, 0),
|
||||
JS_FN("intl_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1,0),
|
||||
JS_FN("intl_Collator", intl_Collator, 2,0),
|
||||
JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
|
||||
JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
|
||||
JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
|
||||
JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_defaultCalendar", intl_defaultCalendar, 1,0),
|
||||
JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
|
||||
JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
|
||||
|
|
@ -2478,18 +2478,15 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("intl_isUpperCaseFirst", intl_isUpperCaseFirst, 1,0),
|
||||
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
|
||||
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
|
||||
JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
|
||||
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
|
||||
JS_FN("intl_patternForStyle", intl_patternForStyle, 3,0),
|
||||
JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
|
||||
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
|
||||
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
|
||||
JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),
|
||||
JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2,0),
|
||||
JS_FN("intl_ValidateAndCanonicalizeLanguageTag", intl_ValidateAndCanonicalizeLanguageTag, 2, 0),
|
||||
JS_FN("intl_TryValidateAndCanonicalizeLanguageTag", intl_TryValidateAndCanonicalizeLanguageTag, 1, 0),
|
||||
JS_FN("intl_RelativeTimeFormat_availableLocales", intl_RelativeTimeFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 3,0),
|
||||
|
||||
JS_INLINABLE_FN("IsCollator",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue