MediaWiki:Gadget-diplomat.js
Jump to navigation
Jump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* jslint esversion: 6 */
(() => {
// index.js
var variablePrefix = "diplomat";
function getLanguageFromURL(url) {
let language = new URLSearchParams(url.hash.substr(1)).get("language");
return language === "" ? null : language;
}
function getLocales() {
let parameter = getLanguageFromURL(window.location)?.split(",");
let userLocales = parameter ?? navigator.languages ?? [navigator.language];
let locales = [];
let localeSet = /* @__PURE__ */ new Set();
for (let locale of userLocales) {
let components = locale.split("-");
while (components.length > 0) {
let parent = components.join("-");
try {
new Intl.Locale(parent);
if (!localeSet.has(parent)) locales.push(parent);
localeSet.add(parent);
} catch {
}
components.pop();
if (components.at(-1)?.length === 2 && components.at(-2) === "u") {
components.pop();
}
}
}
return locales;
}
var defaultUnlocalizedNameProperty = "name";
function getLocalizedNameExpression(locales, options = {}) {
let nameFields = [
...locales.flatMap((l) => {
let localizedNamePropertyFormat = options.localizedNamePropertyFormat || `name:$1`;
let localizedNameProperty = localizedNamePropertyFormat.replaceAll(
"$1",
l
);
let fields = [localizedNameProperty];
if (options.includesLegacyFields && (l === "de" || l === "en")) {
fields.push(localizedNameProperty.replaceAll(":", "_"));
}
return fields;
}),
options.unlocalizedNameProperty || defaultUnlocalizedNameProperty
];
return ["coalesce", ...nameFields.map((f) => ["get", f])];
}
function updateVariable(letExpr, variable, value) {
if (!letExpr || letExpr[0] !== "let") return;
let variableNameIndex = letExpr.indexOf(variable);
if (variableNameIndex % 2 === 1) {
letExpr[variableNameIndex + 1] = value;
} else {
letExpr.splice(-1, 0, variable, value);
}
}
var localizedNameVariable = `${variablePrefix}__localizedName`;
var localizedCollatorVariable = `${variablePrefix}__localizedCollator`;
var diacriticInsensitiveCollatorVariable = `${variablePrefix}__diacriticInsensitiveCollator`;
function replacePropertyReferences(expression, propertyName, replacement) {
if (!Array.isArray(expression) || expression[0] === "literal") return;
if (expression[0] === "get") {
if (expression.length === 2 && expression[1] === propertyName) {
return replacement;
}
return;
}
let didReplace = false;
expression.forEach((arg, idx) => {
if (!idx) return;
let newValue = replacePropertyReferences(arg, propertyName, replacement);
if (newValue !== void 0) {
expression[idx] = newValue;
didReplace = true;
}
});
if (didReplace) return expression;
}
var inlineSeparator = " \u2022 ";
function prepareLayer(layer, unlocalizedNameProperty) {
let textField = layer.layout && layer.layout["text-field"];
if (!textField || textField[0] === "let" && textField.includes(localizedNameVariable)) {
return;
}
let symbolPlacement = layer.layout && layer.layout["symbol-placement"];
let isInline = symbolPlacement === "line" || symbolPlacement === "line-center";
let separator = isInline ? inlineSeparator : "\n";
let listValues = listValuesExpression(
["var", localizedNameVariable],
separator
);
let newTextField = replacePropertyReferences(
textField,
unlocalizedNameProperty || defaultUnlocalizedNameProperty,
listValues
);
if (newTextField !== void 0) {
layer.layout["text-field"] = [
"let",
localizedNameVariable,
"",
newTextField
];
}
}
function localizeLayer(layer, collationLocale, localizedNameExpression, legacyLocalizedNameExpression) {
if (!("layout" in layer) || !("text-field" in layer.layout)) return;
let textField = layer.layout["text-field"];
updateVariable(
textField,
localizedNameVariable,
// https://github.com/openmaptiles/openmaptiles/issues/769
layer["source-layer"] === "transportation_name" ? legacyLocalizedNameExpression : localizedNameExpression
);
updateVariable(textField, localizedCollatorVariable, [
"collator",
{
"case-sensitive": false,
"diacritic-sensitive": true,
locale: collationLocale
}
]);
updateVariable(textField, diacriticInsensitiveCollatorVariable, [
"collator",
{
"case-sensitive": false,
"diacritic-sensitive": !/^en\b/.test(collationLocale),
locale: collationLocale
}
]);
}
function localizeLayers(layers, locales = getLocales(), options = {}) {
let localizedNameExpression = getLocalizedNameExpression(locales, options);
let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {
...options,
includesLegacyFields: true
});
for (let layer of layers) {
localizeLayer(
layer,
locales[0],
localizedNameExpression,
legacyLocalizedNameExpression
);
}
}
function listValueExpression(list, separator, valueToOmit, listStart, numReplacements) {
let asIs = ["slice", list, listStart];
if (numReplacements <= 0) {
return asIs;
}
let iteration = numReplacements;
let rawSeparator = ";";
let needleStartVariable = `${variablePrefix}__needleStart${iteration}`;
let needleEndVariable = `${variablePrefix}__needleEnd${iteration}`;
let valueVariable = `${variablePrefix}__value${iteration}`;
let lookaheadVariable = `${variablePrefix}__lookahead${iteration}`;
let nextListStartVariable = `${variablePrefix}__nextListStart${iteration}`;
return [
"let",
needleStartVariable,
["index-of", rawSeparator, list, listStart],
[
"case",
[">=", ["var", needleStartVariable], 0],
// Found a semicolon.
[
"let",
valueVariable,
["slice", list, listStart, ["var", needleStartVariable]],
needleEndVariable,
["+", ["var", needleStartVariable], rawSeparator.length],
[
"concat",
// Start with everything before the semicolon unless it's the value to
// omit.
[
"case",
["==", ["var", valueVariable], valueToOmit],
"",
["var", valueVariable]
],
[
"let",
lookaheadVariable,
// Look ahead by one character.
[
"slice",
list,
["var", needleEndVariable],
["+", ["var", needleEndVariable], rawSeparator.length]
],
[
"let",
// Skip past the current value and semicolon for any subsequent
// searches.
nextListStartVariable,
[
"+",
["var", needleEndVariable],
// Also skip past any escaped semicolon or space padding.
[
"match",
["var", lookaheadVariable],
[rawSeparator, " "],
rawSeparator.length,
0
]
],
[
"case",
// If the only remaining value is the value to omit, stop
// scanning.
[
"==",
["slice", list, ["var", nextListStartVariable]],
valueToOmit
],
"",
[
"concat",
[
"case",
// If the lookahead character is another semicolon, append
// an unescaped semicolon.
["==", ["var", lookaheadVariable], rawSeparator],
rawSeparator,
// Otherwise, if the value is the value to omit, do nothing.
["==", ["var", valueVariable], valueToOmit],
"",
// Otherwise, append the passed-in separator.
separator
],
// Recurse for the next value in the value list.
listValueExpression(
list,
separator,
valueToOmit,
["var", nextListStartVariable],
numReplacements - 1
)
]
]
]
]
]
],
// No semicolons left in the string, so stop looking and append the value as is.
asIs
]
];
}
var maxValueListLength = 3;
function listValuesExpression(valueList, separator, valueToOmit) {
let maxSeparators = maxValueListLength - 1;
let valueListVariable = `${variablePrefix}__valueList`;
let valueToOmitVariable = `${variablePrefix}__valueToOmit`;
return [
"let",
valueListVariable,
valueList,
valueToOmitVariable,
valueToOmit || ";",
listValueExpression(
["var", valueListVariable],
separator,
["var", valueToOmitVariable],
0,
maxSeparators
)
];
}
var localizedName = [
"let",
localizedNameVariable,
"",
listValuesExpression(["var", localizedNameVariable], "\n")
];
var localizedNameInline = [
"let",
localizedNameVariable,
"",
listValuesExpression(["var", localizedNameVariable], inlineSeparator)
];
function startsWithExpression(target, candidatePrefix, collator) {
let wordBoundaries = " ,";
return [
"all",
[
"==",
["slice", target, 0, ["length", candidatePrefix]],
candidatePrefix,
collator
],
[
"in",
[
"slice",
// Pad the target in case the prefix matches exactly.
// "Montreal " vs. "Montréal"
["concat", target, wordBoundaries[0]],
["length", candidatePrefix],
["+", ["length", candidatePrefix], 1]
],
wordBoundaries
]
];
}
function overwritePrefixExpression(target, newPrefix) {
return ["concat", newPrefix, ["slice", target, ["length", newPrefix]]];
}
function endsWithExpression(target, candidateSuffix, collator) {
let wordBoundary = " ";
let suffixStartVariable = `${variablePrefix}__suffixStart`;
return [
"let",
suffixStartVariable,
["-", ["length", target], ["length", candidateSuffix]],
[
"all",
[
"==",
["slice", target, ["var", suffixStartVariable]],
candidateSuffix,
collator
],
[
"==",
[
"slice",
target,
["-", ["var", suffixStartVariable], 1],
["var", suffixStartVariable]
],
wordBoundary
]
]
];
}
function overwriteSuffixExpression(target, newSuffix) {
return [
"concat",
["slice", target, 0, ["-", ["length", target], ["length", newSuffix]]],
newSuffix
];
}
var localizedNameListVariable = `${variablePrefix}__localizedNameList`;
var nameListVariable = `${variablePrefix}__nameList`;
var localizedNameWithLocalGloss = [
"let",
localizedNameVariable,
"",
localizedCollatorVariable,
["collator", {}],
diacriticInsensitiveCollatorVariable,
["collator", {}],
[
"let",
localizedNameListVariable,
listValuesExpression(["var", localizedNameVariable], "\n"),
[
"case",
// If the name in the preferred and local languages match exactly...
[
"==",
["var", localizedNameVariable],
["get", "name"],
["var", localizedCollatorVariable]
],
// ...just pick one.
["format", ["var", localizedNameListVariable]],
[
"let",
nameListVariable,
listValuesExpression(["get", "name"], "\n"),
[
"case",
// If the name in the preferred language is the same as the name in the
// local language except for the omission of diacritics and/or the addition
// of a suffix (e.g., "City" in English)...
startsWithExpression(
["var", localizedNameVariable],
["get", "name"],
["var", diacriticInsensitiveCollatorVariable]
),
// ...then replace the common prefix with the local name.
[
"format",
overwritePrefixExpression(
["var", localizedNameVariable],
["var", nameListVariable]
)
],
// If the name in the preferred language is the same as the name in the
// local language except for the omission of diacritics and/or the addition
// of a prefix (e.g., "City of" in English or "Ciudad de" in Spanish)...
endsWithExpression(
["var", localizedNameVariable],
["get", "name"],
["var", diacriticInsensitiveCollatorVariable]
),
// ...then replace the common suffix with the local name.
[
"format",
overwriteSuffixExpression(
["var", localizedNameVariable],
["var", nameListVariable]
)
],
// Otherwise, gloss the name in the local language if it differs from the
// localized name.
[
"format",
["var", localizedNameListVariable],
"\n",
"(\u2068",
{ "font-scale": 0.8 },
listValuesExpression(["get", "name"], inlineSeparator, [
"var",
localizedNameVariable
]),
{ "font-scale": 0.8 },
"\u2069)",
{ "font-scale": 0.8 }
]
]
]
]
]
];
var iso3166_1_alpha_2_by_3 = {
ABW: "AW",
AFG: "AF",
AGO: "AO",
AIA: "AI",
ALB: "AL",
AND: "AD",
ARE: "AE",
ARG: "AR",
ARM: "AM",
ASM: "AS",
ATA: "AQ",
ATF: "TF",
ATG: "AG",
AUS: "AU",
AUT: "AT",
AZE: "AZ",
BDI: "BI",
BEL: "BE",
BEN: "BJ",
BFA: "BF",
BGD: "BD",
BGR: "BG",
BHR: "BH",
BHS: "BS",
BIH: "BA",
BLM: "BL",
BLR: "BY",
BLZ: "BZ",
BMU: "BM",
BOL: "BO",
BRA: "BR",
BRB: "BB",
BRN: "BN",
BTN: "BT",
BVT: "BV",
BWA: "BW",
CAF: "CF",
CAN: "CA",
CCK: "CC",
CHE: "CH",
CHL: "CL",
CHN: "CN",
CIV: "CI",
CMR: "CM",
COD: "CD",
COG: "CG",
COK: "CK",
COL: "CO",
COM: "KM",
CPV: "CV",
CRI: "CR",
CUB: "CU",
CUW: "CW",
CXR: "CX",
CYM: "KY",
CYP: "CY",
CZE: "CZ",
DEU: "DE",
DJI: "DJ",
DMA: "DM",
DNK: "DK",
DOM: "DO",
DZA: "DZ",
ECU: "EC",
EGY: "EG",
ERI: "ER",
ESH: "EH",
ESP: "ES",
EST: "EE",
ETH: "ET",
FIN: "FI",
FJI: "FJ",
FLK: "FK",
FRA: "FR",
FRO: "FO",
FSM: "FM",
FXX: "FX",
GAB: "GA",
GBR: "GB",
GEO: "GE",
GGY: "GG",
GHA: "GH",
GIB: "GI",
GIN: "GN",
GLP: "GP",
GMB: "GM",
GNB: "GW",
GNQ: "GQ",
GRC: "GR",
GRD: "GD",
GRL: "GL",
GTM: "GT",
GUF: "GF",
GUM: "GU",
GUY: "GY",
HKG: "HK",
HMD: "HM",
HND: "HN",
HRV: "HR",
HTI: "HT",
HUN: "HU",
IDN: "ID",
IMN: "IM",
IND: "IN",
IOT: "IO",
IRL: "IE",
IRN: "IR",
IRQ: "IQ",
ISL: "IS",
ISR: "IL",
ITA: "IT",
JAM: "JM",
JEY: "JE",
JOR: "JO",
JPN: "JP",
KAZ: "KZ",
KEN: "KE",
KGZ: "KG",
KHM: "KH",
KIR: "KI",
KNA: "KN",
KOR: "KR",
KWT: "KW",
LAO: "LA",
LBN: "LB",
LBR: "LR",
LBY: "LY",
LCA: "LC",
LIE: "LI",
LKA: "LK",
LSO: "LS",
LTU: "LT",
LUX: "LU",
LVA: "LV",
MAC: "MO",
MAF: "MF",
MAR: "MA",
MCO: "MC",
MDA: "MD",
MDG: "MG",
MDV: "MV",
MEX: "MX",
MHL: "MH",
MKD: "MK",
MLI: "ML",
MLT: "MT",
MMR: "MM",
MNE: "ME",
MNG: "MN",
MNP: "MP",
MOZ: "MZ",
MRT: "MR",
MSR: "MS",
MTQ: "MQ",
MUS: "MU",
MWI: "MW",
MYS: "MY",
MYT: "YT",
NAM: "NA",
NCL: "NC",
NER: "NE",
NFK: "NF",
NGA: "NG",
NIC: "NI",
NIU: "NU",
NLD: "NL",
NOR: "NO",
NPL: "NP",
NRU: "NR",
NZL: "NZ",
OMN: "OM",
PAK: "PK",
PAN: "PA",
PCN: "PN",
PER: "PE",
PHL: "PH",
PLW: "PW",
PNG: "PG",
POL: "PL",
PRI: "PR",
PRK: "KP",
PRT: "PT",
PRY: "PY",
PSE: "PS",
PYF: "PF",
QAT: "QA",
REU: "RE",
ROU: "RO",
RUS: "RU",
RWA: "RW",
SAU: "SA",
SDN: "SD",
SEN: "SN",
SGP: "SG",
SGS: "GS",
SHN: "SH",
SJM: "SJ",
SLB: "SB",
SLE: "SL",
SLV: "SV",
SMR: "SM",
SOM: "SO",
SPM: "PM",
SRB: "RS",
SSD: "SS",
STP: "ST",
SUR: "SR",
SVK: "SK",
SVN: "SI",
SWE: "SE",
SWZ: "SZ",
SXM: "SX",
SYC: "SC",
SYR: "SY",
TCA: "TC",
TCD: "TD",
TGO: "TG",
THA: "TH",
TJK: "TJ",
TKL: "TK",
TKM: "TM",
TLS: "TL",
TON: "TO",
TTO: "TT",
TUN: "TN",
TUR: "TR",
TUV: "TV",
TWN: "TW",
TZA: "TZ",
UGA: "UG",
UKR: "UA",
UMI: "UM",
URY: "UY",
USA: "US",
UZB: "UZ",
VAT: "VA",
VCT: "VC",
VEN: "VE",
VGB: "VG",
VIR: "VI",
VNM: "VN",
VUT: "VU",
WLF: "WF",
WSM: "WS",
YEM: "YE",
ZAF: "ZA",
ZMB: "ZM",
ZWE: "ZW"
};
var countryNamesByCodeVariable = `${variablePrefix}__countryNamesByCode`;
function getLocalizedCountryNames(locales, options = {}) {
let countryNames = new Intl.DisplayNames(locales, {
type: "region",
fallback: "none"
});
return Object.fromEntries(
Object.entries(iso3166_1_alpha_2_by_3).map((e) => {
let name = countryNames.of(e[1]);
if (name && options?.uppercase) {
name = name.toLocaleUpperCase(locales).replaceAll(" ", " ");
}
return [e[0], name];
})
);
}
function getGlobalStateForLocalization(locales, options = {}) {
let state = {};
state[countryNamesByCodeVariable] = getLocalizedCountryNames(locales, {
uppercase: options?.uppercaseCountryNames
});
return state;
}
function getLocalizedCountryNameExpression(code) {
return [
"let",
"code",
code,
[
"coalesce",
[
"get",
["var", "code"],
[
"coalesce",
["global-state", countryNamesByCodeVariable],
["literal", {}]
]
],
// Fall back to the country code in parentheses.
["concat", "(", ["var", "code"], ")"]
]
];
}
if (typeof window !== "undefined" && "maplibregl" in window) {
maplibregl.Diplomat = {
getGlobalStateForLocalization,
getLanguageFromURL,
getLocales,
getLocalizedCountryNameExpression,
listValuesExpression,
localizeLayers,
localizedName,
localizedNameInline,
localizedNameWithLocalGloss
};
maplibregl.Map.prototype.localizeStyle = function(locales = getLocales(), options = {}) {
let style = this.getStyle();
let localizedNameExpression = getLocalizedNameExpression(locales, options);
let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {
...options,
includesLegacyFields: true
});
let layers = options.layers?.map((n) => style.layers[n]) || style.layers;
for (let layer of layers) {
prepareLayer(layer, options?.unlocalizedNameProperty);
localizeLayer(
layer,
locales[0],
localizedNameExpression,
legacyLocalizedNameExpression
);
}
let countryNames = getLocalizedCountryNames(locales, {
uppercase: options?.uppercaseCountryNames
});
this.setGlobalStateProperty(countryNamesByCodeVariable, countryNames);
this.setStyle(style);
};
}
})();
//# sourceMappingURL=https://unpkg.com/@americana/[email protected]/dist/index.js.map