@phensley/cldr-core
Version:
Core library for @phensley/cldr
256 lines • 9.42 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
var languagetag_1 = require("./languagetag");
var parser_1 = require("./parser");
var util_1 = require("./util");
var string_1 = require("../utils/string");
var autogen_aliases_1 = require("./autogen.aliases");
var subtags = require("./autogen.subtags");
/**
* Put a nested map into the given map.
*/
var putMap = function (map, key) {
var val = map[key];
if (val === undefined) {
val = [];
map[key] = val;
}
return val;
};
/**
* Since a lot of comparisons will be done, we need fast access to
* core fields of LanguageTag without exposing the raw fields.
*/
var fastTag = function (real) {
// Hack to get fast access to internal core fields without exposing them.
var fake = real;
// The fast tag is used for indexing purposes. Since a field may be
// undefined, and we don't want to use its string representation of
// the undefined value (e.g. 'und', 'Zzzz', etc), we use the field's
// index number to represent undefined.
var language = fake.core[0 /* LANGUAGE */];
var script = fake.core[1 /* SCRIPT */];
var region = fake.core[2 /* REGION */];
return [
language || 0 /* LANGUAGE */,
script || 1 /* SCRIPT */,
region || 2 /* REGION */
];
};
var parseFastTag = function (raw) { return fastTag(parser_1.parseLanguageTag(raw)); };
/**
* Index holding likely subtags matches.
*/
var LikelySubtagsMap = /** @class */ (function () {
function LikelySubtagsMap(likely) {
var _this = this;
// Hack to be able to index using numbers and strings.
this.index = [];
Object.keys(likely).forEach(function (k) {
var key = parseFastTag(k);
var val = parseFastTag(likely[k]);
// Add the fast tag into the index.
var map = putMap(putMap(_this.index, key[0 /* LANGUAGE */]), key[1 /* SCRIPT */]);
map[key[2 /* REGION */]] = val;
});
}
/**
* Lookup the FastTag in the index.
*/
LikelySubtagsMap.prototype.get = function (query) {
var language = query[0 /* LANGUAGE */];
var node1 = this.index[language];
if (node1 !== undefined) {
var script = query[1 /* SCRIPT */];
var node2 = node1[script];
if (node2 !== undefined) {
var region = query[2 /* REGION */];
return node2[region] || undefined;
}
}
return undefined;
};
return LikelySubtagsMap;
}());
// Flags for subtag permutations
var F_LANGUAGE = 1;
var F_SCRIPT = 2;
var F_REGION = 4;
var MATCH_ORDER = [
F_LANGUAGE | F_SCRIPT | F_REGION,
F_LANGUAGE | F_REGION,
F_LANGUAGE | F_SCRIPT,
F_LANGUAGE,
F_SCRIPT
];
/**
* Clear or copy fields from src to dst depending on flags.
*/
var setFields = function (src, dst, flags) {
dst[0 /* LANGUAGE */] = (flags & F_LANGUAGE) === 0 ? 0 /* LANGUAGE */ : src[0 /* LANGUAGE */];
dst[1 /* SCRIPT */] = (flags & F_SCRIPT) === 0 ? 1 /* SCRIPT */ : src[1 /* SCRIPT */];
dst[2 /* REGION */] = (flags & F_REGION) === 0 ? 2 /* REGION */ : src[2 /* REGION */];
};
/**
* Lookup any aliases that match this tag, and replace any undefined subtags.
*/
var substituteLanguageAliases = function (dst) {
var aliases = LANGUAGE_ALIAS_MAP[dst[0 /* LANGUAGE */]];
if (aliases === undefined) {
return;
}
for (var i = 0; i < aliases.length; i++) {
var _a = aliases[i], type = _a.type, repl = _a.repl;
var exact = (type[0 /* LANGUAGE */] === dst[0 /* LANGUAGE */] &&
type[1 /* SCRIPT */] === dst[1 /* SCRIPT */] &&
type[2 /* REGION */] === dst[2 /* REGION */]);
if ((type[1 /* SCRIPT */] === 1 /* SCRIPT */ && type[2 /* REGION */] === 2 /* REGION */) || exact) {
dst[0 /* LANGUAGE */] = repl[0 /* LANGUAGE */];
if (dst[1 /* SCRIPT */] === 1 /* SCRIPT */) {
dst[1 /* SCRIPT */] = repl[1 /* SCRIPT */];
}
if (dst[2 /* REGION */] === 2 /* REGION */) {
dst[2 /* REGION */] = repl[2 /* REGION */];
}
break;
}
}
};
/**
* Add any missing subtags using the likely subtags mapping. For example,
* this would convert "en" to "en-Latn-US".
*/
var addLikelySubtags = function (dst) {
var tmp = dst.slice(0);
for (var i = 0; i < MATCH_ORDER.length; i++) {
var flags = MATCH_ORDER[i];
setFields(dst, tmp, flags);
var match = LIKELY_SUBTAGS_MAP.get(tmp);
if (match !== undefined) {
if (dst[0 /* LANGUAGE */] === 0 /* LANGUAGE */) {
dst[0 /* LANGUAGE */] = match[0 /* LANGUAGE */];
}
if (dst[1 /* SCRIPT */] === 1 /* SCRIPT */) {
dst[1 /* SCRIPT */] = match[1 /* SCRIPT */];
}
if (dst[2 /* REGION */] === 2 /* REGION */) {
dst[2 /* REGION */] = match[2 /* REGION */];
}
break;
}
}
};
/**
* Return a language tag, combining the fast tag's core subtags with the
* original's additional subtags.
*/
var returnTag = function (real, fast) {
var language = fast[0 /* LANGUAGE */];
var script = fast[1 /* SCRIPT */];
var region = fast[2 /* REGION */];
return new languagetag_1.LanguageTag(typeof language === 'number' ? undefined : language, typeof script === 'number' ? undefined : script, typeof region === 'number' ? undefined : region, real.variant(), real.extensions(), real.privateUse());
};
// Undefined tag to be copied for use in resolution below.
var UNDEFINED = [0 /* LANGUAGE */, 1 /* SCRIPT */, 2 /* REGION */];
/**
* Compare two fast tags for equality. These always have identical length.
*/
var fastTagEquals = function (a, b) {
var len = a.length;
for (var i = 0; i < len; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
};
var languageAlias = string_1.stringToObject(autogen_aliases_1.languageAliasRaw, '|', ':');
var buildLanguageAliasMap = function () {
return Object.keys(languageAlias).reduce(function (o, k) {
var type = parseFastTag(k);
var repl = parseFastTag(languageAlias[k]);
var language = type[0 /* LANGUAGE */];
var aliases = o[language];
if (aliases === undefined) {
aliases = [];
o[language] = aliases;
}
aliases.push({ type: type, repl: repl });
return o;
}, {});
};
var likelySubtags = string_1.stringToObject(subtags.likelyRaw, '|', ':');
// Singleton maps.
var LANGUAGE_ALIAS_MAP = buildLanguageAliasMap();
var LIKELY_SUBTAGS_MAP = new LikelySubtagsMap(likelySubtags);
/**
* Methods for substituting language and region aliases, adding likely subtags, etc.
*
* @alpha
*/
var LanguageResolver = /** @class */ (function () {
function LanguageResolver() {
}
/**
* Substitute all relevant aliases, and then add likely subtags.
*/
LanguageResolver.resolve = function (real) {
var tag = typeof real === 'string' ? parser_1.parseLanguageTag(real) : real;
var fast = fastTag(tag);
substituteLanguageAliases(fast);
util_1.substituteRegionAliases(fast);
addLikelySubtags(fast);
return returnTag(tag, fast);
};
/**
* Add any missing subtags using the likely subtags mapping. For example,
* this would convert "en" to "en-Latn-US".
*/
LanguageResolver.addLikelySubtags = function (real) {
var tag = typeof real === 'string' ? parser_1.parseLanguageTag(real) : real;
var fast = fastTag(tag);
addLikelySubtags(fast);
return returnTag(tag, fast);
};
/**
* Remove any subtags that would be added by addLikelySubtags() above. For example,
* this would convert "en-Latn-US" to "en".
*/
LanguageResolver.removeLikelySubtags = function (real) {
var tag = typeof real === 'string' ? parser_1.parseLanguageTag(real) : real;
var max = fastTag(tag);
if (max[0 /* LANGUAGE */] === 0 /* LANGUAGE */ || max[1 /* SCRIPT */] === 1 /* SCRIPT */ || max[2 /* REGION */] === 2 /* REGION */) {
addLikelySubtags(max);
}
var tmp = UNDEFINED.slice(0);
// Using "en-Latn-US" as an example...
// 1. Match "en-Zzzz-ZZ"
tmp[0 /* LANGUAGE */] = max[0 /* LANGUAGE */];
var match = tmp.slice(0);
addLikelySubtags(match);
if (fastTagEquals(match, max)) {
return returnTag(tag, tmp);
}
// 2. Match "en-Zzzz-US"
tmp[2 /* REGION */] = max[2 /* REGION */];
match = tmp.slice(0);
addLikelySubtags(match);
if (fastTagEquals(match, max)) {
tmp[0 /* LANGUAGE */] = max[0 /* LANGUAGE */];
return returnTag(tag, tmp);
}
// 3. Match "en-Latn-ZZ"
tmp[2 /* REGION */] = 2 /* REGION */;
tmp[1 /* SCRIPT */] = max[1 /* SCRIPT */];
match = tmp.slice(0);
addLikelySubtags(match);
if (fastTagEquals(match, max)) {
return returnTag(tag, tmp);
}
// 4. Nothing matched, so return a copy of the original tag.
return returnTag(tag, max);
};
return LanguageResolver;
}());
exports.LanguageResolver = LanguageResolver;
//# sourceMappingURL=resolver.js.map
;