зеркало из https://github.com/mozilla/gecko-dev.git
1111 строки
21 KiB
JavaScript
1111 строки
21 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
||
const mozIntlHelper = Cc["@mozilla.org/mozintlhelper;1"].getService(
|
||
Ci.mozIMozIntlHelper
|
||
);
|
||
const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(
|
||
Ci.mozIOSPreferences
|
||
);
|
||
|
||
/**
|
||
* RegExp used to parse variant subtags from a BCP47 language tag.
|
||
* For example: ca-valencia
|
||
*/
|
||
const variantSubtagsMatch = /(?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))+$/;
|
||
|
||
function getDateTimePatternStyle(option) {
|
||
switch (option) {
|
||
case "full":
|
||
return osPrefs.dateTimeFormatStyleFull;
|
||
case "long":
|
||
return osPrefs.dateTimeFormatStyleLong;
|
||
case "medium":
|
||
return osPrefs.dateTimeFormatStyleMedium;
|
||
case "short":
|
||
return osPrefs.dateTimeFormatStyleShort;
|
||
default:
|
||
return osPrefs.dateTimeFormatStyleNone;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Number of milliseconds in other time units.
|
||
*
|
||
* This is used by relative time format best unit
|
||
* calculations.
|
||
*/
|
||
const second = 1e3;
|
||
const minute = 6e4;
|
||
const hour = 36e5;
|
||
const day = 864e5;
|
||
|
||
/**
|
||
* Use by RelativeTimeFormat.
|
||
*
|
||
* Allows for defining a cached getter to perform
|
||
* calculations only once.
|
||
*
|
||
* @param {Object} obj - Object to place the getter on.
|
||
* @param {String} prop - Name of the property.
|
||
* @param {Function} get - Function that will be used as a getter.
|
||
*/
|
||
function defineCachedGetter(obj, prop, get) {
|
||
defineGetter(obj, prop, function () {
|
||
if (!this._[prop]) {
|
||
this._[prop] = get.call(this);
|
||
}
|
||
return this._[prop];
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Used by RelativeTimeFormat.
|
||
*
|
||
* Defines a getter on an object
|
||
*
|
||
* @param {Object} obj - Object to place the getter on.
|
||
* @param {String} prop - Name of the property.
|
||
* @param {Function} get - Function that will be used as a getter.
|
||
*/
|
||
function defineGetter(obj, prop, get) {
|
||
Object.defineProperty(obj, prop, { get, enumerable: true });
|
||
}
|
||
|
||
/**
|
||
* Used by RelativeTimeFormat.
|
||
*
|
||
* Allows for calculation of the beginning of
|
||
* a period for discrete distances.
|
||
*
|
||
* @param {Date} date - Date of which we're looking to find a start of.
|
||
* @param {String} unit - Period to calculate the start of.
|
||
*
|
||
* @returns {Date}
|
||
*/
|
||
function startOf(date, unit) {
|
||
date = new Date(date.getTime());
|
||
switch (unit) {
|
||
case "year":
|
||
date.setMonth(0);
|
||
// falls through
|
||
case "month":
|
||
date.setDate(1);
|
||
// falls through
|
||
case "day":
|
||
date.setHours(0);
|
||
// falls through
|
||
case "hour":
|
||
date.setMinutes(0);
|
||
// falls through
|
||
case "minute":
|
||
date.setSeconds(0);
|
||
// falls through
|
||
case "second":
|
||
date.setMilliseconds(0);
|
||
}
|
||
return date;
|
||
}
|
||
|
||
/**
|
||
* Used by RelativeTimeFormat.
|
||
*
|
||
* Calculates the best fit unit to use for an absolute diff distance based
|
||
* on thresholds.
|
||
*
|
||
* @param {Object} absDiff - Object with absolute diff per unit calculated.
|
||
*
|
||
* @returns {String}
|
||
*/
|
||
function bestFit(absDiff) {
|
||
switch (true) {
|
||
case absDiff.years > 0 && absDiff.months > threshold.month:
|
||
return "year";
|
||
case absDiff.months > 0 && absDiff.weeks > threshold.week:
|
||
return "month";
|
||
case absDiff.weeks > 0 && absDiff.days > threshold.day:
|
||
return "week";
|
||
case absDiff.days > 0 && absDiff.hours > threshold.hour:
|
||
return "day";
|
||
case absDiff.hours > 0 && absDiff.minutes > threshold.minute:
|
||
return "hour";
|
||
case absDiff.minutes > 0 && absDiff.seconds > threshold.second:
|
||
return "minute";
|
||
default:
|
||
return "second";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Used by RelativeTimeFormat.
|
||
*
|
||
* Thresholds to use for calculating the best unit for relative time fromatting.
|
||
*/
|
||
const threshold = {
|
||
month: 11, // at least 11 months before using year.
|
||
week: 3, // at least 3 weeks before using month.
|
||
day: 6, // at least 6 days before using week.
|
||
hour: 6, // at least 6 hours before using day.
|
||
minute: 59, // at least 59 minutes before using hour.
|
||
second: 59, // at least 59 seconds before using minute.
|
||
};
|
||
|
||
/**
|
||
* Notice: If you're updating this list, you should also
|
||
* update the list in
|
||
* languageNames.ftl and regionNames.ftl.
|
||
*/
|
||
const availableLocaleDisplayNames = {
|
||
region: new Set([
|
||
"ad",
|
||
"ae",
|
||
"af",
|
||
"ag",
|
||
"ai",
|
||
"al",
|
||
"am",
|
||
"ao",
|
||
"aq",
|
||
"ar",
|
||
"as",
|
||
"at",
|
||
"au",
|
||
"aw",
|
||
"az",
|
||
"ba",
|
||
"bb",
|
||
"bd",
|
||
"be",
|
||
"bf",
|
||
"bg",
|
||
"bh",
|
||
"bi",
|
||
"bj",
|
||
"bl",
|
||
"bm",
|
||
"bn",
|
||
"bo",
|
||
"bq",
|
||
"br",
|
||
"bs",
|
||
"bt",
|
||
"bv",
|
||
"bw",
|
||
"by",
|
||
"bz",
|
||
"ca",
|
||
"cc",
|
||
"cd",
|
||
"cf",
|
||
"cg",
|
||
"ch",
|
||
"ci",
|
||
"ck",
|
||
"cl",
|
||
"cm",
|
||
"cn",
|
||
"co",
|
||
"cp",
|
||
"cr",
|
||
"cu",
|
||
"cv",
|
||
"cw",
|
||
"cx",
|
||
"cy",
|
||
"cz",
|
||
"de",
|
||
"dg",
|
||
"dj",
|
||
"dk",
|
||
"dm",
|
||
"do",
|
||
"dz",
|
||
"ec",
|
||
"ee",
|
||
"eg",
|
||
"eh",
|
||
"er",
|
||
"es",
|
||
"et",
|
||
"fi",
|
||
"fj",
|
||
"fk",
|
||
"fm",
|
||
"fo",
|
||
"fr",
|
||
"ga",
|
||
"gb",
|
||
"gd",
|
||
"ge",
|
||
"gf",
|
||
"gg",
|
||
"gh",
|
||
"gi",
|
||
"gl",
|
||
"gm",
|
||
"gn",
|
||
"gp",
|
||
"gq",
|
||
"gr",
|
||
"gs",
|
||
"gt",
|
||
"gu",
|
||
"gw",
|
||
"gy",
|
||
"hk",
|
||
"hm",
|
||
"hn",
|
||
"hr",
|
||
"ht",
|
||
"hu",
|
||
"id",
|
||
"ie",
|
||
"il",
|
||
"im",
|
||
"in",
|
||
"io",
|
||
"iq",
|
||
"ir",
|
||
"is",
|
||
"it",
|
||
"je",
|
||
"jm",
|
||
"jo",
|
||
"jp",
|
||
"ke",
|
||
"kg",
|
||
"kh",
|
||
"ki",
|
||
"km",
|
||
"kn",
|
||
"kp",
|
||
"kr",
|
||
"kw",
|
||
"ky",
|
||
"kz",
|
||
"la",
|
||
"lb",
|
||
"lc",
|
||
"li",
|
||
"lk",
|
||
"lr",
|
||
"ls",
|
||
"lt",
|
||
"lu",
|
||
"lv",
|
||
"ly",
|
||
"ma",
|
||
"mc",
|
||
"md",
|
||
"me",
|
||
"mf",
|
||
"mg",
|
||
"mh",
|
||
"mk",
|
||
"ml",
|
||
"mm",
|
||
"mn",
|
||
"mo",
|
||
"mp",
|
||
"mq",
|
||
"mr",
|
||
"ms",
|
||
"mt",
|
||
"mu",
|
||
"mv",
|
||
"mw",
|
||
"mx",
|
||
"my",
|
||
"mz",
|
||
"na",
|
||
"nc",
|
||
"ne",
|
||
"nf",
|
||
"ng",
|
||
"ni",
|
||
"nl",
|
||
"no",
|
||
"np",
|
||
"nr",
|
||
"nu",
|
||
"nz",
|
||
"om",
|
||
"pa",
|
||
"pe",
|
||
"pf",
|
||
"pg",
|
||
"ph",
|
||
"pk",
|
||
"pl",
|
||
"pm",
|
||
"pn",
|
||
"pr",
|
||
"pt",
|
||
"pw",
|
||
"py",
|
||
"qa",
|
||
"qm",
|
||
"qs",
|
||
"qu",
|
||
"qw",
|
||
"qx",
|
||
"qz",
|
||
"re",
|
||
"ro",
|
||
"rs",
|
||
"ru",
|
||
"rw",
|
||
"sa",
|
||
"sb",
|
||
"sc",
|
||
"sd",
|
||
"se",
|
||
"sg",
|
||
"sh",
|
||
"si",
|
||
"sk",
|
||
"skr",
|
||
"sl",
|
||
"sm",
|
||
"sn",
|
||
"so",
|
||
"sr",
|
||
"ss",
|
||
"st",
|
||
"sv",
|
||
"sx",
|
||
"sy",
|
||
"sz",
|
||
"tc",
|
||
"td",
|
||
"tf",
|
||
"tg",
|
||
"th",
|
||
"tj",
|
||
"tk",
|
||
"tl",
|
||
"tm",
|
||
"tn",
|
||
"to",
|
||
"tr",
|
||
"tt",
|
||
"tv",
|
||
"tw",
|
||
"tz",
|
||
"ua",
|
||
"ug",
|
||
"us",
|
||
"uy",
|
||
"uz",
|
||
"va",
|
||
"vc",
|
||
"ve",
|
||
"vg",
|
||
"vi",
|
||
"vn",
|
||
"vu",
|
||
"wf",
|
||
"ws",
|
||
"xa",
|
||
"xb",
|
||
"xc",
|
||
"xd",
|
||
"xe",
|
||
"xg",
|
||
"xh",
|
||
"xj",
|
||
"xk",
|
||
"xl",
|
||
"xm",
|
||
"xp",
|
||
"xq",
|
||
"xr",
|
||
"xs",
|
||
"xt",
|
||
"xu",
|
||
"xv",
|
||
"xw",
|
||
"ye",
|
||
"yt",
|
||
"za",
|
||
"zm",
|
||
"zw",
|
||
]),
|
||
language: new Set([
|
||
"aa",
|
||
"ab",
|
||
"ach",
|
||
"ae",
|
||
"af",
|
||
"ak",
|
||
"am",
|
||
"an",
|
||
"ar",
|
||
"as",
|
||
"ast",
|
||
"av",
|
||
"ay",
|
||
"az",
|
||
"ba",
|
||
"be",
|
||
"bg",
|
||
"bh",
|
||
"bi",
|
||
"bm",
|
||
"bn",
|
||
"bo",
|
||
"br",
|
||
"bs",
|
||
"ca",
|
||
"cak",
|
||
"ce",
|
||
"ch",
|
||
"co",
|
||
"cr",
|
||
"crh",
|
||
"cs",
|
||
"csb",
|
||
"cu",
|
||
"cv",
|
||
"cy",
|
||
"da",
|
||
"de",
|
||
"dsb",
|
||
"dv",
|
||
"dz",
|
||
"ee",
|
||
"el",
|
||
"en",
|
||
"eo",
|
||
"es",
|
||
"et",
|
||
"eu",
|
||
"fa",
|
||
"ff",
|
||
"fi",
|
||
"fj",
|
||
"fo",
|
||
"fr",
|
||
"fur",
|
||
"fy",
|
||
"ga",
|
||
"gd",
|
||
"gl",
|
||
"gn",
|
||
"gu",
|
||
"gv",
|
||
"ha",
|
||
"haw",
|
||
"he",
|
||
"hi",
|
||
"hil",
|
||
"ho",
|
||
"hr",
|
||
"hsb",
|
||
"ht",
|
||
"hu",
|
||
"hy",
|
||
"hz",
|
||
"ia",
|
||
"id",
|
||
"ie",
|
||
"ig",
|
||
"ii",
|
||
"ik",
|
||
"io",
|
||
"is",
|
||
"it",
|
||
"iu",
|
||
"ja",
|
||
"jv",
|
||
"ka",
|
||
"kab",
|
||
"kg",
|
||
"ki",
|
||
"kj",
|
||
"kk",
|
||
"kl",
|
||
"km",
|
||
"kn",
|
||
"ko",
|
||
"kok",
|
||
"kr",
|
||
"ks",
|
||
"ku",
|
||
"kv",
|
||
"kw",
|
||
"ky",
|
||
"la",
|
||
"lb",
|
||
"lg",
|
||
"li",
|
||
"lij",
|
||
"ln",
|
||
"lo",
|
||
"lt",
|
||
"ltg",
|
||
"lu",
|
||
"lv",
|
||
"mai",
|
||
"meh",
|
||
"mg",
|
||
"mh",
|
||
"mi",
|
||
"mix",
|
||
"mk",
|
||
"ml",
|
||
"mn",
|
||
"mr",
|
||
"ms",
|
||
"mt",
|
||
"my",
|
||
"na",
|
||
"nb",
|
||
"nd",
|
||
"ne",
|
||
"ng",
|
||
"nl",
|
||
"nn",
|
||
"no",
|
||
"nr",
|
||
"nso",
|
||
"nv",
|
||
"ny",
|
||
"oc",
|
||
"oj",
|
||
"om",
|
||
"or",
|
||
"os",
|
||
"pa",
|
||
"pi",
|
||
"pl",
|
||
"ps",
|
||
"pt",
|
||
"qu",
|
||
"rm",
|
||
"rn",
|
||
"ro",
|
||
"ru",
|
||
"rw",
|
||
"sa",
|
||
"sat",
|
||
"sc",
|
||
"sco",
|
||
"sd",
|
||
"se",
|
||
"sg",
|
||
"si",
|
||
"sk",
|
||
"sl",
|
||
"sm",
|
||
"sn",
|
||
"so",
|
||
"son",
|
||
"sq",
|
||
"sr",
|
||
"ss",
|
||
"st",
|
||
"su",
|
||
"sv",
|
||
"sw",
|
||
"szl",
|
||
"ta",
|
||
"te",
|
||
"tg",
|
||
"th",
|
||
"ti",
|
||
"tig",
|
||
"tk",
|
||
"tl",
|
||
"tlh",
|
||
"tn",
|
||
"to",
|
||
"tr",
|
||
"trs",
|
||
"ts",
|
||
"tt",
|
||
"tw",
|
||
"ty",
|
||
"ug",
|
||
"uk",
|
||
"ur",
|
||
"uz",
|
||
"ve",
|
||
"vi",
|
||
"vo",
|
||
"wa",
|
||
"wen",
|
||
"wo",
|
||
"xh",
|
||
"yi",
|
||
"yo",
|
||
"za",
|
||
"zam",
|
||
"zh",
|
||
"zu",
|
||
]),
|
||
};
|
||
|
||
/**
|
||
* Notice: If you're updating these names, you should also update the data
|
||
* in python/mozbuild/mozbuild/action/langpack_localeNames.json.
|
||
*/
|
||
const nativeLocaleNames = new Map(
|
||
Object.entries({
|
||
ach: "Acholi",
|
||
af: "Afrikaans",
|
||
an: "Aragonés",
|
||
ar: "العربية",
|
||
ast: "Asturianu",
|
||
az: "Azərbaycanca",
|
||
be: "Беларуская",
|
||
bg: "Български",
|
||
bn: "বাংলা",
|
||
bo: "བོད་སྐད",
|
||
br: "Brezhoneg",
|
||
brx: "बड़ो",
|
||
bs: "Bosanski",
|
||
ca: "Català",
|
||
"ca-valencia": "Català (Valencià)",
|
||
cak: "Kaqchikel",
|
||
cs: "Čeština",
|
||
cy: "Cymraeg",
|
||
da: "Dansk",
|
||
de: "Deutsch",
|
||
dsb: "Dolnoserbšćina",
|
||
el: "Ελληνικά",
|
||
"en-CA": "English (CA)",
|
||
"en-GB": "English (GB)",
|
||
"en-US": "English (US)",
|
||
eo: "Esperanto",
|
||
"es-AR": "Español (AR)",
|
||
"es-CL": "Español (CL)",
|
||
"es-ES": "Español (ES)",
|
||
"es-MX": "Español (MX)",
|
||
et: "Eesti",
|
||
eu: "Euskara",
|
||
fa: "فارسی",
|
||
ff: "Pulaar",
|
||
fi: "Suomi",
|
||
fr: "Français",
|
||
fur: "Furlan",
|
||
"fy-NL": "Frysk",
|
||
"ga-IE": "Gaeilge",
|
||
gd: "Gàidhlig",
|
||
gl: "Galego",
|
||
gn: "Guarani",
|
||
"gu-IN": "ગુજરાતી",
|
||
he: "עברית",
|
||
"hi-IN": "हिन्दी",
|
||
hr: "Hrvatski",
|
||
hsb: "Hornjoserbšćina",
|
||
hu: "Magyar",
|
||
"hy-AM": "հայերեն",
|
||
ia: "Interlingua",
|
||
id: "Indonesia",
|
||
is: "Islenska",
|
||
it: "Italiano",
|
||
ja: "日本語",
|
||
"ja-JP-mac": "日本語",
|
||
ka: "ქართული",
|
||
kab: "Taqbaylit",
|
||
kk: "қазақ тілі",
|
||
km: "ខ្មែរ",
|
||
kn: "ಕನ್ನಡ",
|
||
ko: "한국어",
|
||
lij: "Ligure",
|
||
lo: "ລາວ",
|
||
lt: "Lietuvių",
|
||
ltg: "Latgalīšu",
|
||
lv: "Latviešu",
|
||
mk: "македонски",
|
||
ml: "മലയാളം",
|
||
mr: "मराठी",
|
||
ms: "Melayu",
|
||
my: "မြန်မာ",
|
||
"nb-NO": "Norsk Bokmål",
|
||
"ne-NP": "नेपाली",
|
||
nl: "Nederlands",
|
||
"nn-NO": "Nynorsk",
|
||
oc: "Occitan",
|
||
or: "ଓଡ଼ିଆ",
|
||
"pa-IN": "ਪੰਜਾਬੀ",
|
||
pl: "Polski",
|
||
"pt-BR": "Português (BR)",
|
||
"pt-PT": "Português (PT)",
|
||
rm: "Rumantsch",
|
||
ro: "Română",
|
||
ru: "Русский",
|
||
sat: "ᱥᱟᱱᱛᱟᱲᱤ",
|
||
sc: "Sardu",
|
||
sco: "Scots",
|
||
si: "සිංහල",
|
||
sk: "Slovenčina",
|
||
skr: "سرائیکی",
|
||
sl: "Slovenščina",
|
||
son: "Soŋay",
|
||
sq: "Shqip",
|
||
sr: "Cрпски",
|
||
"sv-SE": "Svenska",
|
||
szl: "Ślōnsko",
|
||
ta: "தமிழ்",
|
||
te: "తెలుగు",
|
||
tg: "Тоҷикӣ",
|
||
th: "ไทย",
|
||
tl: "Tagalog",
|
||
tr: "Türkçe",
|
||
trs: "Triqui",
|
||
uk: "Українська",
|
||
ur: "اردو",
|
||
uz: "O‘zbek",
|
||
vi: "Tiếng Việt",
|
||
wo: "Wolof",
|
||
xh: "IsiXhosa",
|
||
"zh-CN": "简体中文",
|
||
"zh-TW": "正體中文",
|
||
})
|
||
);
|
||
|
||
class MozRelativeTimeFormat extends Intl.RelativeTimeFormat {
|
||
constructor(locales, options = {}, ...args) {
|
||
// If someone is asking for MozRelativeTimeFormat, it's likely they'll want
|
||
// to use `formatBestUnit` which works better with `auto`
|
||
if (options.numeric === undefined) {
|
||
options.numeric = "auto";
|
||
}
|
||
super(locales, options, ...args);
|
||
}
|
||
|
||
formatBestUnit(date, { now = new Date() } = {}) {
|
||
const diff = {
|
||
_: {},
|
||
ms: date.getTime() - now.getTime(),
|
||
years: date.getFullYear() - now.getFullYear(),
|
||
};
|
||
|
||
defineCachedGetter(diff, "months", function () {
|
||
return this.years * 12 + date.getMonth() - now.getMonth();
|
||
});
|
||
defineCachedGetter(diff, "weeks", function () {
|
||
return Math.trunc(this.days / 7);
|
||
});
|
||
defineCachedGetter(diff, "days", function () {
|
||
return Math.trunc((startOf(date, "day") - startOf(now, "day")) / day);
|
||
});
|
||
defineCachedGetter(diff, "hours", function () {
|
||
return Math.trunc((startOf(date, "hour") - startOf(now, "hour")) / hour);
|
||
});
|
||
defineCachedGetter(diff, "minutes", function () {
|
||
return Math.trunc(
|
||
(startOf(date, "minute") - startOf(now, "minute")) / minute
|
||
);
|
||
});
|
||
defineCachedGetter(diff, "seconds", function () {
|
||
return Math.trunc(
|
||
(startOf(date, "second") - startOf(now, "second")) / second
|
||
);
|
||
});
|
||
|
||
const absDiff = {
|
||
_: {},
|
||
};
|
||
|
||
for (let prop of Object.keys(diff)) {
|
||
defineGetter(absDiff, prop, function () {
|
||
return Math.abs(diff[prop]);
|
||
});
|
||
}
|
||
const unit = bestFit(absDiff);
|
||
|
||
switch (unit) {
|
||
case "year":
|
||
return this.format(diff.years, unit);
|
||
case "month":
|
||
return this.format(diff.months, unit);
|
||
case "week":
|
||
return this.format(diff.weeks, unit);
|
||
case "day":
|
||
return this.format(diff.days, unit);
|
||
case "hour":
|
||
return this.format(diff.hours, unit);
|
||
case "minute":
|
||
return this.format(diff.minutes, unit);
|
||
default:
|
||
if (unit !== "second") {
|
||
throw new TypeError(`Unsupported unit "${unit}"`);
|
||
}
|
||
return this.format(diff.seconds, unit);
|
||
}
|
||
}
|
||
}
|
||
|
||
export class MozIntl {
|
||
Collator = Intl.Collator;
|
||
ListFormat = Intl.ListFormat;
|
||
Locale = Intl.Locale;
|
||
NumberFormat = Intl.NumberFormat;
|
||
PluralRules = Intl.PluralRules;
|
||
RelativeTimeFormat = MozRelativeTimeFormat;
|
||
|
||
constructor() {
|
||
this._cache = {};
|
||
Services.obs.addObserver(this, "intl:app-locales-changed", true);
|
||
}
|
||
|
||
observe() {
|
||
// Clear cache when things change.
|
||
this._cache = {};
|
||
}
|
||
|
||
getCalendarInfo(locales, ...args) {
|
||
if (!this._cache.hasOwnProperty("getCalendarInfo")) {
|
||
mozIntlHelper.addGetCalendarInfo(this._cache);
|
||
}
|
||
|
||
return this._cache.getCalendarInfo(locales, ...args);
|
||
}
|
||
|
||
getDisplayNamesDeprecated(locales, options = {}) {
|
||
// Helper for IntlUtils.webidl, will be removed once Intl.DisplayNames is
|
||
// available in non-privileged code.
|
||
|
||
let { type, style, calendar, keys = [] } = options;
|
||
|
||
let dn = new this.DisplayNames(locales, { type, style, calendar });
|
||
let {
|
||
locale: resolvedLocale,
|
||
type: resolvedType,
|
||
style: resolvedStyle,
|
||
calendar: resolvedCalendar,
|
||
} = dn.resolvedOptions();
|
||
let values = keys.map(key => dn.of(key));
|
||
|
||
return {
|
||
locale: resolvedLocale,
|
||
type: resolvedType,
|
||
style: resolvedStyle,
|
||
calendar: resolvedCalendar,
|
||
values,
|
||
};
|
||
}
|
||
|
||
getAvailableLocaleDisplayNames(type) {
|
||
if (availableLocaleDisplayNames.hasOwnProperty(type)) {
|
||
return Array.from(availableLocaleDisplayNames[type]);
|
||
}
|
||
|
||
return new Error("Unimplemented!");
|
||
}
|
||
|
||
getLanguageDisplayNames(locales, langCodes) {
|
||
if (locales !== undefined) {
|
||
throw new Error("First argument support not implemented yet");
|
||
}
|
||
|
||
if (!this._cache.hasOwnProperty("languageLocalization")) {
|
||
const loc = new Localization(["toolkit/intl/languageNames.ftl"], true);
|
||
this._cache.languageLocalization = loc;
|
||
}
|
||
|
||
const loc = this._cache.languageLocalization;
|
||
|
||
return langCodes.map(langCode => {
|
||
if (typeof langCode !== "string") {
|
||
throw new TypeError("All language codes must be strings.");
|
||
}
|
||
let lcLangCode = langCode.toLowerCase();
|
||
if (availableLocaleDisplayNames.language.has(lcLangCode)) {
|
||
const value = loc.formatValueSync(`language-name-${lcLangCode}`);
|
||
if (value !== null) {
|
||
return value;
|
||
}
|
||
}
|
||
return lcLangCode;
|
||
});
|
||
}
|
||
|
||
getRegionDisplayNames(locales, regionCodes) {
|
||
if (locales !== undefined) {
|
||
throw new Error("First argument support not implemented yet");
|
||
}
|
||
|
||
if (!this._cache.hasOwnProperty("regionLocalization")) {
|
||
const loc = new Localization(["toolkit/intl/regionNames.ftl"], true);
|
||
this._cache.regionLocalization = loc;
|
||
}
|
||
|
||
const loc = this._cache.regionLocalization;
|
||
|
||
return regionCodes.map(regionCode => {
|
||
if (typeof regionCode !== "string") {
|
||
throw new TypeError("All region codes must be strings.");
|
||
}
|
||
let lcRegionCode = regionCode.toLowerCase();
|
||
if (availableLocaleDisplayNames.region.has(lcRegionCode)) {
|
||
let regionID;
|
||
// Allow changing names over time for specific regions
|
||
switch (lcRegionCode) {
|
||
case "bq":
|
||
regionID = "region-name-bq-2018";
|
||
break;
|
||
case "cv":
|
||
regionID = "region-name-cv-2020";
|
||
break;
|
||
case "cz":
|
||
regionID = "region-name-cz-2019";
|
||
break;
|
||
case "mk":
|
||
regionID = "region-name-mk-2019";
|
||
break;
|
||
case "sz":
|
||
regionID = "region-name-sz-2019";
|
||
break;
|
||
default:
|
||
regionID = `region-name-${lcRegionCode}`;
|
||
}
|
||
|
||
const value = loc.formatValueSync(regionID);
|
||
if (value !== null) {
|
||
return value;
|
||
}
|
||
}
|
||
return regionCode.toUpperCase();
|
||
});
|
||
}
|
||
|
||
getLocaleDisplayNames(locales, localeCodes, options = {}) {
|
||
const { preferNative = false } = options;
|
||
|
||
if (locales !== undefined) {
|
||
throw new Error("First argument support not implemented yet");
|
||
}
|
||
// Patterns hardcoded from CLDR 33 english.
|
||
// We can later look into fetching them from CLDR directly.
|
||
const localePattern = "{0} ({1})";
|
||
const localeSeparator = ", ";
|
||
|
||
return localeCodes.map(localeCode => {
|
||
if (typeof localeCode !== "string") {
|
||
throw new TypeError("All locale codes must be strings.");
|
||
}
|
||
|
||
if (preferNative && nativeLocaleNames.has(localeCode)) {
|
||
return nativeLocaleNames.get(localeCode);
|
||
}
|
||
|
||
let locale;
|
||
try {
|
||
locale = new Intl.Locale(localeCode.replaceAll("_", "-"));
|
||
} catch {
|
||
return localeCode;
|
||
}
|
||
|
||
const {
|
||
language: languageSubtag,
|
||
script: scriptSubtag,
|
||
region: regionSubtag,
|
||
} = locale;
|
||
|
||
const variantSubtags = locale.baseName.match(variantSubtagsMatch);
|
||
|
||
const displayName = [
|
||
this.getLanguageDisplayNames(locales, [languageSubtag])[0],
|
||
];
|
||
|
||
if (scriptSubtag) {
|
||
displayName.push(scriptSubtag);
|
||
}
|
||
|
||
if (regionSubtag) {
|
||
displayName.push(
|
||
this.getRegionDisplayNames(locales, [regionSubtag])[0]
|
||
);
|
||
}
|
||
|
||
if (variantSubtags) {
|
||
displayName.push(...variantSubtags[0].substr(1).split("-")); // Collapse multiple variants.
|
||
}
|
||
|
||
let modifiers;
|
||
if (displayName.length === 1) {
|
||
return displayName[0];
|
||
} else if (displayName.length > 2) {
|
||
modifiers = displayName.slice(1).join(localeSeparator);
|
||
} else {
|
||
modifiers = displayName[1];
|
||
}
|
||
return localePattern
|
||
.replace("{0}", displayName[0])
|
||
.replace("{1}", modifiers);
|
||
});
|
||
}
|
||
|
||
getScriptDirection(locale) {
|
||
// This is a crude implementation until Bug 1693576 lands.
|
||
// See justification in toolkit/components/mozintl/mozIMozIntl.idl
|
||
const { language } = new Intl.Locale(locale);
|
||
if (
|
||
language == "ar" ||
|
||
language == "ckb" ||
|
||
language == "fa" ||
|
||
language == "he" ||
|
||
language == "ur"
|
||
) {
|
||
return "rtl";
|
||
}
|
||
return "ltr";
|
||
}
|
||
|
||
stringHasRTLChars(str) {
|
||
return mozIntlHelper.stringHasRTLChars(str);
|
||
}
|
||
|
||
get DateTimeFormat() {
|
||
if (!this._cache.hasOwnProperty("DateTimeFormat")) {
|
||
mozIntlHelper.addDateTimeFormatConstructor(this._cache);
|
||
|
||
const DateTimeFormat = this._cache.DateTimeFormat;
|
||
|
||
class MozDateTimeFormat extends DateTimeFormat {
|
||
constructor(locales, options, ...args) {
|
||
let resolvedLocales = DateTimeFormat.supportedLocalesOf(locales);
|
||
if (options) {
|
||
if (options.dateStyle || options.timeStyle) {
|
||
options.pattern = osPrefs.getDateTimePattern(
|
||
getDateTimePatternStyle(options.dateStyle),
|
||
getDateTimePatternStyle(options.timeStyle),
|
||
resolvedLocales[0]
|
||
);
|
||
} else {
|
||
// make sure that user doesn't pass a pattern explicitly
|
||
options.pattern = undefined;
|
||
}
|
||
}
|
||
super(resolvedLocales, options, ...args);
|
||
}
|
||
}
|
||
this._cache.MozDateTimeFormat = MozDateTimeFormat;
|
||
}
|
||
|
||
return this._cache.MozDateTimeFormat;
|
||
}
|
||
|
||
get DisplayNames() {
|
||
if (!this._cache.hasOwnProperty("DisplayNames")) {
|
||
mozIntlHelper.addDisplayNamesConstructor(this._cache);
|
||
}
|
||
|
||
return this._cache.DisplayNames;
|
||
}
|
||
}
|
||
|
||
MozIntl.prototype.classID = Components.ID(
|
||
"{35ec195a-e8d0-4300-83af-c8a2cc84b4a3}"
|
||
);
|
||
MozIntl.prototype.QueryInterface = ChromeUtils.generateQI([
|
||
"mozIMozIntl",
|
||
"nsIObserver",
|
||
"nsISupportsWeakReference",
|
||
]);
|