@formatjs/intl-locale
Version:
Intl.Locale polyfill
583 lines (582 loc) • 23 kB
JavaScript
import { __assign, __spreadArray } from "tslib";
import { CoerceOptionsToObject, GetOption, HasOwnProperty, SameValue, createDataProperty, invariant, } from '@formatjs/ecma402-abstract';
import { supportedValuesOf } from '@formatjs/intl-enumerator';
import { emitUnicodeLanguageId, emitUnicodeLocaleId, isStructurallyValidLanguageTag, isUnicodeLanguageSubtag, isUnicodeRegionSubtag, isUnicodeScriptSubtag, likelySubtags, parseUnicodeLanguageId, parseUnicodeLocaleId, } from '@formatjs/intl-getcanonicallocales';
import { characterOrders } from './character-orders.generated';
import getInternalSlots from './get_internal_slots';
import { numberingSystems } from './numbering-systems.generated';
import { getCalendarPreferenceDataForRegion, getHourCyclesPreferenceDataForLocaleOrRegion, getTimeZonePreferenceForRegion, getWeekDataForRegion, } from './preference-data';
var ALPHANUM_3_8 = /^[a-z0-9]{3,8}$/i;
var RELEVANT_EXTENSION_KEYS = [
'ca',
'co',
'hc',
'kf',
'kn',
'nu',
'fw',
];
var UNICODE_TYPE_REGEX = /^[a-z0-9]{3,8}(-[a-z0-9]{3,8})*$/i;
function applyOptionsToTag(tag, options) {
invariant(typeof tag === 'string', 'language tag must be a string');
invariant(isStructurallyValidLanguageTag(tag), 'malformed language tag', RangeError);
var language = GetOption(options, 'language', 'string', undefined, undefined);
if (language !== undefined) {
invariant(isUnicodeLanguageSubtag(language), 'Malformed unicode_language_subtag', RangeError);
}
var script = GetOption(options, 'script', 'string', undefined, undefined);
if (script !== undefined) {
invariant(isUnicodeScriptSubtag(script), 'Malformed unicode_script_subtag', RangeError);
}
var region = GetOption(options, 'region', 'string', undefined, undefined);
if (region !== undefined) {
invariant(isUnicodeRegionSubtag(region), 'Malformed unicode_region_subtag', RangeError);
}
var languageId = parseUnicodeLanguageId(tag);
if (language !== undefined) {
languageId.lang = language;
}
if (script !== undefined) {
languageId.script = script;
}
if (region !== undefined) {
languageId.region = region;
}
return Intl.getCanonicalLocales(emitUnicodeLocaleId(__assign(__assign({}, parseUnicodeLocaleId(tag)), { lang: languageId })))[0];
}
function applyUnicodeExtensionToTag(tag, options, relevantExtensionKeys) {
var unicodeExtension;
var keywords = [];
var ast = parseUnicodeLocaleId(tag);
for (var _i = 0, _a = ast.extensions; _i < _a.length; _i++) {
var ext = _a[_i];
if (ext.type === 'u') {
unicodeExtension = ext;
if (Array.isArray(ext.keywords))
keywords = ext.keywords;
}
}
var result = Object.create(null);
for (var _b = 0, relevantExtensionKeys_1 = relevantExtensionKeys; _b < relevantExtensionKeys_1.length; _b++) {
var key = relevantExtensionKeys_1[_b];
var value = void 0, entry = void 0;
for (var _c = 0, keywords_1 = keywords; _c < keywords_1.length; _c++) {
var keyword = keywords_1[_c];
if (keyword[0] === key) {
entry = keyword;
value = entry[1];
}
}
invariant(key in options, "".concat(key, " must be in options"));
var optionsValue = options[key];
if (optionsValue !== undefined) {
invariant(typeof optionsValue === 'string', "Value for ".concat(key, " must be a string"));
value = optionsValue;
if (entry) {
entry[1] = value;
}
else {
keywords.push([key, value]);
}
}
result[key] = value;
}
if (!unicodeExtension) {
if (keywords.length) {
ast.extensions.push({
type: 'u',
keywords: keywords,
attributes: [],
});
}
}
else {
unicodeExtension.keywords = keywords;
}
result.locale = Intl.getCanonicalLocales(emitUnicodeLocaleId(ast))[0];
return result;
}
function mergeUnicodeLanguageId(lang, script, region, variants, replacement) {
if (variants === void 0) { variants = []; }
if (!replacement) {
return {
lang: lang || 'und',
script: script,
region: region,
variants: variants,
};
}
return {
lang: !lang || lang === 'und' ? replacement.lang : lang,
script: script || replacement.script,
region: region || replacement.region,
variants: __spreadArray(__spreadArray([], variants, true), replacement.variants, true),
};
}
function addLikelySubtags(tag) {
var ast = parseUnicodeLocaleId(tag);
var unicodeLangId = ast.lang;
var lang = unicodeLangId.lang, script = unicodeLangId.script, region = unicodeLangId.region, variants = unicodeLangId.variants;
if (script && region) {
var match_1 = likelySubtags[emitUnicodeLanguageId({ lang: lang, script: script, region: region, variants: [] })];
if (match_1) {
var parts_1 = parseUnicodeLanguageId(match_1);
ast.lang = mergeUnicodeLanguageId(undefined, undefined, undefined, variants, parts_1);
return emitUnicodeLocaleId(ast);
}
}
if (script) {
var match_2 = likelySubtags[emitUnicodeLanguageId({ lang: lang, script: script, variants: [] })];
if (match_2) {
var parts_2 = parseUnicodeLanguageId(match_2);
ast.lang = mergeUnicodeLanguageId(undefined, undefined, region, variants, parts_2);
return emitUnicodeLocaleId(ast);
}
}
if (region) {
var match_3 = likelySubtags[emitUnicodeLanguageId({ lang: lang, region: region, variants: [] })];
if (match_3) {
var parts_3 = parseUnicodeLanguageId(match_3);
ast.lang = mergeUnicodeLanguageId(undefined, script, undefined, variants, parts_3);
return emitUnicodeLocaleId(ast);
}
}
var match = likelySubtags[lang] ||
likelySubtags[emitUnicodeLanguageId({ lang: 'und', script: script, variants: [] })];
if (!match) {
throw new Error("No match for addLikelySubtags");
}
var parts = parseUnicodeLanguageId(match);
ast.lang = mergeUnicodeLanguageId(undefined, script, region, variants, parts);
return emitUnicodeLocaleId(ast);
}
/**
* From: https://github.com/unicode-org/icu/blob/4231ca5be053a22a1be24eb891817458c97db709/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java#L2395
* @param tag
*/
function removeLikelySubtags(tag) {
var maxLocale = addLikelySubtags(tag);
if (!maxLocale) {
return tag;
}
maxLocale = emitUnicodeLanguageId(__assign(__assign({}, parseUnicodeLanguageId(maxLocale)), { variants: [] }));
var ast = parseUnicodeLocaleId(tag);
var _a = ast.lang, lang = _a.lang, script = _a.script, region = _a.region, variants = _a.variants;
var trial = addLikelySubtags(emitUnicodeLanguageId({ lang: lang, variants: [] }));
if (trial === maxLocale) {
return emitUnicodeLocaleId(__assign(__assign({}, ast), { lang: mergeUnicodeLanguageId(lang, undefined, undefined, variants) }));
}
if (region) {
var trial_1 = addLikelySubtags(emitUnicodeLanguageId({ lang: lang, region: region, variants: [] }));
if (trial_1 === maxLocale) {
return emitUnicodeLocaleId(__assign(__assign({}, ast), { lang: mergeUnicodeLanguageId(lang, undefined, region, variants) }));
}
}
if (script) {
var trial_2 = addLikelySubtags(emitUnicodeLanguageId({ lang: lang, script: script, variants: [] }));
if (trial_2 === maxLocale) {
return emitUnicodeLocaleId(__assign(__assign({}, ast), { lang: mergeUnicodeLanguageId(lang, script, undefined, variants) }));
}
}
return tag;
}
function createArrayFromListOrRestricted(list, restricted) {
var result = list;
if (restricted !== undefined) {
result = [restricted];
}
return Array.from(result);
}
function calendarsOfLocale(loc) {
var locInternalSlots = getInternalSlots(loc);
var restricted = locInternalSlots.calendar;
var locale = locInternalSlots.locale;
var region;
if (locale !== 'root') {
region = loc.maximize().region;
}
var preferredCalendars = getCalendarPreferenceDataForRegion(region);
return createArrayFromListOrRestricted(preferredCalendars, restricted);
}
function collationsOfLocale(loc) {
var locInternalSlots = getInternalSlots(loc);
var restricted = locInternalSlots.collation;
var locale = locInternalSlots.locale;
var supportedCollations = supportedValuesOf('collation', locale).filter(function (co) { return co !== 'standard' && co !== 'search'; });
supportedCollations.sort();
return createArrayFromListOrRestricted(supportedCollations, restricted);
}
function hourCyclesOfLocale(loc) {
var locInternalSlots = getInternalSlots(loc);
var restricted = locInternalSlots.hourCycle;
var locale = locInternalSlots.locale;
var region;
if (locale !== 'root') {
region = loc.maximize().region;
}
var preferredHourCycles = getHourCyclesPreferenceDataForLocaleOrRegion(locale, region);
return createArrayFromListOrRestricted(preferredHourCycles, restricted);
}
function numberingSystemsOfLocale(loc) {
var _a;
var locInternalSlots = getInternalSlots(loc);
var restricted = locInternalSlots.numberingSystem;
var locale = locInternalSlots.locale;
var language = loc.language;
var localeNumberingSystems = (_a = numberingSystems[locale]) !== null && _a !== void 0 ? _a : numberingSystems[language];
if (localeNumberingSystems) {
return createArrayFromListOrRestricted(__spreadArray([], localeNumberingSystems, true), restricted);
}
return createArrayFromListOrRestricted([], restricted);
}
function timeZonesOfLocale(loc) {
var locInternalSlots = getInternalSlots(loc);
var locale = locInternalSlots.locale;
var region = parseUnicodeLanguageId(locale).region;
if (!region) {
return undefined;
}
var preferredTimeZones = getTimeZonePreferenceForRegion(region);
preferredTimeZones.sort();
return Array.from(preferredTimeZones);
}
function translateCharacterOrder(order) {
if (order === 'right-to-left') {
return 'rtl';
}
return 'ltr';
}
function characterDirectionOfLocale(loc) {
var locale = loc.minimize().toString();
return translateCharacterOrder(characterOrders[locale]);
}
function weekInfoOfLocale(loc) {
var locInternalSlots = getInternalSlots(loc);
var locale = locInternalSlots.locale;
var region;
if (locale !== 'root') {
region = loc.maximize().region;
}
return getWeekDataForRegion(region);
}
var TABLE_1 = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
function weekdayToString(fw) {
return TABLE_1[+fw];
}
var Locale = /** @class */ (function () {
function Locale(tag, opts) {
// test262/test/intl402/RelativeTimeFormat/constructor/constructor/newtarget-undefined.js
// Cannot use `new.target` bc of IE11 & TS transpiles it to something else
var newTarget = this && this instanceof Locale ? this.constructor : void 0;
if (!newTarget) {
throw new TypeError("Intl.Locale must be called with 'new'");
}
var relevantExtensionKeys = Locale.relevantExtensionKeys;
var internalSlotsList = [
'initializedLocale',
'locale',
'calendar',
'collation',
'hourCycle',
'numberingSystem',
];
if (relevantExtensionKeys.indexOf('kf') > -1) {
internalSlotsList.push('caseFirst');
}
if (relevantExtensionKeys.indexOf('kn') > -1) {
internalSlotsList.push('numeric');
}
if (tag === undefined) {
throw new TypeError("First argument to Intl.Locale constructor can't be empty or missing");
}
if (typeof tag !== 'string' && typeof tag !== 'object') {
throw new TypeError('tag must be a string or object');
}
var tagInternalSlots;
if (typeof tag === 'object' &&
(tagInternalSlots = getInternalSlots(tag)) &&
HasOwnProperty(tagInternalSlots, 'initializedLocale')) {
tag = tagInternalSlots.locale;
}
else {
tag = tag.toString();
}
var internalSlots = getInternalSlots(this, internalSlotsList);
var options = CoerceOptionsToObject(opts);
tag = applyOptionsToTag(tag, options);
var opt = Object.create(null);
var calendar = GetOption(options, 'calendar', 'string', undefined, undefined);
if (calendar !== undefined) {
if (!UNICODE_TYPE_REGEX.test(calendar)) {
throw new RangeError('invalid calendar');
}
}
opt.ca = calendar;
var collation = GetOption(options, 'collation', 'string', undefined, undefined);
if (collation !== undefined) {
if (!UNICODE_TYPE_REGEX.test(collation)) {
throw new RangeError('invalid collation');
}
}
opt.co = collation;
var fw = GetOption(options, 'firstDayOfWeek', 'string', undefined, undefined);
if (fw !== undefined) {
fw = weekdayToString(fw);
if (!ALPHANUM_3_8.test(fw)) {
throw new RangeError('Invalid firstDayOfWeek');
}
}
opt.fw = fw;
var hc = GetOption(options, 'hourCycle', 'string', ['h11', 'h12', 'h23', 'h24'], undefined);
opt.hc = hc;
var kf = GetOption(options, 'caseFirst', 'string', ['upper', 'lower', 'false'], undefined);
opt.kf = kf;
var _kn = GetOption(options, 'numeric', 'boolean', undefined, undefined);
var kn;
if (_kn !== undefined) {
kn = String(_kn);
}
opt.kn = kn;
var numberingSystem = GetOption(options, 'numberingSystem', 'string', undefined, undefined);
if (numberingSystem !== undefined) {
if (!UNICODE_TYPE_REGEX.test(numberingSystem)) {
throw new RangeError('Invalid numberingSystem');
}
}
opt.nu = numberingSystem;
var r = applyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys);
internalSlots.locale = r.locale;
internalSlots.calendar = r.ca;
internalSlots.collation = r.co;
internalSlots.firstDayOfWeek = r.fw;
internalSlots.hourCycle = r.hc;
if (relevantExtensionKeys.indexOf('kf') > -1) {
internalSlots.caseFirst = r.kf;
}
if (relevantExtensionKeys.indexOf('kn') > -1) {
internalSlots.numeric = SameValue(r.kn, 'true');
}
internalSlots.numberingSystem = r.nu;
}
/**
* https://www.unicode.org/reports/tr35/#Likely_Subtags
*/
Locale.prototype.maximize = function () {
var locale = getInternalSlots(this).locale;
try {
var maximizedLocale = addLikelySubtags(locale);
return new Locale(maximizedLocale);
}
catch (e) {
return new Locale(locale);
}
};
/**
* https://www.unicode.org/reports/tr35/#Likely_Subtags
*/
Locale.prototype.minimize = function () {
var locale = getInternalSlots(this).locale;
try {
var minimizedLocale = removeLikelySubtags(locale);
return new Locale(minimizedLocale);
}
catch (e) {
return new Locale(locale);
}
};
Locale.prototype.toString = function () {
return getInternalSlots(this).locale;
};
Object.defineProperty(Locale.prototype, "baseName", {
get: function () {
var locale = getInternalSlots(this).locale;
return emitUnicodeLanguageId(parseUnicodeLanguageId(locale));
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "calendar", {
get: function () {
return getInternalSlots(this).calendar;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "collation", {
get: function () {
return getInternalSlots(this).collation;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "caseFirst", {
get: function () {
return getInternalSlots(this).caseFirst;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "numeric", {
get: function () {
return getInternalSlots(this).numeric;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "numberingSystem", {
get: function () {
return getInternalSlots(this).numberingSystem;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "language", {
/**
* https://tc39.es/proposal-intl-locale/#sec-Intl.Locale.prototype.language
*/
get: function () {
var locale = getInternalSlots(this).locale;
return parseUnicodeLanguageId(locale).lang;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "script", {
/**
* https://tc39.es/proposal-intl-locale/#sec-Intl.Locale.prototype.script
*/
get: function () {
var locale = getInternalSlots(this).locale;
return parseUnicodeLanguageId(locale).script;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "region", {
/**
* https://tc39.es/proposal-intl-locale/#sec-Intl.Locale.prototype.region
*/
get: function () {
var locale = getInternalSlots(this).locale;
return parseUnicodeLanguageId(locale).region;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "firstDayOfWeek", {
get: function () {
var internalSlots = getInternalSlots(this);
if (!HasOwnProperty(internalSlots, 'initializedLocale')) {
throw new TypeError('Error uninitialized locale');
}
return internalSlots.firstDayOfWeek;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Locale.prototype, "hourCycle", {
get: function () {
var internalSlots = getInternalSlots(this);
if (!HasOwnProperty(internalSlots, 'initializedLocale')) {
throw new TypeError('Error uninitialized locale');
}
return internalSlots.hourCycle;
},
enumerable: false,
configurable: true
});
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getCalendars
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getCalendars
*/
Locale.prototype.getCalendars = function () {
return calendarsOfLocale(this);
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getCollations
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getCollations
*/
Locale.prototype.getCollations = function () {
return collationsOfLocale(this);
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getHourCycles
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getHourCycles
*/
Locale.prototype.getHourCycles = function () {
var internalSlots = getInternalSlots(this);
if (!HasOwnProperty(internalSlots, 'initializedLocale')) {
throw new TypeError('Error uninitialized locale');
}
return hourCyclesOfLocale(this);
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getNumberingSystems
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getNumberingSystems
*/
Locale.prototype.getNumberingSystems = function () {
return numberingSystemsOfLocale(this);
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTimeZones
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getTimeZones
*/
Locale.prototype.getTimeZones = function () {
return timeZonesOfLocale(this);
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getTextInfo
*/
Locale.prototype.getTextInfo = function () {
var info = Object.create(Object.prototype);
var dir = characterDirectionOfLocale(this);
createDataProperty(info, 'direction', dir);
return info;
};
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo
* https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.getWeekInfo
*/
Locale.prototype.getWeekInfo = function () {
var info = Object.create(Object.prototype);
var internalSlots = getInternalSlots(this);
if (!HasOwnProperty(internalSlots, 'initializedLocale')) {
throw new TypeError('Error uninitialized locale');
}
var wi = weekInfoOfLocale(this);
var we = wi.weekend;
createDataProperty(info, 'firstDay', wi.firstDay);
createDataProperty(info, 'weekend', we);
createDataProperty(info, 'minimalDays', wi.minimalDays);
var fw = internalSlots.firstDayOfWeek;
if (fw !== undefined) {
info.firstDay = fw;
}
return info;
};
Locale.relevantExtensionKeys = RELEVANT_EXTENSION_KEYS;
Locale.polyfilled = true;
return Locale;
}());
export { Locale };
try {
if (typeof Symbol !== 'undefined') {
Object.defineProperty(Locale.prototype, Symbol.toStringTag, {
value: 'Intl.Locale',
writable: false,
enumerable: false,
configurable: true,
});
}
Object.defineProperty(Locale.prototype.constructor, 'length', {
value: 1,
writable: false,
enumerable: false,
configurable: true,
});
}
catch (e) {
// Meta fix so we're test262-compliant, not important
}
export default Locale;