mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-22 23:27:30 +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"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::ReportInternalError;
|
using js::intl::ReportInternalError;
|
||||||
using js::intl::SharedIntlData;
|
using js::intl::SharedIntlData;
|
||||||
|
|
@ -185,19 +184,6 @@ js::CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObjec
|
||||||
return proto;
|
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
|
bool
|
||||||
js::intl_availableCollations(JSContext* cx, unsigned argc, Value* vp)
|
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
|
extern MOZ_MUST_USE bool
|
||||||
intl_Collator(JSContext* cx, unsigned argc, Value* vp);
|
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
|
* Returns an array with the collation type identifiers per Unicode
|
||||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ function resolveCollatorInternals(lazyCollatorData)
|
||||||
var relevantExtensionKeys = Collator.relevantExtensionKeys;
|
var relevantExtensionKeys = Collator.relevantExtensionKeys;
|
||||||
|
|
||||||
// Step 17.
|
// Step 17.
|
||||||
var r = ResolveLocale(callFunction(Collator.availableLocales, Collator),
|
var r = ResolveLocale("Collator",
|
||||||
lazyCollatorData.requestedLocales,
|
lazyCollatorData.requestedLocales,
|
||||||
lazyCollatorData.opt,
|
lazyCollatorData.opt,
|
||||||
relevantExtensionKeys,
|
relevantExtensionKeys,
|
||||||
|
|
@ -203,8 +203,7 @@ function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
|
||||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
|
var availableLocales = "Collator";
|
||||||
collatorInternalProperties);
|
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
@ -222,17 +221,6 @@ function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
|
||||||
var collatorInternalProperties = {
|
var collatorInternalProperties = {
|
||||||
sortLocaleData: collatorSortLocaleData,
|
sortLocaleData: collatorSortLocaleData,
|
||||||
searchLocaleData: collatorSearchLocaleData,
|
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"]
|
relevantExtensionKeys: ["co", "kn", "kf"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -245,10 +233,8 @@ function collatorActualLocale(locale) {
|
||||||
|
|
||||||
// If |locale| is the default locale (e.g. da-DK), but only supported
|
// 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
|
// through a fallback (da), we need to get the actual locale before we
|
||||||
// can call intl_isUpperCaseFirst. Also see BestAvailableLocaleHelper.
|
// can call intl_isUpperCaseFirst. Also see intl_BestAvailableLocale.
|
||||||
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
|
return BestAvailableLocaleIgnoringDefault("Collator", locale);
|
||||||
collatorInternalProperties);
|
|
||||||
return BestAvailableLocaleIgnoringDefault(availableLocales, locale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,33 +83,10 @@ js::intl::ReportInternalError(JSContext* cx)
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
const js::intl::OldStyleLanguageTagMapping
|
||||||
js::intl::GetAvailableLocales(JSContext* cx, CountAvailable countAvailable,
|
js::intl::oldStyleLanguageTagMappings[] = {
|
||||||
GetAvailable getAvailable, MutableHandleValue result)
|
{"pa-PK", "pa-Arab-PK"}, {"zh-CN", "zh-Hans-CN"},
|
||||||
{
|
{"zh-HK", "zh-Hant-HK"}, {"zh-SG", "zh-Hans-SG"},
|
||||||
RootedObject locales(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
|
{"zh-TW", "zh-Hant-TW"},
|
||||||
if (!locales)
|
};
|
||||||
return false;
|
|
||||||
|
|
||||||
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);
|
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*
|
static inline const char*
|
||||||
IcuLocale(const char* locale)
|
IcuLocale(const char* locale)
|
||||||
{
|
{
|
||||||
|
|
@ -129,25 +155,6 @@ CallICU(JSContext* cx, const ICUStringFunction& strFn)
|
||||||
return NewStringCopyN<CanGC>(cx, chars.begin(), size_t(size));
|
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 intl
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
||||||
|
|
@ -138,78 +138,12 @@ function IsASCIIAlphaString(s) {
|
||||||
return true;
|
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 = {
|
var localeCache = {
|
||||||
runtimeDefaultLocale: undefined,
|
runtimeDefaultLocale: undefined,
|
||||||
defaultLocale: 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.
|
* Returns the BCP 47 language tag for the host environment's current locale.
|
||||||
*
|
*
|
||||||
|
|
@ -221,29 +155,13 @@ function DefaultLocale() {
|
||||||
return localeCache.defaultLocale;
|
return localeCache.defaultLocale;
|
||||||
|
|
||||||
// If we didn't have a cache hit, compute the candidate default locale.
|
// 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
|
var locale = intl_supportedLocaleOrFallback(runtimeDefaultLocale);
|
||||||
// (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();
|
|
||||||
}
|
|
||||||
|
|
||||||
assertIsValidAndCanonicalLanguageTag(locale, "the computed default locale");
|
assertIsValidAndCanonicalLanguageTag(locale, "the computed default locale");
|
||||||
assert(startOfUnicodeExtensions(locale) < 0,
|
assert(startOfUnicodeExtensions(locale) < 0,
|
||||||
"the computed default locale must not contain a Unicode extension sequence");
|
"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.defaultLocale = locale;
|
||||||
localeCache.runtimeDefaultLocale = runtimeDefaultLocale;
|
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.
|
* 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
|
* Compares a BCP 47 language tag against the locales in availableLocales
|
||||||
* and returns the best available match. Uses the fallback
|
* and returns the best available match. Uses the fallback
|
||||||
|
|
@ -388,16 +238,15 @@ function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLoca
|
||||||
* Spec: RFC 4647, section 3.4.
|
* Spec: RFC 4647, section 3.4.
|
||||||
*/
|
*/
|
||||||
function BestAvailableLocale(availableLocales, locale) {
|
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
|
* Identical to BestAvailableLocale, but does not consider the default locale
|
||||||
* during computation.
|
* during computation.
|
||||||
*/
|
*/
|
||||||
function BestAvailableLocaleIgnoringDefault(availableLocales, locale) {
|
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::CallICU;
|
||||||
using js::intl::DateTimeFormatOptions;
|
using js::intl::DateTimeFormatOptions;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||||
using js::intl::SharedIntlData;
|
using js::intl::SharedIntlData;
|
||||||
|
|
@ -228,19 +227,6 @@ js::AddMozDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl)
|
||||||
return mozDateTimeFormatProto != nullptr;
|
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
|
static bool
|
||||||
DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval)
|
DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -54,17 +54,6 @@ CreateDateTimeFormatPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp);
|
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
|
* Returns an array with the calendar type identifiers per Unicode
|
||||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
||||||
var localeData = DateTimeFormat.localeData;
|
var localeData = DateTimeFormat.localeData;
|
||||||
|
|
||||||
// Step 11.
|
// Step 11.
|
||||||
var r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
var r = ResolveLocale("DateTimeFormat",
|
||||||
lazyDateTimeFormatData.requestedLocales,
|
lazyDateTimeFormatData.requestedLocales,
|
||||||
lazyDateTimeFormatData.localeOpt,
|
lazyDateTimeFormatData.localeOpt,
|
||||||
DateTimeFormat.relevantExtensionKeys,
|
DateTimeFormat.relevantExtensionKeys,
|
||||||
|
|
@ -852,8 +852,7 @@ function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var availableLocales = callFunction(dateTimeFormatInternalProperties.availableLocales,
|
var availableLocales = "DateTimeFormat";
|
||||||
dateTimeFormatInternalProperties);
|
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
@ -870,17 +869,6 @@ function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
*/
|
*/
|
||||||
var dateTimeFormatInternalProperties = {
|
var dateTimeFormatInternalProperties = {
|
||||||
localeData: dateTimeFormatLocaleData,
|
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"]
|
relevantExtensionKeys: ["ca", "nu", "hc"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "unicode/udatpg.h"
|
#include "unicode/udatpg.h"
|
||||||
#include "unicode/udisplaycontext.h"
|
#include "unicode/udisplaycontext.h"
|
||||||
#include "unicode/uenum.h"
|
#include "unicode/uenum.h"
|
||||||
|
#include "unicode/uloc.h"
|
||||||
#include "unicode/unum.h"
|
#include "unicode/unum.h"
|
||||||
#include "unicode/unumsys.h"
|
#include "unicode/unumsys.h"
|
||||||
#include "unicode/upluralrules.h"
|
#include "unicode/upluralrules.h"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
#include "mozilla/Likely.h"
|
#include "mozilla/Likely.h"
|
||||||
#include "mozilla/Range.h"
|
#include "mozilla/Range.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
|
|
@ -18,12 +21,15 @@
|
||||||
#include "builtin/intl/Collator.h"
|
#include "builtin/intl/Collator.h"
|
||||||
#include "builtin/intl/CommonFunctions.h"
|
#include "builtin/intl/CommonFunctions.h"
|
||||||
#include "builtin/intl/DateTimeFormat.h"
|
#include "builtin/intl/DateTimeFormat.h"
|
||||||
|
#include "builtin/intl/LanguageTag.h"
|
||||||
#include "builtin/intl/ICUHeader.h"
|
#include "builtin/intl/ICUHeader.h"
|
||||||
#include "builtin/intl/Locale.h"
|
#include "builtin/intl/Locale.h"
|
||||||
#include "builtin/intl/NumberFormat.h"
|
#include "builtin/intl/NumberFormat.h"
|
||||||
#include "builtin/intl/PluralRules.h"
|
#include "builtin/intl/PluralRules.h"
|
||||||
#include "builtin/intl/RelativeTimeFormat.h"
|
#include "builtin/intl/RelativeTimeFormat.h"
|
||||||
#include "builtin/intl/ScopedICUObject.h"
|
#include "builtin/intl/ScopedICUObject.h"
|
||||||
|
#include "builtin/intl/SharedIntlData.h"
|
||||||
|
#include "js/Result.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
@ -32,7 +38,6 @@ using namespace js;
|
||||||
|
|
||||||
using js::intl::CallICU;
|
using js::intl::CallICU;
|
||||||
using js::intl::DateTimeFormatOptions;
|
using js::intl::DateTimeFormatOptions;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||||
using js::intl::StringsAreEqual;
|
using js::intl::StringsAreEqual;
|
||||||
|
|
@ -407,6 +412,275 @@ js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
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 = {
|
const Class js::IntlClass = {
|
||||||
js_Object_str,
|
js_Object_str,
|
||||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Intl)
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Intl)
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,35 @@ intl_GetCalendarInfo(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
intl_ComputeDisplayNames(JSContext* cx, unsigned argc, JS::Value* vp);
|
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
|
} // namespace js
|
||||||
|
|
||||||
#endif /* builtin_intl_IntlObject_h */
|
#endif /* builtin_intl_IntlObject_h */
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ function Intl_getCalendarInfo(locales) {
|
||||||
// 5. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]],
|
// 5. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]],
|
||||||
// requestedLocales, localeOpt,
|
// requestedLocales, localeOpt,
|
||||||
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||||
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
const r = ResolveLocale("DateTimeFormat",
|
||||||
requestedLocales,
|
requestedLocales,
|
||||||
localeOpt,
|
localeOpt,
|
||||||
DateTimeFormat.relevantExtensionKeys,
|
DateTimeFormat.relevantExtensionKeys,
|
||||||
|
|
@ -129,11 +129,11 @@ function Intl_getDisplayNames(locales, options) {
|
||||||
|
|
||||||
// 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
|
// 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
|
||||||
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||||
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
const r = ResolveLocale("DateTimeFormat",
|
||||||
requestedLocales,
|
requestedLocales,
|
||||||
localeOpt,
|
localeOpt,
|
||||||
DateTimeFormat.relevantExtensionKeys,
|
DateTimeFormat.relevantExtensionKeys,
|
||||||
localeData);
|
localeData);
|
||||||
|
|
||||||
// 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
|
// 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
|
||||||
const style = 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));
|
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>
|
template <size_t InitialCapacity>
|
||||||
static bool SortAlphabetically(JSContext* cx,
|
static bool SortAlphabetically(JSContext* cx,
|
||||||
Vector<UniqueChars, InitialCapacity>& subtags) {
|
Vector<UniqueChars, InitialCapacity>& subtags) {
|
||||||
|
|
@ -754,8 +763,13 @@ bool LanguageTag::canonicalizeTransformExtension(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LanguageTag::appendTo(JSContext* cx, StringBuffer& sb) const {
|
JSString* LanguageTag::toString(JSContext* cx) const {
|
||||||
return LanguageTagToString(cx, *this, sb);
|
StringBuffer sb(cx);
|
||||||
|
if (!LanguageTagToString(cx, *this, sb)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.finishString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero-terminated ICU Locale ID.
|
// Zero-terminated ICU Locale ID.
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ class JSString;
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class StringBuffer;
|
|
||||||
|
|
||||||
namespace intl {
|
namespace intl {
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -315,6 +313,11 @@ class MOZ_STACK_CLASS LanguageTag final {
|
||||||
*/
|
*/
|
||||||
bool setUnicodeExtension(JS::UniqueChars extension);
|
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
|
* Set the private-use subtag. The input must be a valid, case-normalized
|
||||||
* private-use subtag or the empty string.
|
* 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
|
* Return the string representation of this language tag.
|
||||||
* string buffer.
|
|
||||||
*/
|
*/
|
||||||
bool appendTo(JSContext* cx, StringBuffer& sb) const;
|
JSString* toString(JSContext* cx) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add likely-subtags to the language tag.
|
* Add likely-subtags to the language tag.
|
||||||
|
|
|
||||||
|
|
@ -106,12 +106,7 @@ static LocaleObject* CreateLocaleObject(JSContext* cx, HandleObject prototype,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer sb(cx);
|
RootedString tagStr(cx, tag.toString(cx));
|
||||||
if (!tag.appendTo(cx, sb)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedString tagStr(cx, sb.finishString());
|
|
||||||
if (!tagStr) {
|
if (!tagStr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -1320,12 +1315,7 @@ bool js::intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx, unsigned argc,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer sb(cx);
|
JSString* resultStr = tag.toString(cx);
|
||||||
if (!tag.appendTo(cx, sb)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSString* resultStr = sb.finishString();
|
|
||||||
if (!resultStr) {
|
if (!resultStr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1358,12 +1348,7 @@ bool js::intl_TryValidateAndCanonicalizeLanguageTag(JSContext* cx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer sb(cx);
|
JSString* resultStr = tag.toString(cx);
|
||||||
if (!tag.appendTo(cx, sb)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSString* resultStr = sb.finishString();
|
|
||||||
if (!resultStr) {
|
if (!resultStr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ using mozilla::IsNaN;
|
||||||
using mozilla::IsNegativeZero;
|
using mozilla::IsNegativeZero;
|
||||||
using js::intl::CallICU;
|
using js::intl::CallICU;
|
||||||
using js::intl::DateTimeFormatOptions;
|
using js::intl::DateTimeFormatOptions;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||||
using js::intl::StringsAreEqual;
|
using js::intl::StringsAreEqual;
|
||||||
|
|
@ -203,19 +202,6 @@ js::CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalO
|
||||||
return proto;
|
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
|
bool
|
||||||
js::intl_numberingSystem(JSContext* cx, unsigned argc, Value* vp)
|
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
|
extern MOZ_MUST_USE bool
|
||||||
intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp);
|
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
|
* Returns the numbering system type identifier per Unicode
|
||||||
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
* Technical Standard 35, Unicode Locale Data Markup Language, for the
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,6 @@
|
||||||
*/
|
*/
|
||||||
var numberFormatInternalProperties = {
|
var numberFormatInternalProperties = {
|
||||||
localeData: numberFormatLocaleData,
|
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"]
|
relevantExtensionKeys: ["nu"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -43,7 +32,7 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
|
||||||
var localeData = NumberFormat.localeData;
|
var localeData = NumberFormat.localeData;
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
|
var r = ResolveLocale("NumberFormat",
|
||||||
lazyNumberFormatData.requestedLocales,
|
lazyNumberFormatData.requestedLocales,
|
||||||
lazyNumberFormatData.opt,
|
lazyNumberFormatData.opt,
|
||||||
NumberFormat.relevantExtensionKeys,
|
NumberFormat.relevantExtensionKeys,
|
||||||
|
|
@ -396,8 +385,7 @@ function Intl_NumberFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var availableLocales = callFunction(numberFormatInternalProperties.availableLocales,
|
var availableLocales = "NumberFormat";
|
||||||
numberFormatInternalProperties);
|
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ using namespace js;
|
||||||
using mozilla::AssertedCast;
|
using mozilla::AssertedCast;
|
||||||
|
|
||||||
using js::intl::CallICU;
|
using js::intl::CallICU;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||||
using js::intl::StringsAreEqual;
|
using js::intl::StringsAreEqual;
|
||||||
|
|
@ -180,21 +179,6 @@ js::CreatePluralRulesPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalOb
|
||||||
return proto;
|
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
|
* This creates new UNumberFormat with calculated digit formatting
|
||||||
|
|
|
||||||
|
|
@ -49,17 +49,6 @@ CreatePluralRulesPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
intl_PluralRules(JSContext* cx, unsigned argc, Value* vp);
|
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
|
* Returns a plural rule for the number x according to the effective
|
||||||
* locale and the formatting options of the given PluralRules.
|
* locale and the formatting options of the given PluralRules.
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,6 @@
|
||||||
*/
|
*/
|
||||||
var pluralRulesInternalProperties = {
|
var pluralRulesInternalProperties = {
|
||||||
localeData: pluralRulesLocaleData,
|
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: [],
|
relevantExtensionKeys: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -50,7 +39,7 @@ function resolvePluralRulesInternals(lazyPluralRulesData) {
|
||||||
var localeData = PluralRules.localeData;
|
var localeData = PluralRules.localeData;
|
||||||
|
|
||||||
// Step 11.
|
// Step 11.
|
||||||
const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules),
|
const r = ResolveLocale("PluralRules",
|
||||||
lazyPluralRulesData.requestedLocales,
|
lazyPluralRulesData.requestedLocales,
|
||||||
lazyPluralRulesData.opt,
|
lazyPluralRulesData.opt,
|
||||||
PluralRules.relevantExtensionKeys,
|
PluralRules.relevantExtensionKeys,
|
||||||
|
|
@ -187,8 +176,8 @@ function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) {
|
||||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales,
|
var availableLocales = "PluralRules";
|
||||||
pluralRulesInternalProperties);
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let requestedLocales = CanonicalizeLocaleList(locales);
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ using mozilla::Range;
|
||||||
using mozilla::RangedPtr;
|
using mozilla::RangedPtr;
|
||||||
|
|
||||||
using js::intl::CallICU;
|
using js::intl::CallICU;
|
||||||
using js::intl::GetAvailableLocales;
|
|
||||||
using js::intl::IcuLocale;
|
using js::intl::IcuLocale;
|
||||||
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
using js::intl::INITIAL_CHAR_BUFFER_SIZE;
|
||||||
using js::intl::StringsAreEqual;
|
using js::intl::StringsAreEqual;
|
||||||
|
|
@ -164,22 +163,6 @@ js::CreateRelativeTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<G
|
||||||
return proto;
|
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
|
enum class RelativeTimeNumeric
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -39,17 +39,6 @@ extern JSObject*
|
||||||
CreateRelativeTimeFormatPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
CreateRelativeTimeFormatPrototype(JSContext* cx, JS::Handle<JSObject*> Intl,
|
||||||
JS::Handle<GlobalObject*> global);
|
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
|
* Returns a relative time as a string formatted according to the effective
|
||||||
* locale and the formatting options of the given RelativeTimeFormat.
|
* locale and the formatting options of the given RelativeTimeFormat.
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,6 @@
|
||||||
*/
|
*/
|
||||||
var relativeTimeFormatInternalProperties = {
|
var relativeTimeFormatInternalProperties = {
|
||||||
localeData: relativeTimeFormatLocaleData,
|
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: [],
|
relevantExtensionKeys: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,7 +30,7 @@ function resolveRelativeTimeFormatInternals(lazyRelativeTimeFormatData) {
|
||||||
var RelativeTimeFormat = relativeTimeFormatInternalProperties;
|
var RelativeTimeFormat = relativeTimeFormatInternalProperties;
|
||||||
|
|
||||||
// Steps 7-8.
|
// Steps 7-8.
|
||||||
const r = ResolveLocale(callFunction(RelativeTimeFormat.availableLocales, RelativeTimeFormat),
|
const r = ResolveLocale("RelativeTimeFormat",
|
||||||
lazyRelativeTimeFormatData.requestedLocales,
|
lazyRelativeTimeFormatData.requestedLocales,
|
||||||
lazyRelativeTimeFormatData.opt,
|
lazyRelativeTimeFormatData.opt,
|
||||||
RelativeTimeFormat.relevantExtensionKeys,
|
RelativeTimeFormat.relevantExtensionKeys,
|
||||||
|
|
@ -159,8 +148,8 @@ function Intl_RelativeTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var availableLocales = callFunction(relativeTimeFormatInternalProperties.availableLocales,
|
var availableLocales = "RelativeTimeFormat";
|
||||||
relativeTimeFormatInternalProperties);
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let requestedLocales = CanonicalizeLocaleList(locales);
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/HashFunctions.h"
|
#include "mozilla/HashFunctions.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
|
|
@ -21,6 +22,7 @@
|
||||||
#include "builtin/intl/ScopedICUObject.h"
|
#include "builtin/intl/ScopedICUObject.h"
|
||||||
#include "builtin/intl/TimeZoneDataGenerated.h"
|
#include "builtin/intl/TimeZoneDataGenerated.h"
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
#include "js/Vector.h"
|
||||||
|
|
||||||
using js::HashNumber;
|
using js::HashNumber;
|
||||||
using js::intl::StringsAreEqual;
|
using js::intl::StringsAreEqual;
|
||||||
|
|
@ -278,6 +280,13 @@ js::intl::SharedIntlData::LocaleHasher::Lookup::Lookup(JSLinearString* locale)
|
||||||
hash = mozilla::HashString(twoByteChars, length);
|
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
|
bool
|
||||||
js::intl::SharedIntlData::LocaleHasher::match(Locale key, const Lookup& lookup)
|
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);
|
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
|
bool
|
||||||
js::intl::SharedIntlData::ensureUpperCaseFirstLocales(JSContext* cx)
|
js::intl::SharedIntlData::ensureUpperCaseFirstLocales(JSContext* cx)
|
||||||
{
|
{
|
||||||
|
|
@ -393,6 +569,8 @@ js::intl::SharedIntlData::destroyInstance()
|
||||||
availableTimeZones.finish();
|
availableTimeZones.finish();
|
||||||
ianaZonesTreatedAsLinksByICU.finish();
|
ianaZonesTreatedAsLinksByICU.finish();
|
||||||
ianaLinksCanonicalizedDifferentlyByICU.finish();
|
ianaLinksCanonicalizedDifferentlyByICU.finish();
|
||||||
|
supportedLocales.finish();
|
||||||
|
collatorSupportedLocales.finish();
|
||||||
upperCaseFirstLocales.finish();
|
upperCaseFirstLocales.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,6 +582,8 @@ js::intl::SharedIntlData::trace(JSTracer* trc)
|
||||||
availableTimeZones.trace(trc);
|
availableTimeZones.trace(trc);
|
||||||
ianaZonesTreatedAsLinksByICU.trace(trc);
|
ianaZonesTreatedAsLinksByICU.trace(trc);
|
||||||
ianaLinksCanonicalizedDifferentlyByICU.trace(trc);
|
ianaLinksCanonicalizedDifferentlyByICU.trace(trc);
|
||||||
|
supportedLocales.trace(trc);
|
||||||
|
collatorSupportedLocales.trace(trc);
|
||||||
upperCaseFirstLocales.trace(trc);
|
upperCaseFirstLocales.trace(trc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -414,5 +594,7 @@ js::intl::SharedIntlData::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
|
||||||
return availableTimeZones.sizeOfExcludingThis(mallocSizeOf) +
|
return availableTimeZones.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
ianaZonesTreatedAsLinksByICU.sizeOfExcludingThis(mallocSizeOf) +
|
ianaZonesTreatedAsLinksByICU.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
ianaLinksCanonicalizedDifferentlyByICU.sizeOfExcludingThis(mallocSizeOf) +
|
ianaLinksCanonicalizedDifferentlyByICU.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
|
supportedLocales.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
|
collatorSupportedLocales.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
upperCaseFirstLocales.sizeOfExcludingThis(mallocSizeOf);
|
upperCaseFirstLocales.sizeOfExcludingThis(mallocSizeOf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,12 @@ class SharedIntlData
|
||||||
else
|
else
|
||||||
twoByteChars = string->twoByteChars(nogc);
|
twoByteChars = string->twoByteChars(nogc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LinearStringLookup(const char* chars, size_t length)
|
||||||
|
: isLatin1(true), length(length)
|
||||||
|
{
|
||||||
|
latin1Chars = reinterpret_cast<const JS::Latin1Char*>(chars);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -161,6 +167,76 @@ class SharedIntlData
|
||||||
*/
|
*/
|
||||||
bool tryCanonicalizeTimeZoneConsistentWithIANA(JSContext* cx, JS::HandleString timeZone,
|
bool tryCanonicalizeTimeZoneConsistentWithIANA(JSContext* cx, JS::HandleString timeZone,
|
||||||
JS::MutableHandleString result);
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
* The case first parameter (BCP47 key "kf") allows to switch the order of
|
* 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.
|
* 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;
|
LocaleSet upperCaseFirstLocales;
|
||||||
|
|
||||||
bool upperCaseFirstInitialized = false;
|
bool upperCaseFirstInitialized = false;
|
||||||
|
|
|
||||||
|
|
@ -2462,12 +2462,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
// See builtin/intl/*.h for descriptions of the intl_* functions.
|
// See builtin/intl/*.h for descriptions of the intl_* functions.
|
||||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||||
JS_FN("intl_availableCollations", intl_availableCollations, 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_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1,0),
|
||||||
JS_FN("intl_Collator", intl_Collator, 2,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_CompareStrings", intl_CompareStrings, 3,0),
|
||||||
JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,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_defaultCalendar", intl_defaultCalendar, 1,0),
|
||||||
JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
|
JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
|
||||||
JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 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_isUpperCaseFirst", intl_isUpperCaseFirst, 1,0),
|
||||||
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
|
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
|
||||||
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,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_numberingSystem", intl_numberingSystem, 1,0),
|
||||||
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
|
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
|
||||||
JS_FN("intl_patternForStyle", intl_patternForStyle, 3,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_GetPluralCategories", intl_GetPluralCategories, 2, 0),
|
||||||
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
|
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
|
||||||
JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),
|
JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),
|
||||||
JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2,0),
|
JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2,0),
|
||||||
JS_FN("intl_ValidateAndCanonicalizeLanguageTag", intl_ValidateAndCanonicalizeLanguageTag, 2, 0),
|
JS_FN("intl_ValidateAndCanonicalizeLanguageTag", intl_ValidateAndCanonicalizeLanguageTag, 2, 0),
|
||||||
JS_FN("intl_TryValidateAndCanonicalizeLanguageTag", intl_TryValidateAndCanonicalizeLanguageTag, 1, 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_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 3,0),
|
||||||
|
|
||||||
JS_INLINABLE_FN("IsCollator",
|
JS_INLINABLE_FN("IsCollator",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue