MediaWiki:Gadget-diplomat.js

From OpenStreetMap Wiki
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