@americana/diplomat 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/dist/index.js +5 -5
- package/dist/index.js.map +3 -3
- package/index.d.ts +85 -0
- package/index.js +79 -21
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Diplomat gives all parties a win-win:
|
|
|
14
14
|
|
|
15
15
|
- Tailors labels to the user’s preferred language.
|
|
16
16
|
- Respects multilingualism with optional dual language labels: both the user’s preferred language and the local native language.
|
|
17
|
-
- Recognizes any language, dialect, or script out of the box.
|
|
17
|
+
- Recognizes any language, dialect, or script out of the box with sophisticated language code matching.
|
|
18
18
|
|
|
19
19
|
Diplomat lets your designer save face:
|
|
20
20
|
|
|
@@ -238,6 +238,23 @@ Example:
|
|
|
238
238
|
maplibregl.Diplomat.getLocales().includes("en");
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
+
### `maplibregl.Diplomat.getRelatedLanguageTags()`
|
|
242
|
+
|
|
243
|
+
Returns an array of the language tags related to the given language tag, sorted from most specific to least specific.
|
|
244
|
+
|
|
245
|
+
Parameters:
|
|
246
|
+
|
|
247
|
+
- **`tag`** (`string`): The language tag that the returned language tags are related to.
|
|
248
|
+
|
|
249
|
+
Returns a sorted array of related language tags, or an empty array if `tag` is malformed.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
|
|
253
|
+
```js
|
|
254
|
+
maplibregl.Diplomat.getRelatedLanguageTags("sr-RS").includes("sr-Cyrl");
|
|
255
|
+
maplibregl.Diplomat.getRelatedLanguageTags("zh").includes("zh-Hans-CN");
|
|
256
|
+
```
|
|
257
|
+
|
|
241
258
|
### `maplibregl.Diplomat.localizeStyle()`
|
|
242
259
|
|
|
243
260
|
Updates each style layer's `text-field` value to match the given locales, upgrading any unlocalizable layer along the way.
|
|
@@ -283,7 +300,7 @@ Diplomat only switches between languages that are present in the stylesheet’s
|
|
|
283
300
|
|
|
284
301
|
By default, MapLibre GL JS does not support bidirectional text. Arabic, Hebrew, and other right-to-left languages will be unreadable unless you [install the mapbox-gl-rtl-text plugin](https://maplibre.org/maplibre-gl-js/docs/examples/add-support-for-right-to-left-scripts/).
|
|
285
302
|
|
|
286
|
-
Diplomat
|
|
303
|
+
Diplomat performs basic language fallbacks according to the [ICU locale fallback algorithm](https://unicode-org.github.io/icu/userguide/locale/#fallback). Additionally, it implements the [Likely Subtags](https://www.unicode.org/reports/tr35/#Likely_Subtags) algorithm of Unicode Technical Standard #35, so for example requesting either `zh` or `cmn` returns a name tagged as `zh-Hans-CN`, among other variations. However, in general, it does not fall back to a related but distinct language code, such as from `sr-Cyrl` to `ru` or from `nb` to `no`. Instead, the user can [set their preferred languages](https://www.w3.org/International/questions/qa-lang-priorities) in their browser or operating system settings.
|
|
287
304
|
|
|
288
305
|
For historical reasons, [OpenStreetMap’s coverage in many reasons](https://wiki.openstreetmap.org/wiki/Multilingual_names) encodes multiple local names separated by human-readable punctuation. Diplomat makes no attempt to guess which punctuation is part of a name and which punctuation delimits two names.
|
|
289
306
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(()=>{var
|
|
2
|
-
`),
|
|
3
|
-
`),["case",["==",["var",
|
|
4
|
-
`),["case",
|
|
5
|
-
`,"(\u2068",{"font-scale":.8},
|
|
1
|
+
(()=>{var u="diplomat";function E(e){let t=new URLSearchParams(e.hash.substr(1)).get("language");return t===""?null:t}function O(e){return e.reduce((t,a)=>[...t,...t.map(l=>[...l,a])],[[]])}function B(e){return e.variants??e.minimize().baseName.match(/-([-\w]+)/)?.[1]}function h(e){let t;try{t=new Intl.Locale(e)}catch{return[]}let a=t.maximize(),l=[a.script,a.region,B(a),a.numberingSystem].filter(n=>n),r=O(l).map(n=>[a.language,...n].join("-"));r.push(t+""),r.push(t.baseName);let i=r.map(n=>{try{return new Intl.Locale(n)}catch{}}).filter(n=>n),o=n=>{let N=n+"",L=0;return L+=N.length??0,L+=N.split("-").length??0,L+=B(n)?.length??0,L+=N.match(/(?:-[tx]-|-u-\w\w-)\w+/)?.[0]?.length??0,L};i.sort((n,N)=>o(N)-o(n));let c=i.map(n=>n+"");return[...new Set(c)]}function S(){let a=(E(window.location)?.split(",")??navigator.languages??[navigator.language]).flatMap(l=>h(l));return[...new Set(a)]}var I="name";function A(e,t={}){return["coalesce",...[...e.flatMap(l=>{let i=(t.localizedNamePropertyFormat||"name:$1").replaceAll("$1",l),o=[i];return t.includesLegacyFields&&(l==="de"||l==="en")&&o.push(i.replaceAll(":","_")),o}),t.unlocalizedNameProperty||I].map(l=>["get",l])]}function R(e,t,a){if(!e||e[0]!=="let")return;let l=e.indexOf(t);l%2===1?e[l+1]=a:e.splice(-1,0,t,a)}var s=`${u}__localizedName`,T=`${u}__localizedCollator`,d=`${u}__diacriticInsensitiveCollator`;function y(e,t,a){if(!Array.isArray(e)||e[0]==="literal")return;if(e[0]==="get")return e.length===2&&e[1]===t?a:void 0;let l=!1;if(e.forEach((r,i)=>{if(!i)return;let o=y(r,t,a);o!==void 0&&(e[i]=o,l=!0)}),l)return e}var P=" \u2022 ";function H(e,t,a){let l=e.layout&&e.layout["text-field"];if(!l||l[0]==="let"&&l.includes(s))return;let r=e.layout&&e.layout["symbol-placement"],c=y(l,t||I,a?K:r==="line"||r==="line-center"?F:U);c!==void 0&&(e.layout["text-field"]=["let",s,"",c])}function V(e,t,a,l){if(!("layout"in e)||!("text-field"in e.layout))return;let r=e.layout["text-field"];R(r,s,e["source-layer"]==="transportation_name"?l:a),R(r,T,["collator",{"case-sensitive":!1,"diacritic-sensitive":!0,locale:t}]),R(r,d,["collator",{"case-sensitive":!1,"diacritic-sensitive":!/^en\b/.test(t),locale:t}])}function _(e,t=S(),a={}){let l=A(t,a),r=A(t,{...a,includesLegacyFields:!0});for(let i of e)V(i,t[0],l,r)}function v(e,t,a,l,r){let i=["slice",e,l];if(r<=0)return i;let o=r,c=";",n=`${u}__needleStart${o}`,N=`${u}__needleEnd${o}`,L=`${u}__value${o}`,m=`${u}__lookahead${o}`,C=`${u}__nextListStart${o}`;return["let",n,["index-of",c,e,l],["case",[">=",["var",n],0],["let",L,["slice",e,l,["var",n]],N,["+",["var",n],c.length],["concat",["case",["==",["var",L],a],"",["var",L]],["let",m,["slice",e,["var",N],["+",["var",N],c.length]],["let",C,["+",["var",N],["match",["var",m],[c," "],c.length,0]],["case",["==",["slice",e,["var",C]],a],"",["concat",["case",["==",["var",m],c],c,["==",["var",L],a],"",t],v(e,t,a,["var",C],r-1)]]]]]],i]]}var z=3;function M(e,t,a){let l=z-1,r=`${u}__valueList`,i=`${u}__valueToOmit`;return["let",r,e,i,a||";",v(["var",r],t,["var",i],0,l)]}var U=M(["var",s],`
|
|
2
|
+
`),b=["let",s,"",U],F=M(["var",s],P),x=["let",s,"",F];function W(e,t,a){let l=" ,";return["all",["==",["slice",e,0,["length",t]],t,a],["in",["slice",["concat",e,l[0]],["length",t],["+",["length",t],1]],l]]}function Z(e,t){return["concat",t,["slice",e,["length",t]]]}function w(e,t,a){let l=" ",r=`${u}__suffixStart`;return["let",r,["-",["length",e],["length",t]],["all",["==",["slice",e,["var",r]],t,a],["==",["slice",e,["-",["var",r],1],["var",r]],l]]]}function Y(e,t){return["concat",["slice",e,0,["-",["length",e],["length",t]]],t]}var f=`${u}__localizedNameList`,G=`${u}__nameList`,K=["let",f,M(["var",s],`
|
|
3
|
+
`),["case",["==",["var",s],["get","name"],["var",T]],["format",["var",f]],["let",G,M(["get","name"],`
|
|
4
|
+
`),["case",W(["var",s],["get","name"],["var",d]),["format",Z(["var",s],["var",G])],w(["var",s],["get","name"],["var",d]),["format",Y(["var",s],["var",G])],["format",["var",f],`
|
|
5
|
+
`,"(\u2068",{"font-scale":.8},M(["get","name"],P,["var",s]),{"font-scale":.8},"\u2069)",{"font-scale":.8}]]]]],$=["let",s,"",T,["collator",{}],d,["collator",{}],K],J={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"},g=`${u}__countryNamesByCode`;function D(e,t={}){let a=new Intl.DisplayNames(e,{type:"region",fallback:"none"});return Object.fromEntries(Object.entries(J).map(l=>{let r=a.of(l[1]);return r&&t?.uppercase&&(r=r.toLocaleUpperCase(e).replaceAll(" "," ")),[l[0],r]}))}function X(e,t={}){let a={};return a[g]=D(e,{uppercase:t?.uppercaseCountryNames}),a}function Q(e){return["let","code",e,["coalesce",["get",["var","code"],["coalesce",["global-state",g],["literal",{}]]],["concat","(",["var","code"],")"]]]}function p(e,t=S(),a={}){let l=e.getStyle(),r=A(t,a),i=A(t,{...a,includesLegacyFields:!0});for(let c of l.layers){let n=c["source-layer"];(!a.layers&&!a.sourceLayers||a.layers?.includes(c.id)||n&&a.sourceLayers?.includes(n))&&H(c,a?.unlocalizedNameProperty,a?.glossLocalNames),V(c,t[0],r,i)}let o=D(t,{uppercase:a?.uppercaseCountryNames});e.setGlobalStateProperty(g,o),e.setStyle(l)}typeof window<"u"&&(window.Diplomat={getGlobalStateForLocalization:X,getLanguageFromURL:E,getLocales:S,getLocalizedCountryNameExpression:Q,listValuesExpression:M,localizeLayers:_,localizeStyle:p,localizedName:b,localizedNameInline:x,localizedNameWithLocalGloss:$},"maplibregl"in window&&(maplibregl.Diplomat=window.Diplomat,maplibregl.Map.prototype.localizeStyle=function(e=S(),t={}){p(this,e,t)}));})();
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.js"],
|
|
4
|
-
"sourcesContent": ["/// A prefix that uniquely identifies this plugin, prepended onto the name of any variable generated by this plugin.\nconst variablePrefix = \"diplomat\";\n\n/**\n * Returns a list of languages as a comma-delimited string from the given URL hash.\n */\nexport function getLanguageFromURL(url) {\n let language = new URLSearchParams(url.hash.substr(1)).get(\"language\");\n return language === \"\" ? null : language;\n}\n\n/**\n * Returns the languages that the user prefers.\n */\nexport function getLocales() {\n // Check the language \"parameter\" in the hash.\n let parameter = getLanguageFromURL(window.location)?.split(\",\");\n // Fall back to the user's language preference.\n let userLocales = parameter ?? navigator.languages ?? [navigator.language];\n let locales = [];\n let localeSet = new Set(); // avoid duplicates\n for (let locale of userLocales) {\n // Add progressively less specific variants of each user-specified locale.\n let components = locale.split(\"-\");\n while (components.length > 0) {\n let parent = components.join(\"-\");\n try {\n // Preflight the parent locale in case it\u2019s incomplete like `en-x`.\n new Intl.Locale(parent);\n if (!localeSet.has(parent)) locales.push(parent);\n localeSet.add(parent);\n } catch {}\n components.pop();\n // A Unicode extension like -u-nu must be followed by another subtag.\n if (components.at(-1)?.length === 2 && components.at(-2) === \"u\") {\n components.pop();\n }\n }\n }\n return locales;\n}\n\nconst defaultUnlocalizedNameProperty = \"name\";\n\n/**\n * Returns a `coalesce` expression that resolves to the feature's name in a\n * language that the user prefers.\n *\n * @param {[string]} locales - Locales of the name fields to include.\n * @param {boolean} options.includesLegacyFields - Whether to include the older fields\n * that include underscores, for layers that have not transitioned to the\n * colon syntax.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n */\nexport function getLocalizedNameExpression(locales, options = {}) {\n let nameFields = [\n ...locales.flatMap((l) => {\n let localizedNamePropertyFormat =\n options.localizedNamePropertyFormat || `name:$1`;\n let localizedNameProperty = localizedNamePropertyFormat.replaceAll(\n \"$1\",\n l,\n );\n let fields = [localizedNameProperty];\n // transportation_label uses an underscore instead of a colon.\n // https://github.com/openmaptiles/openmaptiles/issues/769\n if (options.includesLegacyFields && (l === \"de\" || l === \"en\")) {\n fields.push(localizedNameProperty.replaceAll(\":\", \"_\"));\n }\n return fields;\n }),\n options.unlocalizedNameProperty || defaultUnlocalizedNameProperty,\n ];\n return [\"coalesce\", ...nameFields.map((f) => [\"get\", f])];\n}\n\n/**\n * Mutates a `let` expression to have a new value for the variable by the given name, binding the variable if it isn\u2019t already bound to any value.\n *\n * @param {array} letExpr - Expression to update.\n * @param {string} variable - Name of the variable to set.\n * @param {*} value - The variable's new value.\n */\nexport function updateVariable(letExpr, variable, value) {\n if (!letExpr || letExpr[0] !== \"let\") return;\n\n let variableNameIndex = letExpr.indexOf(variable);\n if (variableNameIndex % 2 === 1) {\n letExpr[variableNameIndex + 1] = value;\n } else {\n letExpr.splice(-1, 0, variable, value);\n }\n}\n\nconst localizedNameVariable = `${variablePrefix}__localizedName`;\nconst localizedCollatorVariable = `${variablePrefix}__localizedCollator`;\nconst diacriticInsensitiveCollatorVariable = `${variablePrefix}__diacriticInsensitiveCollator`;\n\n/**\n * Recursively walks an expression, returning a copy of the subexpression after replacing any reference to a specific feature property with a new value in place.\n *\n * @param {array} expression - The expression to transform.\n * @param {string} propertyName - The name of the feature property to look for.\n * @param {*} replacement - The replacement value.\n * @returns {array} The same array as `expression` if `expression` referred to `propertyName`, or `undefined` if `expression` did not refer to `propertyName`.\n */\nexport function replacePropertyReferences(\n expression,\n propertyName,\n replacement,\n) {\n if (!Array.isArray(expression) || expression[0] === \"literal\") return;\n if (expression[0] === \"get\") {\n if (expression.length === 2 && expression[1] === propertyName) {\n return replacement;\n }\n return;\n }\n let didReplace = false;\n expression.forEach((arg, idx) => {\n if (!idx) return; // operator can never be a property reference\n let newValue = replacePropertyReferences(arg, propertyName, replacement);\n if (newValue !== undefined) {\n expression[idx] = newValue;\n didReplace = true;\n }\n });\n if (didReplace) return expression;\n}\n\n/**\n * The separator to use in inline contexts.\n */\nconst inlineSeparator = \" \\u2022 \";\n\n/**\n * Transforms a layer\u2019s `text-field` layout property so that it can be localized by `localizeLayers` later on.\n *\n * The transformed `text-field` property is only modified if it contains a reference to the feature property specified by `unlocalizedNameProperty`. If the layer\u2019s `symbol-placement` layout property is set to either `line` or `line-center`, the resulting text field takes up only one line. Otherwise, the text field for a given feature may span multiple lines if its unlocalized name property is set to a list of values.\n *\n * @param {object} layer - The style layer to prepare for localization.\n * @param {string} unlocalizedNameProperty - The name of the feature property that holds the unlocalized name. References to this property are replaced by a more complex expression that can be localized dynamically.\n * @param {boolean} glossLocalNames - Whether to format each label as a dual language label including a local name gloss.\n */\nexport function prepareLayer(layer, unlocalizedNameProperty, glossLocalNames) {\n let textField = layer.layout && layer.layout[\"text-field\"];\n if (\n !textField ||\n (textField[0] === \"let\" && textField.includes(localizedNameVariable))\n ) {\n return;\n }\n\n let symbolPlacement = layer.layout && layer.layout[\"symbol-placement\"];\n let isInline =\n symbolPlacement === \"line\" || symbolPlacement === \"line-center\";\n let listValues = glossLocalNames\n ? localizedNameWithLocalGlossCore\n : isInline\n ? localizedNameInlineCore\n : localizedNameCore;\n let newTextField = replacePropertyReferences(\n textField,\n unlocalizedNameProperty || defaultUnlocalizedNameProperty,\n listValues,\n );\n if (newTextField !== undefined) {\n layer.layout[\"text-field\"] = [\n \"let\",\n localizedNameVariable,\n \"\",\n newTextField,\n ];\n }\n}\n\n/**\n * Updates localizable variables at the top level of the layer's `text-field` expression based on the given locales.\n *\n * @param {object} layer - The style layer to localize.\n * @param {string} collationLocale - The locale for string comparison purposes.\n * @param {array} localizedNameExpression - An expression that produces a localized name.\n * @param {array} legacyLocalizedNameExpression - An expression that produces a localized name based on legacy properties in OpenMapTiles.\n */\nfunction localizeLayer(\n layer,\n collationLocale,\n localizedNameExpression,\n legacyLocalizedNameExpression,\n) {\n if (!(\"layout\" in layer) || !(\"text-field\" in layer.layout)) return;\n\n let textField = layer.layout[\"text-field\"];\n\n updateVariable(\n textField,\n localizedNameVariable,\n // https://github.com/openmaptiles/openmaptiles/issues/769\n layer[\"source-layer\"] === \"transportation_name\"\n ? legacyLocalizedNameExpression\n : localizedNameExpression,\n );\n\n updateVariable(textField, localizedCollatorVariable, [\n \"collator\",\n {\n \"case-sensitive\": false,\n \"diacritic-sensitive\": true,\n locale: collationLocale,\n },\n ]);\n\n // Only perform diacritic folding in English. English normally uses few diacritics except when labeling foreign place names on maps.\n updateVariable(textField, diacriticInsensitiveCollatorVariable, [\n \"collator\",\n {\n \"case-sensitive\": false,\n \"diacritic-sensitive\": !/^en\\b/.test(collationLocale),\n locale: collationLocale,\n },\n ]);\n}\n\n/**\n * Updates localizable variables at the top level of each layer's `text-field` expression based on the given locales.\n *\n * @param {[object]} layers - The style layers to localize.\n * @param {[string]} locales - The locales to insert into each layer.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n */\nexport function localizeLayers(layers, locales = getLocales(), options = {}) {\n let localizedNameExpression = getLocalizedNameExpression(locales, options);\n let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {\n ...options,\n includesLegacyFields: true,\n });\n for (let layer of layers) {\n localizeLayer(\n layer,\n locales[0],\n localizedNameExpression,\n legacyLocalizedNameExpression,\n );\n }\n}\n\n/**\n * Recursively scans a semicolon-delimited value list, replacing a finite number\n * of semicolons with a separator, starting from the given index.\n *\n * This expression nests recursively by the maximum number of replacements. Take\n * special care to minimize this limit, which exponentially increases the length\n * of a property value in JSON. Excessive nesting causes acute performance\n * problems when loading the style.\n *\n * The returned expression can be complex, so use it only once within a property\n * value. To reuse the evaluated value, bind it to a variable in a let\n * expression.\n *\n * @param list The overall string expression to search within.\n * @param separator A string to insert after the value, or an expression that\n * evaluates to this string.\n * @param listStart A zero-based index into the list at which the search begins.\n * @param numReplacements The maximum number of replacements remaining.\n */\nfunction listValueExpression(\n list,\n separator,\n valueToOmit,\n listStart,\n numReplacements,\n) {\n let asIs = [\"slice\", list, listStart];\n if (numReplacements <= 0) {\n return asIs;\n }\n\n let iteration = numReplacements;\n let rawSeparator = \";\";\n let needleStartVariable = `${variablePrefix}__needleStart${iteration}`;\n let needleEndVariable = `${variablePrefix}__needleEnd${iteration}`;\n let valueVariable = `${variablePrefix}__value${iteration}`;\n let lookaheadVariable = `${variablePrefix}__lookahead${iteration}`;\n let nextListStartVariable = `${variablePrefix}__nextListStart${iteration}`;\n return [\n \"let\",\n needleStartVariable,\n [\"index-of\", rawSeparator, list, listStart],\n [\n \"case\",\n [\">=\", [\"var\", needleStartVariable], 0],\n // Found a semicolon.\n [\n \"let\",\n valueVariable,\n [\"slice\", list, listStart, [\"var\", needleStartVariable]],\n needleEndVariable,\n [\"+\", [\"var\", needleStartVariable], rawSeparator.length],\n [\n \"concat\",\n // Start with everything before the semicolon unless it's the value to\n // omit.\n [\n \"case\",\n [\"==\", [\"var\", valueVariable], valueToOmit],\n \"\",\n [\"var\", valueVariable],\n ],\n [\n \"let\",\n lookaheadVariable,\n // Look ahead by one character.\n [\n \"slice\",\n list,\n [\"var\", needleEndVariable],\n [\"+\", [\"var\", needleEndVariable], rawSeparator.length],\n ],\n [\n \"let\",\n // Skip past the current value and semicolon for any subsequent\n // searches.\n nextListStartVariable,\n [\n \"+\",\n [\"var\", needleEndVariable],\n // Also skip past any escaped semicolon or space padding.\n [\n \"match\",\n [\"var\", lookaheadVariable],\n [rawSeparator, \" \"],\n rawSeparator.length,\n 0,\n ],\n ],\n [\n \"case\",\n // If the only remaining value is the value to omit, stop\n // scanning.\n [\n \"==\",\n [\"slice\", list, [\"var\", nextListStartVariable]],\n valueToOmit,\n ],\n \"\",\n [\n \"concat\",\n [\n \"case\",\n // If the lookahead character is another semicolon, append\n // an unescaped semicolon.\n [\"==\", [\"var\", lookaheadVariable], rawSeparator],\n rawSeparator,\n // Otherwise, if the value is the value to omit, do nothing.\n [\"==\", [\"var\", valueVariable], valueToOmit],\n \"\",\n // Otherwise, append the passed-in separator.\n separator,\n ],\n // Recurse for the next value in the value list.\n listValueExpression(\n list,\n separator,\n valueToOmit,\n [\"var\", nextListStartVariable],\n numReplacements - 1,\n ),\n ],\n ],\n ],\n ],\n ],\n ],\n // No semicolons left in the string, so stop looking and append the value as is.\n asIs,\n ],\n ];\n}\n\n/**\n * Maximum number of values in a semicolon-delimited list of values.\n *\n * Increasing this constant deepens recursion for replacing delimiters in the\n * list, potentially affecting style loading performance.\n */\nconst maxValueListLength = 3;\n\n/**\n * Returns an expression interpreting the given string as a list of tag values,\n * pretty-printing the standard semicolon delimiter with the given separator.\n *\n * https://wiki.openstreetmap.org/wiki/Semi-colon_value_separator\n *\n * The returned expression can be complex, so use it only once within a property\n * value. To reuse the evaluated value, bind it to a variable in a let\n * expression.\n *\n * @param valueList A semicolon-delimited list of values.\n * @param separator A string to insert between each value, or an expression that\n * evaluates to this string.\n */\nexport function listValuesExpression(valueList, separator, valueToOmit) {\n let maxSeparators = maxValueListLength - 1;\n let valueListVariable = `${variablePrefix}__valueList`;\n let valueToOmitVariable = `${variablePrefix}__valueToOmit`;\n return [\n \"let\",\n valueListVariable,\n valueList,\n valueToOmitVariable,\n valueToOmit || \";\",\n listValueExpression(\n [\"var\", valueListVariable],\n separator,\n [\"var\", valueToOmitVariable],\n 0,\n maxSeparators,\n ),\n ];\n}\n\nconst localizedNameCore = listValuesExpression(\n [\"var\", localizedNameVariable],\n \"\\n\",\n);\n\n/**\n * The names in the user's preferred language, each on a separate line.\n */\nexport const localizedName = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedNameCore,\n];\n\nconst localizedNameInlineCore = listValuesExpression(\n [\"var\", localizedNameVariable],\n inlineSeparator,\n);\n\n/**\n * The names in the user's preferred language, all on the same line.\n */\nexport const localizedNameInline = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedNameInlineCore,\n];\n\n/**\n * Returns an expression that tests whether the target has the given prefix,\n * respecting word boundaries.\n */\nfunction startsWithExpression(target, candidatePrefix, collator) {\n // \"Quebec City\" vs. \"Qu\u00E9bec\", \"Washington, D.C.\" vs. \"Washington\"\n let wordBoundaries = \" ,\";\n return [\n \"all\",\n [\n \"==\",\n [\"slice\", target, 0, [\"length\", candidatePrefix]],\n candidatePrefix,\n collator,\n ],\n [\n \"in\",\n [\n \"slice\",\n // Pad the target in case the prefix matches exactly.\n // \"Montreal \" vs. \"Montr\u00E9al\"\n [\"concat\", target, wordBoundaries[0]],\n [\"length\", candidatePrefix],\n [\"+\", [\"length\", candidatePrefix], 1],\n ],\n wordBoundaries,\n ],\n ];\n}\n\nfunction overwritePrefixExpression(target, newPrefix) {\n return [\"concat\", newPrefix, [\"slice\", target, [\"length\", newPrefix]]];\n}\n\n/**\n * Returns an expression that tests whether the target has the given suffix,\n * respecting word boundaries.\n */\nfunction endsWithExpression(target, candidateSuffix, collator) {\n let wordBoundary = \" \";\n let suffixStartVariable = `${variablePrefix}__suffixStart`;\n return [\n \"let\",\n suffixStartVariable,\n [\"-\", [\"length\", target], [\"length\", candidateSuffix]],\n [\n \"all\",\n [\n \"==\",\n [\"slice\", target, [\"var\", suffixStartVariable]],\n candidateSuffix,\n collator,\n ],\n [\n \"==\",\n [\n \"slice\",\n target,\n [\"-\", [\"var\", suffixStartVariable], 1],\n [\"var\", suffixStartVariable],\n ],\n wordBoundary,\n ],\n ],\n ];\n}\n\nfunction overwriteSuffixExpression(target, newSuffix) {\n return [\n \"concat\",\n [\"slice\", target, 0, [\"-\", [\"length\", target], [\"length\", newSuffix]]],\n newSuffix,\n ];\n}\n\nconst localizedNameListVariable = `${variablePrefix}__localizedNameList`;\nconst nameListVariable = `${variablePrefix}__nameList`;\n\nconst localizedNameWithLocalGlossCore = [\n \"let\",\n localizedNameListVariable,\n listValuesExpression([\"var\", localizedNameVariable], \"\\n\"),\n [\n \"case\",\n // If the name in the preferred and local languages match exactly...\n [\n \"==\",\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", localizedCollatorVariable],\n ],\n // ...just pick one.\n [\"format\", [\"var\", localizedNameListVariable]],\n [\n \"let\",\n nameListVariable,\n listValuesExpression([\"get\", \"name\"], \"\\n\"),\n [\n \"case\",\n // If the name in the preferred language is the same as the name in the\n // local language except for the omission of diacritics and/or the addition\n // of a suffix (e.g., \"City\" in English)...\n startsWithExpression(\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", diacriticInsensitiveCollatorVariable],\n ),\n // ...then replace the common prefix with the local name.\n [\n \"format\",\n overwritePrefixExpression(\n [\"var\", localizedNameVariable],\n [\"var\", nameListVariable],\n ),\n ],\n // If the name in the preferred language is the same as the name in the\n // local language except for the omission of diacritics and/or the addition\n // of a prefix (e.g., \"City of\" in English or \"Ciudad de\" in Spanish)...\n endsWithExpression(\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", diacriticInsensitiveCollatorVariable],\n ),\n // ...then replace the common suffix with the local name.\n [\n \"format\",\n overwriteSuffixExpression(\n [\"var\", localizedNameVariable],\n [\"var\", nameListVariable],\n ),\n ],\n // Otherwise, gloss the name in the local language if it differs from the\n // localized name.\n [\n \"format\",\n [\"var\", localizedNameListVariable],\n \"\\n\",\n \"(\\u2068\",\n { \"font-scale\": 0.8 },\n listValuesExpression([\"get\", \"name\"], inlineSeparator, [\n \"var\",\n localizedNameVariable,\n ]),\n { \"font-scale\": 0.8 },\n \"\\u2069)\",\n { \"font-scale\": 0.8 },\n ],\n ],\n ],\n ],\n];\n\n/**\n * The name in the user's preferred language, followed by the name in the local\n * language in parentheses if it differs.\n */\nexport const localizedNameWithLocalGloss = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedCollatorVariable,\n [\"collator\", {}],\n diacriticInsensitiveCollatorVariable,\n [\"collator\", {}],\n localizedNameWithLocalGlossCore,\n];\n\n/**\n * ISO 3166-1 alpha-2 country codes by ISO 3166-1 alpha-3 code.\n *\n * Source: https://www.cia.gov/the-world-factbook/references/country-data-codes/\n */\nconst iso3166_1_alpha_2_by_3 = {\n ABW: \"AW\",\n AFG: \"AF\",\n AGO: \"AO\",\n AIA: \"AI\",\n ALB: \"AL\",\n AND: \"AD\",\n ARE: \"AE\",\n ARG: \"AR\",\n ARM: \"AM\",\n ASM: \"AS\",\n ATA: \"AQ\",\n ATF: \"TF\",\n ATG: \"AG\",\n AUS: \"AU\",\n AUT: \"AT\",\n AZE: \"AZ\",\n BDI: \"BI\",\n BEL: \"BE\",\n BEN: \"BJ\",\n BFA: \"BF\",\n BGD: \"BD\",\n BGR: \"BG\",\n BHR: \"BH\",\n BHS: \"BS\",\n BIH: \"BA\",\n BLM: \"BL\",\n BLR: \"BY\",\n BLZ: \"BZ\",\n BMU: \"BM\",\n BOL: \"BO\",\n BRA: \"BR\",\n BRB: \"BB\",\n BRN: \"BN\",\n BTN: \"BT\",\n BVT: \"BV\",\n BWA: \"BW\",\n CAF: \"CF\",\n CAN: \"CA\",\n CCK: \"CC\",\n CHE: \"CH\",\n CHL: \"CL\",\n CHN: \"CN\",\n CIV: \"CI\",\n CMR: \"CM\",\n COD: \"CD\",\n COG: \"CG\",\n COK: \"CK\",\n COL: \"CO\",\n COM: \"KM\",\n CPV: \"CV\",\n CRI: \"CR\",\n CUB: \"CU\",\n CUW: \"CW\",\n CXR: \"CX\",\n CYM: \"KY\",\n CYP: \"CY\",\n CZE: \"CZ\",\n DEU: \"DE\",\n DJI: \"DJ\",\n DMA: \"DM\",\n DNK: \"DK\",\n DOM: \"DO\",\n DZA: \"DZ\",\n ECU: \"EC\",\n EGY: \"EG\",\n ERI: \"ER\",\n ESH: \"EH\",\n ESP: \"ES\",\n EST: \"EE\",\n ETH: \"ET\",\n FIN: \"FI\",\n FJI: \"FJ\",\n FLK: \"FK\",\n FRA: \"FR\",\n FRO: \"FO\",\n FSM: \"FM\",\n FXX: \"FX\",\n GAB: \"GA\",\n GBR: \"GB\",\n GEO: \"GE\",\n GGY: \"GG\",\n GHA: \"GH\",\n GIB: \"GI\",\n GIN: \"GN\",\n GLP: \"GP\",\n GMB: \"GM\",\n GNB: \"GW\",\n GNQ: \"GQ\",\n GRC: \"GR\",\n GRD: \"GD\",\n GRL: \"GL\",\n GTM: \"GT\",\n GUF: \"GF\",\n GUM: \"GU\",\n GUY: \"GY\",\n HKG: \"HK\",\n HMD: \"HM\",\n HND: \"HN\",\n HRV: \"HR\",\n HTI: \"HT\",\n HUN: \"HU\",\n IDN: \"ID\",\n IMN: \"IM\",\n IND: \"IN\",\n IOT: \"IO\",\n IRL: \"IE\",\n IRN: \"IR\",\n IRQ: \"IQ\",\n ISL: \"IS\",\n ISR: \"IL\",\n ITA: \"IT\",\n JAM: \"JM\",\n JEY: \"JE\",\n JOR: \"JO\",\n JPN: \"JP\",\n KAZ: \"KZ\",\n KEN: \"KE\",\n KGZ: \"KG\",\n KHM: \"KH\",\n KIR: \"KI\",\n KNA: \"KN\",\n KOR: \"KR\",\n KWT: \"KW\",\n LAO: \"LA\",\n LBN: \"LB\",\n LBR: \"LR\",\n LBY: \"LY\",\n LCA: \"LC\",\n LIE: \"LI\",\n LKA: \"LK\",\n LSO: \"LS\",\n LTU: \"LT\",\n LUX: \"LU\",\n LVA: \"LV\",\n MAC: \"MO\",\n MAF: \"MF\",\n MAR: \"MA\",\n MCO: \"MC\",\n MDA: \"MD\",\n MDG: \"MG\",\n MDV: \"MV\",\n MEX: \"MX\",\n MHL: \"MH\",\n MKD: \"MK\",\n MLI: \"ML\",\n MLT: \"MT\",\n MMR: \"MM\",\n MNE: \"ME\",\n MNG: \"MN\",\n MNP: \"MP\",\n MOZ: \"MZ\",\n MRT: \"MR\",\n MSR: \"MS\",\n MTQ: \"MQ\",\n MUS: \"MU\",\n MWI: \"MW\",\n MYS: \"MY\",\n MYT: \"YT\",\n NAM: \"NA\",\n NCL: \"NC\",\n NER: \"NE\",\n NFK: \"NF\",\n NGA: \"NG\",\n NIC: \"NI\",\n NIU: \"NU\",\n NLD: \"NL\",\n NOR: \"NO\",\n NPL: \"NP\",\n NRU: \"NR\",\n NZL: \"NZ\",\n OMN: \"OM\",\n PAK: \"PK\",\n PAN: \"PA\",\n PCN: \"PN\",\n PER: \"PE\",\n PHL: \"PH\",\n PLW: \"PW\",\n PNG: \"PG\",\n POL: \"PL\",\n PRI: \"PR\",\n PRK: \"KP\",\n PRT: \"PT\",\n PRY: \"PY\",\n PSE: \"PS\",\n PYF: \"PF\",\n QAT: \"QA\",\n REU: \"RE\",\n ROU: \"RO\",\n RUS: \"RU\",\n RWA: \"RW\",\n SAU: \"SA\",\n SDN: \"SD\",\n SEN: \"SN\",\n SGP: \"SG\",\n SGS: \"GS\",\n SHN: \"SH\",\n SJM: \"SJ\",\n SLB: \"SB\",\n SLE: \"SL\",\n SLV: \"SV\",\n SMR: \"SM\",\n SOM: \"SO\",\n SPM: \"PM\",\n SRB: \"RS\",\n SSD: \"SS\",\n STP: \"ST\",\n SUR: \"SR\",\n SVK: \"SK\",\n SVN: \"SI\",\n SWE: \"SE\",\n SWZ: \"SZ\",\n SXM: \"SX\",\n SYC: \"SC\",\n SYR: \"SY\",\n TCA: \"TC\",\n TCD: \"TD\",\n TGO: \"TG\",\n THA: \"TH\",\n TJK: \"TJ\",\n TKL: \"TK\",\n TKM: \"TM\",\n TLS: \"TL\",\n TON: \"TO\",\n TTO: \"TT\",\n TUN: \"TN\",\n TUR: \"TR\",\n TUV: \"TV\",\n TWN: \"TW\",\n TZA: \"TZ\",\n UGA: \"UG\",\n UKR: \"UA\",\n UMI: \"UM\",\n URY: \"UY\",\n USA: \"US\",\n UZB: \"UZ\",\n VAT: \"VA\",\n VCT: \"VC\",\n VEN: \"VE\",\n VGB: \"VG\",\n VIR: \"VI\",\n VNM: \"VN\",\n VUT: \"VU\",\n WLF: \"WF\",\n WSM: \"WS\",\n YEM: \"YE\",\n ZAF: \"ZA\",\n ZMB: \"ZM\",\n ZWE: \"ZW\",\n};\n\nconst countryNamesByCodeVariable = `${variablePrefix}__countryNamesByCode`;\n\n/**\n * Returns a table of country names in the user\u2019s preferred language by ISO 3166-1 alpha-3 code.\n *\n * @param {[string]} locales - The locales for formatting the country names.\n * @param {boolean} options.uppercase Whether to write the country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function getLocalizedCountryNames(locales, options = {}) {\n let countryNames = new Intl.DisplayNames(locales, {\n type: \"region\",\n fallback: \"none\",\n });\n return Object.fromEntries(\n Object.entries(iso3166_1_alpha_2_by_3).map((e) => {\n let name = countryNames.of(e[1]);\n if (name && options?.uppercase) {\n // Neither the upcase expression operator nor the text-transform layout property is locale-aware, so uppercase the name upfront.\n name = name\n .toLocaleUpperCase(locales)\n // Word boundaries are less discernible in uppercase text, so pad each word by an additional space.\n .replaceAll(\" \", \" \");\n }\n return [e[0], name];\n }),\n );\n}\n\n/**\n * Returns the global state that Diplomat needs to fully localize the style.\n *\n * @param {[string]} locales - The locales for formatting the country names.\n * @param {boolean} options.uppercaseCountryNames Whether to write country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function getGlobalStateForLocalization(locales, options = {}) {\n let state = {};\n state[countryNamesByCodeVariable] = getLocalizedCountryNames(locales, {\n uppercase: options?.uppercaseCountryNames,\n });\n return state;\n}\n\n/**\n * Returns an expression that converts the given country code to a human-readable name in the user's preferred language.\n *\n * @param {array} code An expression that evaluates to an ISO 3166-1 alpha-3 country code.\n */\nexport function getLocalizedCountryNameExpression(code) {\n return [\n \"let\",\n \"code\",\n code,\n [\n \"coalesce\",\n [\n \"get\",\n [\"var\", \"code\"],\n [\n \"coalesce\",\n [\"global-state\", countryNamesByCodeVariable],\n [\"literal\", {}],\n ],\n ],\n // Fall back to the country code in parentheses.\n [\"concat\", \"(\", [\"var\", \"code\"], \")\"],\n ],\n ];\n}\n\n/**\n * Updates each style layer's `text-field` value to match the given locales, upgrading any unlocalizable layer along the way.\n *\n * This method ugprades unlocalizable layers to localized multiline or inline labels depending on the `symbol-placement` layout property. To add a dual language label to a layer, set its `text-field` layout property manually using the `localizedNameWithLocalGloss` constant.\n *\n * If neither `options.layers` nor `options.sourceLayers` is specified, this function makes localizable any style layer that gets the feature property specified in `options.unlocalizedNameProperty`, or `name` by default.\n *\n * @param {maplibregl.Map} map - The map to localize.\n * @param {[string]} locales - The locales to insert into each layer.\n * @param {[string]} options.layers - The style layers with these IDs will be made localizable.\n * @param {[string]} options.sourceLayers - The style layers that use these source layers will be made localizable. These are source layer IDs, not style layer IDs.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n * @param {boolean} options.glossLocalNames - Whether to format each label as a dual language label including a local name gloss.\n * @param {boolean} options.uppercaseCountryNames Whether to write country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function localizeStyle(map, locales = getLocales(), options = {}) {\n let style = map.getStyle();\n\n let localizedNameExpression = getLocalizedNameExpression(locales, options);\n let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {\n ...options,\n includesLegacyFields: true,\n });\n\n for (let layer of style.layers) {\n let sourceLayer = layer[\"source-layer\"];\n if (\n (!options.layers && !options.sourceLayers) ||\n options.layers?.includes(layer.id) ||\n (sourceLayer && options.sourceLayers?.includes(sourceLayer))\n ) {\n prepareLayer(\n layer,\n options?.unlocalizedNameProperty,\n options?.glossLocalNames,\n );\n }\n localizeLayer(\n layer,\n locales[0],\n localizedNameExpression,\n legacyLocalizedNameExpression,\n );\n }\n\n let countryNames = getLocalizedCountryNames(locales, {\n uppercase: options?.uppercaseCountryNames,\n });\n map.setGlobalStateProperty(countryNamesByCodeVariable, countryNames);\n\n map.setStyle(style);\n}\n\nif (typeof window !== \"undefined\") {\n window.Diplomat = {\n getGlobalStateForLocalization,\n getLanguageFromURL,\n getLocales,\n getLocalizedCountryNameExpression,\n listValuesExpression,\n localizeLayers,\n localizeStyle,\n localizedName,\n localizedNameInline,\n localizedNameWithLocalGloss,\n };\n if (\"maplibregl\" in window) {\n maplibregl.Diplomat = window.Diplomat;\n\n maplibregl.Map.prototype.localizeStyle = function (\n locales = getLocales(),\n options = {},\n ) {\n localizeStyle(this, locales, options);\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "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ACD,CAAE,aAAc,EAAI,EACpB,UACA,CAAE,aAAc,EAAI,CACtB,CACF,CACF,CACF,CACF,EAMaiE,EAA8B,CACzC,MACAjE,EACA,GACAC,EACA,CAAC,WAAY,CAAC,CAAC,EACfC,EACA,CAAC,WAAY,CAAC,CAAC,EACfiB,CACF,EAOM+C,EAAyB,CAC7B,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACP,EAEMC,EAA6B,GAAGzF,CAAc,uBAQ7C,SAAS0F,EAAyBpF,EAASO,EAAU,CAAC,EAAG,CAC9D,IAAI8E,EAAe,IAAI,KAAK,aAAarF,EAAS,CAChD,KAAM,SACN,SAAU,MACZ,CAAC,EACD,OAAO,OAAO,YACZ,OAAO,QAAQkF,CAAsB,EAAE,IAAKI,GAAM,CAChD,IAAIC,EAAOF,EAAa,GAAGC,EAAE,CAAC,CAAC,EAC/B,OAAIC,GAAQhF,GAAS,YAEnBgF,EAAOA,EACJ,kBAAkBvF,CAAO,EAEzB,WAAW,IAAK,IAAI,GAElB,CAACsF,EAAE,CAAC,EAAGC,CAAI,CACpB,CAAC,CACH,CACF,CAQO,SAASC,EAA8BxF,EAASO,EAAU,CAAC,EAAG,CACnE,IAAIkF,EAAQ,CAAC,EACb,OAAAA,EAAMN,CAA0B,EAAIC,EAAyBpF,EAAS,CACpE,UAAWO,GAAS,qBACtB,CAAC,EACMkF,CACT,CAOO,SAASC,EAAkCC,EAAM,CACtD,MAAO,CACL,MACA,OACAA,EACA,CACE,WACA,CACE,MACA,CAAC,MAAO,MAAM,EACd,CACE,WACA,CAAC,eAAgBR,CAA0B,EAC3C,CAAC,UAAW,CAAC,CAAC,CAChB,CACF,EAEA,CAAC,SAAU,IAAK,CAAC,MAAO,MAAM,EAAG,GAAG,CACtC,CACF,CACF,CAkBO,SAASS,EAAcC,EAAK7F,EAAUF,EAAW,EAAGS,EAAU,CAAC,EAAG,CACvE,IAAIuF,EAAQD,EAAI,SAAS,EAErBrD,EAA0BlC,EAA2BN,EAASO,CAAO,EACrEkC,EAAgCnC,EAA2BN,EAAS,CACtE,GAAGO,EACH,qBAAsB,EACxB,CAAC,EAED,QAASsB,KAASiE,EAAM,OAAQ,CAC9B,IAAIC,EAAclE,EAAM,cAAc,GAEnC,CAACtB,EAAQ,QAAU,CAACA,EAAQ,cAC7BA,EAAQ,QAAQ,SAASsB,EAAM,EAAE,GAChCkE,GAAexF,EAAQ,cAAc,SAASwF,CAAW,IAE1DnE,EACEC,EACAtB,GAAS,wBACTA,GAAS,eACX,EAEF+B,EACET,EACA7B,EAAQ,CAAC,EACTwC,EACAC,CACF,CACF,CAEA,IAAI4C,EAAeD,EAAyBpF,EAAS,CACnD,UAAWO,GAAS,qBACtB,CAAC,EACDsF,EAAI,uBAAuBV,EAA4BE,CAAY,EAEnEQ,EAAI,SAASC,CAAK,CACpB,CAEI,OAAO,OAAW,MACpB,OAAO,SAAW,CAChB,8BAAAN,EACA,mBAAA7F,EACA,WAAAG,EACA,kCAAA4F,EACA,qBAAA/B,EACA,eAAAjB,EACA,cAAAkD,EACA,cAAA5B,EACA,oBAAAC,EACA,4BAAAgB,CACF,EACI,eAAgB,SAClB,WAAW,SAAW,OAAO,SAE7B,WAAW,IAAI,UAAU,cAAgB,SACvCjF,EAAUF,EAAW,EACrBS,EAAU,CAAC,EACX,CACAqF,EAAc,KAAM5F,EAASO,CAAO,CACtC",
|
|
6
|
-
"names": ["variablePrefix", "getLanguageFromURL", "url", "language", "
|
|
4
|
+
"sourcesContent": ["/// A prefix that uniquely identifies this plugin, prepended onto the name of any variable generated by this plugin.\nconst variablePrefix = \"diplomat\";\n\n/**\n * Returns a list of languages as a comma-delimited string from the given URL hash.\n */\nexport function getLanguageFromURL(url) {\n let language = new URLSearchParams(url.hash.substr(1)).get(\"language\");\n return language === \"\" ? null : language;\n}\n\n/**\n Returns the powerset of the given array.\n */\nfunction powerset(array) {\n return array.reduce(\n (accum, value) => [...accum, ...accum.map((pick) => [...pick, value])],\n [[]],\n );\n}\n\n/**\n Compatibility shim for `Intl.Locale.prototype.variants`.\n */\nfunction getVariants(locale) {\n return locale.variants ?? locale.minimize().baseName.match(/-([-\\w]+)/)?.[1];\n}\n\n/**\n Returns an array of the language tags related to the given language tag, sorted from most specific to least specific.\n \n @param {string} tag - The language tag that the returned language tags are related to.\n @returns {[string]} A sorted array of related language tags, or an empty array if `tag` is malformed.\n */\nexport function getRelatedLanguageTags(tag) {\n let locale;\n try {\n locale = new Intl.Locale(tag);\n } catch {\n return [];\n }\n\n let maximized = locale.maximize();\n // The subtags and extensions used in OSM name:*=* subkeys.\n let quals = [\n maximized.script,\n maximized.region,\n getVariants(maximized),\n maximized.numberingSystem,\n ].filter((q) => q);\n // Get all the combinations of components and convert them to language tags.\n let tags = powerset(quals).map((quals) =>\n [maximized.language, ...quals].join(\"-\"),\n );\n\n // Add the original language tag, in case maximizing it dropped miscellaneous extensions.\n tags.push(locale + \"\");\n tags.push(locale.baseName);\n\n // Validate each of the language tags.\n let locales = tags\n .map((tag) => {\n try {\n return new Intl.Locale(tag);\n } catch {}\n })\n .filter((l) => l);\n\n // Sort the locales from most specific to least specific.\n let scoreLocale = (locale) => {\n let tag = locale + \"\";\n let score = 0;\n score += tag.length ?? 0;\n score += tag.split(\"-\").length ?? 0;\n // Prioritize variants, which are more specific than script and region.\n score += getVariants(locale)?.length ?? 0;\n // Prioritize extensions, which Intl.Locale.prototype.maximize can\u2019t maximize.\n score += tag.match(/(?:-[tx]-|-u-\\w\\w-)\\w+/)?.[0]?.length ?? 0;\n return score;\n };\n locales.sort((a, b) => scoreLocale(b) - scoreLocale(a));\n\n let validTags = locales.map((l) => l + \"\");\n return [...new Set(validTags)];\n}\n\n/**\n * Returns the languages that the user prefers.\n */\nexport function getLocales() {\n // Check the language \"parameter\" in the hash.\n let parameter = getLanguageFromURL(window.location)?.split(\",\");\n // Fall back to the user's language preference.\n let userLocales = parameter ?? navigator.languages ?? [navigator.language];\n // Get a full fallback list.\n let tags = userLocales.flatMap((l) => getRelatedLanguageTags(l));\n\n return [...new Set(tags)];\n}\n\nconst defaultUnlocalizedNameProperty = \"name\";\n\n/**\n * Returns a `coalesce` expression that resolves to the feature's name in a\n * language that the user prefers.\n *\n * @param {[string]} locales - Locales of the name fields to include.\n * @param {boolean} options.includesLegacyFields - Whether to include the older fields\n * that include underscores, for layers that have not transitioned to the\n * colon syntax.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n */\nexport function getLocalizedNameExpression(locales, options = {}) {\n let nameFields = [\n ...locales.flatMap((l) => {\n let localizedNamePropertyFormat =\n options.localizedNamePropertyFormat || `name:$1`;\n let localizedNameProperty = localizedNamePropertyFormat.replaceAll(\n \"$1\",\n l,\n );\n let fields = [localizedNameProperty];\n // transportation_label uses an underscore instead of a colon.\n // https://github.com/openmaptiles/openmaptiles/issues/769\n if (options.includesLegacyFields && (l === \"de\" || l === \"en\")) {\n fields.push(localizedNameProperty.replaceAll(\":\", \"_\"));\n }\n return fields;\n }),\n options.unlocalizedNameProperty || defaultUnlocalizedNameProperty,\n ];\n return [\"coalesce\", ...nameFields.map((f) => [\"get\", f])];\n}\n\n/**\n * Mutates a `let` expression to have a new value for the variable by the given name, binding the variable if it isn\u2019t already bound to any value.\n *\n * @param {array} letExpr - Expression to update.\n * @param {string} variable - Name of the variable to set.\n * @param {*} value - The variable's new value.\n */\nexport function updateVariable(letExpr, variable, value) {\n if (!letExpr || letExpr[0] !== \"let\") return;\n\n let variableNameIndex = letExpr.indexOf(variable);\n if (variableNameIndex % 2 === 1) {\n letExpr[variableNameIndex + 1] = value;\n } else {\n letExpr.splice(-1, 0, variable, value);\n }\n}\n\nconst localizedNameVariable = `${variablePrefix}__localizedName`;\nconst localizedCollatorVariable = `${variablePrefix}__localizedCollator`;\nconst diacriticInsensitiveCollatorVariable = `${variablePrefix}__diacriticInsensitiveCollator`;\n\n/**\n * Recursively walks an expression, returning a copy of the subexpression after replacing any reference to a specific feature property with a new value in place.\n *\n * @param {array} expression - The expression to transform.\n * @param {string} propertyName - The name of the feature property to look for.\n * @param {*} replacement - The replacement value.\n * @returns {array} The same array as `expression` if `expression` referred to `propertyName`, or `undefined` if `expression` did not refer to `propertyName`.\n */\nexport function replacePropertyReferences(\n expression,\n propertyName,\n replacement,\n) {\n if (!Array.isArray(expression) || expression[0] === \"literal\") return;\n if (expression[0] === \"get\") {\n if (expression.length === 2 && expression[1] === propertyName) {\n return replacement;\n }\n return;\n }\n let didReplace = false;\n expression.forEach((arg, idx) => {\n if (!idx) return; // operator can never be a property reference\n let newValue = replacePropertyReferences(arg, propertyName, replacement);\n if (newValue !== undefined) {\n expression[idx] = newValue;\n didReplace = true;\n }\n });\n if (didReplace) return expression;\n}\n\n/**\n * The separator to use in inline contexts.\n */\nconst inlineSeparator = \" \\u2022 \";\n\n/**\n * Transforms a layer\u2019s `text-field` layout property so that it can be localized by `localizeLayers` later on.\n *\n * The transformed `text-field` property is only modified if it contains a reference to the feature property specified by `unlocalizedNameProperty`. If the layer\u2019s `symbol-placement` layout property is set to either `line` or `line-center`, the resulting text field takes up only one line. Otherwise, the text field for a given feature may span multiple lines if its unlocalized name property is set to a list of values.\n *\n * @param {object} layer - The style layer to prepare for localization.\n * @param {string} unlocalizedNameProperty - The name of the feature property that holds the unlocalized name. References to this property are replaced by a more complex expression that can be localized dynamically.\n * @param {boolean} glossLocalNames - Whether to format each label as a dual language label including a local name gloss.\n */\nexport function prepareLayer(layer, unlocalizedNameProperty, glossLocalNames) {\n let textField = layer.layout && layer.layout[\"text-field\"];\n if (\n !textField ||\n (textField[0] === \"let\" && textField.includes(localizedNameVariable))\n ) {\n return;\n }\n\n let symbolPlacement = layer.layout && layer.layout[\"symbol-placement\"];\n let isInline =\n symbolPlacement === \"line\" || symbolPlacement === \"line-center\";\n let listValues = glossLocalNames\n ? localizedNameWithLocalGlossCore\n : isInline\n ? localizedNameInlineCore\n : localizedNameCore;\n let newTextField = replacePropertyReferences(\n textField,\n unlocalizedNameProperty || defaultUnlocalizedNameProperty,\n listValues,\n );\n if (newTextField !== undefined) {\n layer.layout[\"text-field\"] = [\n \"let\",\n localizedNameVariable,\n \"\",\n newTextField,\n ];\n }\n}\n\n/**\n * Updates localizable variables at the top level of the layer's `text-field` expression based on the given locales.\n *\n * @param {object} layer - The style layer to localize.\n * @param {string} collationLocale - The locale for string comparison purposes.\n * @param {array} localizedNameExpression - An expression that produces a localized name.\n * @param {array} legacyLocalizedNameExpression - An expression that produces a localized name based on legacy properties in OpenMapTiles.\n */\nfunction localizeLayer(\n layer,\n collationLocale,\n localizedNameExpression,\n legacyLocalizedNameExpression,\n) {\n if (!(\"layout\" in layer) || !(\"text-field\" in layer.layout)) return;\n\n let textField = layer.layout[\"text-field\"];\n\n updateVariable(\n textField,\n localizedNameVariable,\n // https://github.com/openmaptiles/openmaptiles/issues/769\n layer[\"source-layer\"] === \"transportation_name\"\n ? legacyLocalizedNameExpression\n : localizedNameExpression,\n );\n\n updateVariable(textField, localizedCollatorVariable, [\n \"collator\",\n {\n \"case-sensitive\": false,\n \"diacritic-sensitive\": true,\n locale: collationLocale,\n },\n ]);\n\n // Only perform diacritic folding in English. English normally uses few diacritics except when labeling foreign place names on maps.\n updateVariable(textField, diacriticInsensitiveCollatorVariable, [\n \"collator\",\n {\n \"case-sensitive\": false,\n \"diacritic-sensitive\": !/^en\\b/.test(collationLocale),\n locale: collationLocale,\n },\n ]);\n}\n\n/**\n * Updates localizable variables at the top level of each layer's `text-field` expression based on the given locales.\n *\n * @param {[object]} layers - The style layers to localize.\n * @param {[string]} locales - The locales to insert into each layer.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n */\nexport function localizeLayers(layers, locales = getLocales(), options = {}) {\n let localizedNameExpression = getLocalizedNameExpression(locales, options);\n let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {\n ...options,\n includesLegacyFields: true,\n });\n for (let layer of layers) {\n localizeLayer(\n layer,\n locales[0],\n localizedNameExpression,\n legacyLocalizedNameExpression,\n );\n }\n}\n\n/**\n * Recursively scans a semicolon-delimited value list, replacing a finite number\n * of semicolons with a separator, starting from the given index.\n *\n * This expression nests recursively by the maximum number of replacements. Take\n * special care to minimize this limit, which exponentially increases the length\n * of a property value in JSON. Excessive nesting causes acute performance\n * problems when loading the style.\n *\n * The returned expression can be complex, so use it only once within a property\n * value. To reuse the evaluated value, bind it to a variable in a let\n * expression.\n *\n * @param list The overall string expression to search within.\n * @param separator A string to insert after the value, or an expression that\n * evaluates to this string.\n * @param listStart A zero-based index into the list at which the search begins.\n * @param numReplacements The maximum number of replacements remaining.\n */\nfunction listValueExpression(\n list,\n separator,\n valueToOmit,\n listStart,\n numReplacements,\n) {\n let asIs = [\"slice\", list, listStart];\n if (numReplacements <= 0) {\n return asIs;\n }\n\n let iteration = numReplacements;\n let rawSeparator = \";\";\n let needleStartVariable = `${variablePrefix}__needleStart${iteration}`;\n let needleEndVariable = `${variablePrefix}__needleEnd${iteration}`;\n let valueVariable = `${variablePrefix}__value${iteration}`;\n let lookaheadVariable = `${variablePrefix}__lookahead${iteration}`;\n let nextListStartVariable = `${variablePrefix}__nextListStart${iteration}`;\n return [\n \"let\",\n needleStartVariable,\n [\"index-of\", rawSeparator, list, listStart],\n [\n \"case\",\n [\">=\", [\"var\", needleStartVariable], 0],\n // Found a semicolon.\n [\n \"let\",\n valueVariable,\n [\"slice\", list, listStart, [\"var\", needleStartVariable]],\n needleEndVariable,\n [\"+\", [\"var\", needleStartVariable], rawSeparator.length],\n [\n \"concat\",\n // Start with everything before the semicolon unless it's the value to\n // omit.\n [\n \"case\",\n [\"==\", [\"var\", valueVariable], valueToOmit],\n \"\",\n [\"var\", valueVariable],\n ],\n [\n \"let\",\n lookaheadVariable,\n // Look ahead by one character.\n [\n \"slice\",\n list,\n [\"var\", needleEndVariable],\n [\"+\", [\"var\", needleEndVariable], rawSeparator.length],\n ],\n [\n \"let\",\n // Skip past the current value and semicolon for any subsequent\n // searches.\n nextListStartVariable,\n [\n \"+\",\n [\"var\", needleEndVariable],\n // Also skip past any escaped semicolon or space padding.\n [\n \"match\",\n [\"var\", lookaheadVariable],\n [rawSeparator, \" \"],\n rawSeparator.length,\n 0,\n ],\n ],\n [\n \"case\",\n // If the only remaining value is the value to omit, stop\n // scanning.\n [\n \"==\",\n [\"slice\", list, [\"var\", nextListStartVariable]],\n valueToOmit,\n ],\n \"\",\n [\n \"concat\",\n [\n \"case\",\n // If the lookahead character is another semicolon, append\n // an unescaped semicolon.\n [\"==\", [\"var\", lookaheadVariable], rawSeparator],\n rawSeparator,\n // Otherwise, if the value is the value to omit, do nothing.\n [\"==\", [\"var\", valueVariable], valueToOmit],\n \"\",\n // Otherwise, append the passed-in separator.\n separator,\n ],\n // Recurse for the next value in the value list.\n listValueExpression(\n list,\n separator,\n valueToOmit,\n [\"var\", nextListStartVariable],\n numReplacements - 1,\n ),\n ],\n ],\n ],\n ],\n ],\n ],\n // No semicolons left in the string, so stop looking and append the value as is.\n asIs,\n ],\n ];\n}\n\n/**\n * Maximum number of values in a semicolon-delimited list of values.\n *\n * Increasing this constant deepens recursion for replacing delimiters in the\n * list, potentially affecting style loading performance.\n */\nconst maxValueListLength = 3;\n\n/**\n * Returns an expression interpreting the given string as a list of tag values,\n * pretty-printing the standard semicolon delimiter with the given separator.\n *\n * https://wiki.openstreetmap.org/wiki/Semi-colon_value_separator\n *\n * The returned expression can be complex, so use it only once within a property\n * value. To reuse the evaluated value, bind it to a variable in a let\n * expression.\n *\n * @param valueList A semicolon-delimited list of values.\n * @param separator A string to insert between each value, or an expression that\n * evaluates to this string.\n */\nexport function listValuesExpression(valueList, separator, valueToOmit) {\n let maxSeparators = maxValueListLength - 1;\n let valueListVariable = `${variablePrefix}__valueList`;\n let valueToOmitVariable = `${variablePrefix}__valueToOmit`;\n return [\n \"let\",\n valueListVariable,\n valueList,\n valueToOmitVariable,\n valueToOmit || \";\",\n listValueExpression(\n [\"var\", valueListVariable],\n separator,\n [\"var\", valueToOmitVariable],\n 0,\n maxSeparators,\n ),\n ];\n}\n\nconst localizedNameCore = listValuesExpression(\n [\"var\", localizedNameVariable],\n \"\\n\",\n);\n\n/**\n * The names in the user's preferred language, each on a separate line.\n */\nexport const localizedName = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedNameCore,\n];\n\nconst localizedNameInlineCore = listValuesExpression(\n [\"var\", localizedNameVariable],\n inlineSeparator,\n);\n\n/**\n * The names in the user's preferred language, all on the same line.\n */\nexport const localizedNameInline = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedNameInlineCore,\n];\n\n/**\n * Returns an expression that tests whether the target has the given prefix,\n * respecting word boundaries.\n */\nfunction startsWithExpression(target, candidatePrefix, collator) {\n // \"Quebec City\" vs. \"Qu\u00E9bec\", \"Washington, D.C.\" vs. \"Washington\"\n let wordBoundaries = \" ,\";\n return [\n \"all\",\n [\n \"==\",\n [\"slice\", target, 0, [\"length\", candidatePrefix]],\n candidatePrefix,\n collator,\n ],\n [\n \"in\",\n [\n \"slice\",\n // Pad the target in case the prefix matches exactly.\n // \"Montreal \" vs. \"Montr\u00E9al\"\n [\"concat\", target, wordBoundaries[0]],\n [\"length\", candidatePrefix],\n [\"+\", [\"length\", candidatePrefix], 1],\n ],\n wordBoundaries,\n ],\n ];\n}\n\nfunction overwritePrefixExpression(target, newPrefix) {\n return [\"concat\", newPrefix, [\"slice\", target, [\"length\", newPrefix]]];\n}\n\n/**\n * Returns an expression that tests whether the target has the given suffix,\n * respecting word boundaries.\n */\nfunction endsWithExpression(target, candidateSuffix, collator) {\n let wordBoundary = \" \";\n let suffixStartVariable = `${variablePrefix}__suffixStart`;\n return [\n \"let\",\n suffixStartVariable,\n [\"-\", [\"length\", target], [\"length\", candidateSuffix]],\n [\n \"all\",\n [\n \"==\",\n [\"slice\", target, [\"var\", suffixStartVariable]],\n candidateSuffix,\n collator,\n ],\n [\n \"==\",\n [\n \"slice\",\n target,\n [\"-\", [\"var\", suffixStartVariable], 1],\n [\"var\", suffixStartVariable],\n ],\n wordBoundary,\n ],\n ],\n ];\n}\n\nfunction overwriteSuffixExpression(target, newSuffix) {\n return [\n \"concat\",\n [\"slice\", target, 0, [\"-\", [\"length\", target], [\"length\", newSuffix]]],\n newSuffix,\n ];\n}\n\nconst localizedNameListVariable = `${variablePrefix}__localizedNameList`;\nconst nameListVariable = `${variablePrefix}__nameList`;\n\nconst localizedNameWithLocalGlossCore = [\n \"let\",\n localizedNameListVariable,\n listValuesExpression([\"var\", localizedNameVariable], \"\\n\"),\n [\n \"case\",\n // If the name in the preferred and local languages match exactly...\n [\n \"==\",\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", localizedCollatorVariable],\n ],\n // ...just pick one.\n [\"format\", [\"var\", localizedNameListVariable]],\n [\n \"let\",\n nameListVariable,\n listValuesExpression([\"get\", \"name\"], \"\\n\"),\n [\n \"case\",\n // If the name in the preferred language is the same as the name in the\n // local language except for the omission of diacritics and/or the addition\n // of a suffix (e.g., \"City\" in English)...\n startsWithExpression(\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", diacriticInsensitiveCollatorVariable],\n ),\n // ...then replace the common prefix with the local name.\n [\n \"format\",\n overwritePrefixExpression(\n [\"var\", localizedNameVariable],\n [\"var\", nameListVariable],\n ),\n ],\n // If the name in the preferred language is the same as the name in the\n // local language except for the omission of diacritics and/or the addition\n // of a prefix (e.g., \"City of\" in English or \"Ciudad de\" in Spanish)...\n endsWithExpression(\n [\"var\", localizedNameVariable],\n [\"get\", \"name\"],\n [\"var\", diacriticInsensitiveCollatorVariable],\n ),\n // ...then replace the common suffix with the local name.\n [\n \"format\",\n overwriteSuffixExpression(\n [\"var\", localizedNameVariable],\n [\"var\", nameListVariable],\n ),\n ],\n // Otherwise, gloss the name in the local language if it differs from the\n // localized name.\n [\n \"format\",\n [\"var\", localizedNameListVariable],\n \"\\n\",\n \"(\\u2068\",\n { \"font-scale\": 0.8 },\n listValuesExpression([\"get\", \"name\"], inlineSeparator, [\n \"var\",\n localizedNameVariable,\n ]),\n { \"font-scale\": 0.8 },\n \"\\u2069)\",\n { \"font-scale\": 0.8 },\n ],\n ],\n ],\n ],\n];\n\n/**\n * The name in the user's preferred language, followed by the name in the local\n * language in parentheses if it differs.\n */\nexport const localizedNameWithLocalGloss = [\n \"let\",\n localizedNameVariable,\n \"\",\n localizedCollatorVariable,\n [\"collator\", {}],\n diacriticInsensitiveCollatorVariable,\n [\"collator\", {}],\n localizedNameWithLocalGlossCore,\n];\n\n/**\n * ISO 3166-1 alpha-2 country codes by ISO 3166-1 alpha-3 code.\n *\n * Source: https://www.cia.gov/the-world-factbook/references/country-data-codes/\n */\nconst iso3166_1_alpha_2_by_3 = {\n ABW: \"AW\",\n AFG: \"AF\",\n AGO: \"AO\",\n AIA: \"AI\",\n ALB: \"AL\",\n AND: \"AD\",\n ARE: \"AE\",\n ARG: \"AR\",\n ARM: \"AM\",\n ASM: \"AS\",\n ATA: \"AQ\",\n ATF: \"TF\",\n ATG: \"AG\",\n AUS: \"AU\",\n AUT: \"AT\",\n AZE: \"AZ\",\n BDI: \"BI\",\n BEL: \"BE\",\n BEN: \"BJ\",\n BFA: \"BF\",\n BGD: \"BD\",\n BGR: \"BG\",\n BHR: \"BH\",\n BHS: \"BS\",\n BIH: \"BA\",\n BLM: \"BL\",\n BLR: \"BY\",\n BLZ: \"BZ\",\n BMU: \"BM\",\n BOL: \"BO\",\n BRA: \"BR\",\n BRB: \"BB\",\n BRN: \"BN\",\n BTN: \"BT\",\n BVT: \"BV\",\n BWA: \"BW\",\n CAF: \"CF\",\n CAN: \"CA\",\n CCK: \"CC\",\n CHE: \"CH\",\n CHL: \"CL\",\n CHN: \"CN\",\n CIV: \"CI\",\n CMR: \"CM\",\n COD: \"CD\",\n COG: \"CG\",\n COK: \"CK\",\n COL: \"CO\",\n COM: \"KM\",\n CPV: \"CV\",\n CRI: \"CR\",\n CUB: \"CU\",\n CUW: \"CW\",\n CXR: \"CX\",\n CYM: \"KY\",\n CYP: \"CY\",\n CZE: \"CZ\",\n DEU: \"DE\",\n DJI: \"DJ\",\n DMA: \"DM\",\n DNK: \"DK\",\n DOM: \"DO\",\n DZA: \"DZ\",\n ECU: \"EC\",\n EGY: \"EG\",\n ERI: \"ER\",\n ESH: \"EH\",\n ESP: \"ES\",\n EST: \"EE\",\n ETH: \"ET\",\n FIN: \"FI\",\n FJI: \"FJ\",\n FLK: \"FK\",\n FRA: \"FR\",\n FRO: \"FO\",\n FSM: \"FM\",\n FXX: \"FX\",\n GAB: \"GA\",\n GBR: \"GB\",\n GEO: \"GE\",\n GGY: \"GG\",\n GHA: \"GH\",\n GIB: \"GI\",\n GIN: \"GN\",\n GLP: \"GP\",\n GMB: \"GM\",\n GNB: \"GW\",\n GNQ: \"GQ\",\n GRC: \"GR\",\n GRD: \"GD\",\n GRL: \"GL\",\n GTM: \"GT\",\n GUF: \"GF\",\n GUM: \"GU\",\n GUY: \"GY\",\n HKG: \"HK\",\n HMD: \"HM\",\n HND: \"HN\",\n HRV: \"HR\",\n HTI: \"HT\",\n HUN: \"HU\",\n IDN: \"ID\",\n IMN: \"IM\",\n IND: \"IN\",\n IOT: \"IO\",\n IRL: \"IE\",\n IRN: \"IR\",\n IRQ: \"IQ\",\n ISL: \"IS\",\n ISR: \"IL\",\n ITA: \"IT\",\n JAM: \"JM\",\n JEY: \"JE\",\n JOR: \"JO\",\n JPN: \"JP\",\n KAZ: \"KZ\",\n KEN: \"KE\",\n KGZ: \"KG\",\n KHM: \"KH\",\n KIR: \"KI\",\n KNA: \"KN\",\n KOR: \"KR\",\n KWT: \"KW\",\n LAO: \"LA\",\n LBN: \"LB\",\n LBR: \"LR\",\n LBY: \"LY\",\n LCA: \"LC\",\n LIE: \"LI\",\n LKA: \"LK\",\n LSO: \"LS\",\n LTU: \"LT\",\n LUX: \"LU\",\n LVA: \"LV\",\n MAC: \"MO\",\n MAF: \"MF\",\n MAR: \"MA\",\n MCO: \"MC\",\n MDA: \"MD\",\n MDG: \"MG\",\n MDV: \"MV\",\n MEX: \"MX\",\n MHL: \"MH\",\n MKD: \"MK\",\n MLI: \"ML\",\n MLT: \"MT\",\n MMR: \"MM\",\n MNE: \"ME\",\n MNG: \"MN\",\n MNP: \"MP\",\n MOZ: \"MZ\",\n MRT: \"MR\",\n MSR: \"MS\",\n MTQ: \"MQ\",\n MUS: \"MU\",\n MWI: \"MW\",\n MYS: \"MY\",\n MYT: \"YT\",\n NAM: \"NA\",\n NCL: \"NC\",\n NER: \"NE\",\n NFK: \"NF\",\n NGA: \"NG\",\n NIC: \"NI\",\n NIU: \"NU\",\n NLD: \"NL\",\n NOR: \"NO\",\n NPL: \"NP\",\n NRU: \"NR\",\n NZL: \"NZ\",\n OMN: \"OM\",\n PAK: \"PK\",\n PAN: \"PA\",\n PCN: \"PN\",\n PER: \"PE\",\n PHL: \"PH\",\n PLW: \"PW\",\n PNG: \"PG\",\n POL: \"PL\",\n PRI: \"PR\",\n PRK: \"KP\",\n PRT: \"PT\",\n PRY: \"PY\",\n PSE: \"PS\",\n PYF: \"PF\",\n QAT: \"QA\",\n REU: \"RE\",\n ROU: \"RO\",\n RUS: \"RU\",\n RWA: \"RW\",\n SAU: \"SA\",\n SDN: \"SD\",\n SEN: \"SN\",\n SGP: \"SG\",\n SGS: \"GS\",\n SHN: \"SH\",\n SJM: \"SJ\",\n SLB: \"SB\",\n SLE: \"SL\",\n SLV: \"SV\",\n SMR: \"SM\",\n SOM: \"SO\",\n SPM: \"PM\",\n SRB: \"RS\",\n SSD: \"SS\",\n STP: \"ST\",\n SUR: \"SR\",\n SVK: \"SK\",\n SVN: \"SI\",\n SWE: \"SE\",\n SWZ: \"SZ\",\n SXM: \"SX\",\n SYC: \"SC\",\n SYR: \"SY\",\n TCA: \"TC\",\n TCD: \"TD\",\n TGO: \"TG\",\n THA: \"TH\",\n TJK: \"TJ\",\n TKL: \"TK\",\n TKM: \"TM\",\n TLS: \"TL\",\n TON: \"TO\",\n TTO: \"TT\",\n TUN: \"TN\",\n TUR: \"TR\",\n TUV: \"TV\",\n TWN: \"TW\",\n TZA: \"TZ\",\n UGA: \"UG\",\n UKR: \"UA\",\n UMI: \"UM\",\n URY: \"UY\",\n USA: \"US\",\n UZB: \"UZ\",\n VAT: \"VA\",\n VCT: \"VC\",\n VEN: \"VE\",\n VGB: \"VG\",\n VIR: \"VI\",\n VNM: \"VN\",\n VUT: \"VU\",\n WLF: \"WF\",\n WSM: \"WS\",\n YEM: \"YE\",\n ZAF: \"ZA\",\n ZMB: \"ZM\",\n ZWE: \"ZW\",\n};\n\nconst countryNamesByCodeVariable = `${variablePrefix}__countryNamesByCode`;\n\n/**\n * Returns a table of country names in the user\u2019s preferred language by ISO 3166-1 alpha-3 code.\n *\n * @param {[string]} locales - The locales for formatting the country names.\n * @param {boolean} options.uppercase Whether to write the country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function getLocalizedCountryNames(locales, options = {}) {\n let countryNames = new Intl.DisplayNames(locales, {\n type: \"region\",\n fallback: \"none\",\n });\n return Object.fromEntries(\n Object.entries(iso3166_1_alpha_2_by_3).map((e) => {\n let name = countryNames.of(e[1]);\n if (name && options?.uppercase) {\n // Neither the upcase expression operator nor the text-transform layout property is locale-aware, so uppercase the name upfront.\n name = name\n .toLocaleUpperCase(locales)\n // Word boundaries are less discernible in uppercase text, so pad each word by an additional space.\n .replaceAll(\" \", \" \");\n }\n return [e[0], name];\n }),\n );\n}\n\n/**\n * Returns the global state that Diplomat needs to fully localize the style.\n *\n * @param {[string]} locales - The locales for formatting the country names.\n * @param {boolean} options.uppercaseCountryNames Whether to write country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function getGlobalStateForLocalization(locales, options = {}) {\n let state = {};\n state[countryNamesByCodeVariable] = getLocalizedCountryNames(locales, {\n uppercase: options?.uppercaseCountryNames,\n });\n return state;\n}\n\n/**\n * Returns an expression that converts the given country code to a human-readable name in the user's preferred language.\n *\n * @param {array} code An expression that evaluates to an ISO 3166-1 alpha-3 country code.\n */\nexport function getLocalizedCountryNameExpression(code) {\n return [\n \"let\",\n \"code\",\n code,\n [\n \"coalesce\",\n [\n \"get\",\n [\"var\", \"code\"],\n [\n \"coalesce\",\n [\"global-state\", countryNamesByCodeVariable],\n [\"literal\", {}],\n ],\n ],\n // Fall back to the country code in parentheses.\n [\"concat\", \"(\", [\"var\", \"code\"], \")\"],\n ],\n ];\n}\n\n/**\n * Updates each style layer's `text-field` value to match the given locales, upgrading any unlocalizable layer along the way.\n *\n * This method ugprades unlocalizable layers to localized multiline or inline labels depending on the `symbol-placement` layout property. To add a dual language label to a layer, set its `text-field` layout property manually using the `localizedNameWithLocalGloss` constant.\n *\n * If neither `options.layers` nor `options.sourceLayers` is specified, this function makes localizable any style layer that gets the feature property specified in `options.unlocalizedNameProperty`, or `name` by default.\n *\n * @param {maplibregl.Map} map - The map to localize.\n * @param {[string]} locales - The locales to insert into each layer.\n * @param {[string]} options.layers - The style layers with these IDs will be made localizable.\n * @param {[string]} options.sourceLayers - The style layers that use these source layers will be made localizable. These are source layer IDs, not style layer IDs.\n * @param {string} options.unlocalizedNameProperty - The name of the property holding the unlocalized name.\n * @param {string} options.localizedNamePropertyFormat - The format of properties holding localized names, where `$1` is replaced by an IETF language tag.\n * @param {boolean} options.glossLocalNames - Whether to format each label as a dual language label including a local name gloss.\n * @param {boolean} options.uppercaseCountryNames Whether to write country names in all uppercase, respecting the locale\u2019s case conventions.\n */\nexport function localizeStyle(map, locales = getLocales(), options = {}) {\n let style = map.getStyle();\n\n let localizedNameExpression = getLocalizedNameExpression(locales, options);\n let legacyLocalizedNameExpression = getLocalizedNameExpression(locales, {\n ...options,\n includesLegacyFields: true,\n });\n\n for (let layer of style.layers) {\n let sourceLayer = layer[\"source-layer\"];\n if (\n (!options.layers && !options.sourceLayers) ||\n options.layers?.includes(layer.id) ||\n (sourceLayer && options.sourceLayers?.includes(sourceLayer))\n ) {\n prepareLayer(\n layer,\n options?.unlocalizedNameProperty,\n options?.glossLocalNames,\n );\n }\n localizeLayer(\n layer,\n locales[0],\n localizedNameExpression,\n legacyLocalizedNameExpression,\n );\n }\n\n let countryNames = getLocalizedCountryNames(locales, {\n uppercase: options?.uppercaseCountryNames,\n });\n map.setGlobalStateProperty(countryNamesByCodeVariable, countryNames);\n\n map.setStyle(style);\n}\n\nif (typeof window !== \"undefined\") {\n window.Diplomat = {\n getGlobalStateForLocalization,\n getLanguageFromURL,\n getLocales,\n getLocalizedCountryNameExpression,\n listValuesExpression,\n localizeLayers,\n localizeStyle,\n localizedName,\n localizedNameInline,\n localizedNameWithLocalGloss,\n };\n if (\"maplibregl\" in window) {\n maplibregl.Diplomat = window.Diplomat;\n\n maplibregl.Map.prototype.localizeStyle = function (\n locales = getLocales(),\n options = {},\n ) {\n localizeStyle(this, locales, options);\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACP,EAEMC,EAA6B,GAAGtG,CAAc,uBAQ7C,SAASuG,EAAyBtF,EAASU,EAAU,CAAC,EAAG,CAC9D,IAAI6E,EAAe,IAAI,KAAK,aAAavF,EAAS,CAChD,KAAM,SACN,SAAU,MACZ,CAAC,EACD,OAAO,OAAO,YACZ,OAAO,QAAQoF,CAAsB,EAAE,IAAKI,GAAM,CAChD,IAAIC,EAAOF,EAAa,GAAGC,EAAE,CAAC,CAAC,EAC/B,OAAIC,GAAQ/E,GAAS,YAEnB+E,EAAOA,EACJ,kBAAkBzF,CAAO,EAEzB,WAAW,IAAK,IAAI,GAElB,CAACwF,EAAE,CAAC,EAAGC,CAAI,CACpB,CAAC,CACH,CACF,CAQO,SAASC,EAA8B1F,EAASU,EAAU,CAAC,EAAG,CACnE,IAAIiF,EAAQ,CAAC,EACb,OAAAA,EAAMN,CAA0B,EAAIC,EAAyBtF,EAAS,CACpE,UAAWU,GAAS,qBACtB,CAAC,EACMiF,CACT,CAOO,SAASC,EAAkCC,EAAM,CACtD,MAAO,CACL,MACA,OACAA,EACA,CACE,WACA,CACE,MACA,CAAC,MAAO,MAAM,EACd,CACE,WACA,CAAC,eAAgBR,CAA0B,EAC3C,CAAC,UAAW,CAAC,CAAC,CAChB,CACF,EAEA,CAAC,SAAU,IAAK,CAAC,MAAO,MAAM,EAAG,GAAG,CACtC,CACF,CACF,CAkBO,SAASS,EAAcC,EAAK/F,EAAUO,EAAW,EAAGG,EAAU,CAAC,EAAG,CACvE,IAAIsF,EAAQD,EAAI,SAAS,EAErBrD,EAA0BjC,EAA2BT,EAASU,CAAO,EACrEiC,EAAgClC,EAA2BT,EAAS,CACtE,GAAGU,EACH,qBAAsB,EACxB,CAAC,EAED,QAASqB,KAASiE,EAAM,OAAQ,CAC9B,IAAIC,EAAclE,EAAM,cAAc,GAEnC,CAACrB,EAAQ,QAAU,CAACA,EAAQ,cAC7BA,EAAQ,QAAQ,SAASqB,EAAM,EAAE,GAChCkE,GAAevF,EAAQ,cAAc,SAASuF,CAAW,IAE1DnE,EACEC,EACArB,GAAS,wBACTA,GAAS,eACX,EAEF8B,EACET,EACA/B,EAAQ,CAAC,EACT0C,EACAC,CACF,CACF,CAEA,IAAI4C,EAAeD,EAAyBtF,EAAS,CACnD,UAAWU,GAAS,qBACtB,CAAC,EACDqF,EAAI,uBAAuBV,EAA4BE,CAAY,EAEnEQ,EAAI,SAASC,CAAK,CACpB,CAEI,OAAO,OAAW,MACpB,OAAO,SAAW,CAChB,8BAAAN,EACA,mBAAA1G,EACA,WAAAuB,EACA,kCAAAqF,EACA,qBAAA/B,EACA,eAAAjB,EACA,cAAAkD,EACA,cAAA5B,EACA,oBAAAC,EACA,4BAAAgB,CACF,EACI,eAAgB,SAClB,WAAW,SAAW,OAAO,SAE7B,WAAW,IAAI,UAAU,cAAgB,SACvCnF,EAAUO,EAAW,EACrBG,EAAU,CAAC,EACX,CACAoF,EAAc,KAAM9F,EAASU,CAAO,CACtC",
|
|
6
|
+
"names": ["variablePrefix", "getLanguageFromURL", "url", "language", "powerset", "array", "accum", "value", "pick", "getVariants", "locale", "getRelatedLanguageTags", "tag", "maximized", "quals", "q", "tags", "locales", "l", "scoreLocale", "score", "a", "b", "validTags", "getLocales", "defaultUnlocalizedNameProperty", "getLocalizedNameExpression", "options", "localizedNameProperty", "fields", "f", "updateVariable", "letExpr", "variable", "variableNameIndex", "localizedNameVariable", "localizedCollatorVariable", "diacriticInsensitiveCollatorVariable", "replacePropertyReferences", "expression", "propertyName", "replacement", "didReplace", "arg", "idx", "newValue", "inlineSeparator", "prepareLayer", "layer", "unlocalizedNameProperty", "glossLocalNames", "textField", "symbolPlacement", "newTextField", "localizedNameWithLocalGlossCore", "localizedNameInlineCore", "localizedNameCore", "localizeLayer", "collationLocale", "localizedNameExpression", "legacyLocalizedNameExpression", "localizeLayers", "layers", "listValueExpression", "list", "separator", "valueToOmit", "listStart", "numReplacements", "asIs", "iteration", "rawSeparator", "needleStartVariable", "needleEndVariable", "valueVariable", "lookaheadVariable", "nextListStartVariable", "maxValueListLength", "listValuesExpression", "valueList", "maxSeparators", "valueListVariable", "valueToOmitVariable", "localizedName", "localizedNameInline", "startsWithExpression", "target", "candidatePrefix", "collator", "wordBoundaries", "overwritePrefixExpression", "newPrefix", "endsWithExpression", "candidateSuffix", "wordBoundary", "suffixStartVariable", "overwriteSuffixExpression", "newSuffix", "localizedNameListVariable", "nameListVariable", "localizedNameWithLocalGloss", "iso3166_1_alpha_2_by_3", "countryNamesByCodeVariable", "getLocalizedCountryNames", "countryNames", "e", "name", "getGlobalStateForLocalization", "state", "getLocalizedCountryNameExpression", "code", "localizeStyle", "map", "style", "sourceLayer"]
|
|
7
7
|
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
declare module "@americana/diplomat" {
|
|
2
|
+
import type { Map as MaplibreMap, StyleLayer } from "maplibre-gl";
|
|
3
|
+
|
|
4
|
+
// MapLibre types expressions as `any`
|
|
5
|
+
type Expression = any;
|
|
6
|
+
|
|
7
|
+
export function getLanguageFromURL(url: URL): string | null;
|
|
8
|
+
|
|
9
|
+
export function getRelatedLanguageTags(tag: string): string[];
|
|
10
|
+
|
|
11
|
+
export function getLocales(): string[];
|
|
12
|
+
|
|
13
|
+
export function getLocalizedNameExpression(
|
|
14
|
+
locales: string[],
|
|
15
|
+
options?: {
|
|
16
|
+
includesLegacyFields?: boolean;
|
|
17
|
+
unlocalizedNameProperty?: string;
|
|
18
|
+
localizedNamePropertyFormat?: string;
|
|
19
|
+
},
|
|
20
|
+
): Expression;
|
|
21
|
+
|
|
22
|
+
export function updateVariable(
|
|
23
|
+
letExpr: Expression,
|
|
24
|
+
variable: string,
|
|
25
|
+
value: any,
|
|
26
|
+
): void;
|
|
27
|
+
|
|
28
|
+
export function replacePropertyReferences(
|
|
29
|
+
expression: Expression,
|
|
30
|
+
propertyName: string,
|
|
31
|
+
replacement: any,
|
|
32
|
+
): Expression | undefined;
|
|
33
|
+
|
|
34
|
+
export function listValuesExpression(
|
|
35
|
+
valueList: Expression,
|
|
36
|
+
separator: string | Expression,
|
|
37
|
+
valueToOmit?: Expression,
|
|
38
|
+
): Expression;
|
|
39
|
+
|
|
40
|
+
export function prepareLayer(
|
|
41
|
+
layer: StyleLayer,
|
|
42
|
+
unlocalizedNameProperty?: string,
|
|
43
|
+
glossLocalNames?: boolean,
|
|
44
|
+
): void;
|
|
45
|
+
|
|
46
|
+
export function localizeLayers(
|
|
47
|
+
layers: StyleLayer[],
|
|
48
|
+
locales?: string[],
|
|
49
|
+
options?: {
|
|
50
|
+
unlocalizedNameProperty?: string;
|
|
51
|
+
localizedNamePropertyFormat?: string;
|
|
52
|
+
},
|
|
53
|
+
): void;
|
|
54
|
+
|
|
55
|
+
export function getLocalizedCountryNames(
|
|
56
|
+
locales: string[],
|
|
57
|
+
options?: { uppercase?: boolean },
|
|
58
|
+
): Record<string, string | undefined>;
|
|
59
|
+
|
|
60
|
+
export function getGlobalStateForLocalization(
|
|
61
|
+
locales: string[],
|
|
62
|
+
options?: { uppercaseCountryNames?: boolean },
|
|
63
|
+
): Record<string, any>;
|
|
64
|
+
|
|
65
|
+
export function getLocalizedCountryNameExpression(
|
|
66
|
+
code: Expression,
|
|
67
|
+
): Expression;
|
|
68
|
+
|
|
69
|
+
export function localizeStyle(
|
|
70
|
+
map: MaplibreMap,
|
|
71
|
+
locales?: string[],
|
|
72
|
+
options?: {
|
|
73
|
+
layers?: string[];
|
|
74
|
+
sourceLayers?: string[];
|
|
75
|
+
unlocalizedNameProperty?: string;
|
|
76
|
+
localizedNamePropertyFormat?: string;
|
|
77
|
+
glossLocalNames?: boolean;
|
|
78
|
+
uppercaseCountryNames?: boolean;
|
|
79
|
+
},
|
|
80
|
+
): void;
|
|
81
|
+
|
|
82
|
+
export const localizedName: Expression;
|
|
83
|
+
export const localizedNameInline: Expression;
|
|
84
|
+
export const localizedNameWithLocalGloss: Expression;
|
|
85
|
+
}
|
package/index.js
CHANGED
|
@@ -9,6 +9,81 @@ export function getLanguageFromURL(url) {
|
|
|
9
9
|
return language === "" ? null : language;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
Returns the powerset of the given array.
|
|
14
|
+
*/
|
|
15
|
+
function powerset(array) {
|
|
16
|
+
return array.reduce(
|
|
17
|
+
(accum, value) => [...accum, ...accum.map((pick) => [...pick, value])],
|
|
18
|
+
[[]],
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
Compatibility shim for `Intl.Locale.prototype.variants`.
|
|
24
|
+
*/
|
|
25
|
+
function getVariants(locale) {
|
|
26
|
+
return locale.variants ?? locale.minimize().baseName.match(/-([-\w]+)/)?.[1];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
Returns an array of the language tags related to the given language tag, sorted from most specific to least specific.
|
|
31
|
+
|
|
32
|
+
@param {string} tag - The language tag that the returned language tags are related to.
|
|
33
|
+
@returns {[string]} A sorted array of related language tags, or an empty array if `tag` is malformed.
|
|
34
|
+
*/
|
|
35
|
+
export function getRelatedLanguageTags(tag) {
|
|
36
|
+
let locale;
|
|
37
|
+
try {
|
|
38
|
+
locale = new Intl.Locale(tag);
|
|
39
|
+
} catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let maximized = locale.maximize();
|
|
44
|
+
// The subtags and extensions used in OSM name:*=* subkeys.
|
|
45
|
+
let quals = [
|
|
46
|
+
maximized.script,
|
|
47
|
+
maximized.region,
|
|
48
|
+
getVariants(maximized),
|
|
49
|
+
maximized.numberingSystem,
|
|
50
|
+
].filter((q) => q);
|
|
51
|
+
// Get all the combinations of components and convert them to language tags.
|
|
52
|
+
let tags = powerset(quals).map((quals) =>
|
|
53
|
+
[maximized.language, ...quals].join("-"),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Add the original language tag, in case maximizing it dropped miscellaneous extensions.
|
|
57
|
+
tags.push(locale + "");
|
|
58
|
+
tags.push(locale.baseName);
|
|
59
|
+
|
|
60
|
+
// Validate each of the language tags.
|
|
61
|
+
let locales = tags
|
|
62
|
+
.map((tag) => {
|
|
63
|
+
try {
|
|
64
|
+
return new Intl.Locale(tag);
|
|
65
|
+
} catch {}
|
|
66
|
+
})
|
|
67
|
+
.filter((l) => l);
|
|
68
|
+
|
|
69
|
+
// Sort the locales from most specific to least specific.
|
|
70
|
+
let scoreLocale = (locale) => {
|
|
71
|
+
let tag = locale + "";
|
|
72
|
+
let score = 0;
|
|
73
|
+
score += tag.length ?? 0;
|
|
74
|
+
score += tag.split("-").length ?? 0;
|
|
75
|
+
// Prioritize variants, which are more specific than script and region.
|
|
76
|
+
score += getVariants(locale)?.length ?? 0;
|
|
77
|
+
// Prioritize extensions, which Intl.Locale.prototype.maximize can’t maximize.
|
|
78
|
+
score += tag.match(/(?:-[tx]-|-u-\w\w-)\w+/)?.[0]?.length ?? 0;
|
|
79
|
+
return score;
|
|
80
|
+
};
|
|
81
|
+
locales.sort((a, b) => scoreLocale(b) - scoreLocale(a));
|
|
82
|
+
|
|
83
|
+
let validTags = locales.map((l) => l + "");
|
|
84
|
+
return [...new Set(validTags)];
|
|
85
|
+
}
|
|
86
|
+
|
|
12
87
|
/**
|
|
13
88
|
* Returns the languages that the user prefers.
|
|
14
89
|
*/
|
|
@@ -17,27 +92,10 @@ export function getLocales() {
|
|
|
17
92
|
let parameter = getLanguageFromURL(window.location)?.split(",");
|
|
18
93
|
// Fall back to the user's language preference.
|
|
19
94
|
let userLocales = parameter ?? navigator.languages ?? [navigator.language];
|
|
20
|
-
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let components = locale.split("-");
|
|
25
|
-
while (components.length > 0) {
|
|
26
|
-
let parent = components.join("-");
|
|
27
|
-
try {
|
|
28
|
-
// Preflight the parent locale in case it’s incomplete like `en-x`.
|
|
29
|
-
new Intl.Locale(parent);
|
|
30
|
-
if (!localeSet.has(parent)) locales.push(parent);
|
|
31
|
-
localeSet.add(parent);
|
|
32
|
-
} catch {}
|
|
33
|
-
components.pop();
|
|
34
|
-
// A Unicode extension like -u-nu must be followed by another subtag.
|
|
35
|
-
if (components.at(-1)?.length === 2 && components.at(-2) === "u") {
|
|
36
|
-
components.pop();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return locales;
|
|
95
|
+
// Get a full fallback list.
|
|
96
|
+
let tags = userLocales.flatMap((l) => getRelatedLanguageTags(l));
|
|
97
|
+
|
|
98
|
+
return [...new Set(tags)];
|
|
41
99
|
}
|
|
42
100
|
|
|
43
101
|
const defaultUnlocalizedNameProperty = "name";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@americana/diplomat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Internationalization plugin for MapLibre GL JS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"maplibre-gl-js",
|
|
@@ -29,10 +29,12 @@
|
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"dist/",
|
|
32
|
-
"docs/"
|
|
32
|
+
"docs/",
|
|
33
|
+
"index.d.ts"
|
|
33
34
|
],
|
|
34
35
|
"type": "module",
|
|
35
36
|
"main": "index.js",
|
|
37
|
+
"types": "index.d.ts",
|
|
36
38
|
"scripts": {
|
|
37
39
|
"build": "esbuild index.js --bundle --minify --sourcemap --outdir=dist",
|
|
38
40
|
"clean": "shx rm -rf dist build",
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@maplibre/maplibre-gl-style-spec": "^24.3.1",
|
|
48
|
-
"esbuild": "0.27.
|
|
50
|
+
"esbuild": "0.27.3",
|
|
49
51
|
"open": "^11.0.0",
|
|
50
52
|
"prettier": "^3.6.2",
|
|
51
53
|
"shx": "^0.4.0"
|