From 150fda426c849d31de3db9c490e09ab8d5971c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 26 Nov 2022 15:21:53 -0800 Subject: [PATCH 1/5] Document name usage for taginfo --- scripts/taginfo_template.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/taginfo_template.json b/scripts/taginfo_template.json index b03d4675e..6c26db5da 100644 --- a/scripts/taginfo_template.json +++ b/scripts/taginfo_template.json @@ -10,6 +10,16 @@ "contact_email": "zelonewolf@gmail.com" }, "tags": [ + { + "key": "name:en", + "object_types": ["node", "way", "relation", "area"], + "description": "Labels are in English if available." + }, + { + "key": "name", + "object_types": ["node", "way", "relation", "area"], + "description": "Labels fall back to the local language if name:en is unavailable." + }, { "key": "capital", "value": "yes", From 794a8b4c3fdfe3c49344b944dfb7479106fdd400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 26 Nov 2022 15:22:54 -0800 Subject: [PATCH 2/5] Consolidated name expressions for consistency --- src/constants/label.js | 2 +- src/layer/aeroway.js | 12 +++--------- src/layer/park.js | 13 +++---------- src/layer/place.js | 20 ++++++++++---------- src/layer/water.js | 12 +++--------- 5 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/constants/label.js b/src/constants/label.js index a18a80674..0f0e973f2 100644 --- a/src/constants/label.js +++ b/src/constants/label.js @@ -1,7 +1,7 @@ "use strict"; // Name fields in order of preference -export const name_en = [ +export const localizedName = [ "coalesce", ["get", "name:en"], ["get", "name:latin"], diff --git a/src/layer/aeroway.js b/src/layer/aeroway.js index b3c7ff124..d65cee895 100644 --- a/src/layer/aeroway.js +++ b/src/layer/aeroway.js @@ -1,14 +1,8 @@ "use strict"; +import * as Label from "../constants/label.js"; import * as Color from "../constants/color.js"; -const name_en = [ - "coalesce", - ["get", "name:en"], - ["get", "name:latin"], - ["get", "name"], -]; - const minorAirport = [ "any", ["!", ["has", "iata"]], @@ -221,7 +215,7 @@ export const airportLabel = { }, layout: { visibility: "visible", - "text-field": name_en, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold"], "text-size": 10, ...iconLayout, @@ -245,7 +239,7 @@ export const minorAirportLabel = { }, layout: { visibility: "visible", - "text-field": name_en, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold"], "text-size": 10, }, diff --git a/src/layer/park.js b/src/layer/park.js index 0e53e70ae..8d58424ba 100644 --- a/src/layer/park.js +++ b/src/layer/park.js @@ -1,15 +1,8 @@ "use strict"; +import * as Label from "../constants/label.js"; import * as Color from "../constants/color.js"; -// Name fields in order of preference -const name_en = [ - "coalesce", - ["get", "name:en"], - ["get", "name:latin"], - ["get", "name"], -]; - export const fill = { id: "protected-area-fill", type: "fill", @@ -50,7 +43,7 @@ export const label = { }, layout: { visibility: "visible", - "text-field": name_en, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold"], "text-size": 10, "symbol-sort-key": ["get", "rank"], @@ -102,7 +95,7 @@ export const parkLabel = { }, layout: { visibility: "visible", - "text-field": name_en, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold"], "text-size": 10, "symbol-sort-key": ["get", "rank"], diff --git a/src/layer/place.js b/src/layer/place.js index 4420c1019..5df441b6d 100644 --- a/src/layer/place.js +++ b/src/layer/place.js @@ -1,4 +1,4 @@ -import * as label from "../constants/label.js"; +import * as Label from "../constants/label.js"; const cityLabelPaint = { "text-color": "#444", @@ -59,7 +59,7 @@ export const village = { [11, 0.5], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-anchor": "bottom", "text-variable-anchor": [ "bottom", @@ -122,7 +122,7 @@ export const town = { [11, 0.7], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-anchor": "bottom", "text-variable-anchor": [ "bottom", @@ -181,7 +181,7 @@ export const city = { [11, 0.9], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-anchor": "bottom", "text-variable-anchor": [ "bottom", @@ -223,7 +223,7 @@ export const state = { [6, 14], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-padding": 1, "text-transform": "uppercase", "text-letter-spacing": 0.04, @@ -266,7 +266,7 @@ export const countryOther = { [7, 15], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-max-width": 6.25, "text-transform": "none", }, @@ -296,7 +296,7 @@ export const country3 = { [7, 17], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-max-width": 6.25, "text-transform": "none", }, @@ -326,7 +326,7 @@ export const country2 = { [5, 17], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-max-width": 6.25, "text-transform": "none", }, @@ -357,7 +357,7 @@ export const country1 = { [6, 19], ], }, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-max-width": ["step", ["zoom"], 6.25, 3, 12], "text-transform": "none", "text-offset": [ @@ -383,7 +383,7 @@ export const continent = { layout: { "text-font": ["Metropolis Light"], "text-size": 13, - "text-field": label.name_en, + "text-field": Label.localizedName, "text-justify": "center", "text-transform": "uppercase", }, diff --git a/src/layer/water.js b/src/layer/water.js index 580f5855a..9d532612b 100644 --- a/src/layer/water.js +++ b/src/layer/water.js @@ -1,5 +1,6 @@ "use strict"; +import * as Label from "../constants/label.js"; import * as Color from "../constants/color.js"; const bigRivers = ["river", "canal"]; @@ -75,16 +76,9 @@ const labelPaintProperties = { "text-halo-blur": 0.25, }; -const nameField = [ - "coalesce", - ["get", "name:en"], - ["get", "name_en"], - ["get", "name"], -]; - const labelLayoutProperties = { "symbol-placement": "line", - "text-field": nameField, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold Italic"], "text-max-angle": 55, }; @@ -153,7 +147,7 @@ export const waterPointLabel = { "source-layer": "water_name", filter: ["all", ["==", ["geometry-type"], "Point"]], layout: { - "text-field": nameField, + "text-field": Label.localizedName, "text-font": ["Metropolis Bold Italic"], "text-size": [ "interpolate", From 3ff1f9c006857d1cf0b36f65cce2dfed179b1655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 26 Nov 2022 16:10:11 -0800 Subject: [PATCH 3/5] Use user-preferred languages in labels --- scripts/taginfo_template.json | 7 +------ src/constants/label.js | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/scripts/taginfo_template.json b/scripts/taginfo_template.json index 6c26db5da..3ce35e689 100644 --- a/scripts/taginfo_template.json +++ b/scripts/taginfo_template.json @@ -10,15 +10,10 @@ "contact_email": "zelonewolf@gmail.com" }, "tags": [ - { - "key": "name:en", - "object_types": ["node", "way", "relation", "area"], - "description": "Labels are in English if available." - }, { "key": "name", "object_types": ["node", "way", "relation", "area"], - "description": "Labels fall back to the local language if name:en is unavailable." + "description": "Labels fall back to the local language if none of the user-preferred languages is available." }, { "key": "capital", diff --git a/src/constants/label.js b/src/constants/label.js index 0f0e973f2..37ae6f77d 100644 --- a/src/constants/label.js +++ b/src/constants/label.js @@ -1,9 +1,24 @@ "use strict"; // Name fields in order of preference -export const localizedName = [ - "coalesce", - ["get", "name:en"], - ["get", "name:latin"], - ["get", "name"], -]; +export const localizedName = (function () { + let userLocales = + "languages" in navigator ? [...navigator.languages] : [navigator.language]; + let locales = []; + let localeSet = new Set(); // avoid duplicates + for (let locale of userLocales) { + // Add progressively less specific variants of each user-specified locale. + let components = locale.split("-"); + while (components.length > 0) { + let parent = components.join("-"); + if (!localeSet.has(parent)) locales.push(parent); + localeSet.add(parent); + components.pop(); + } + } + if (locales.at(-1) === "en") { + locales.push("latin"); + } + let nameFields = [...locales.map((l) => `name:${l}`), "name"]; + return ["coalesce", ...nameFields.map((f) => ["get", f])]; +})(); From 275dde8358ae0e85f552bf77f9b89bc5411754f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 26 Nov 2022 19:59:31 -0800 Subject: [PATCH 4/5] Update src/constants/label.js Co-authored-by: Josh Lee --- src/constants/label.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/constants/label.js b/src/constants/label.js index 37ae6f77d..5db32f0f3 100644 --- a/src/constants/label.js +++ b/src/constants/label.js @@ -2,8 +2,7 @@ // Name fields in order of preference export const localizedName = (function () { - let userLocales = - "languages" in navigator ? [...navigator.languages] : [navigator.language]; + let userLocales = navigator.languages ?? [navigator.language]; let locales = []; let localeSet = new Set(); // avoid duplicates for (let locale of userLocales) { From f5db5eed5e325f1eb0eb9564b7655b0353320a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 26 Nov 2022 21:13:21 -0800 Subject: [PATCH 5/5] Localize road names (into German) --- src/constants/label.js | 28 ++++++++++++++++++++++++---- src/layer/transportation_label.js | 8 ++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/constants/label.js b/src/constants/label.js index 5db32f0f3..e25addfdd 100644 --- a/src/constants/label.js +++ b/src/constants/label.js @@ -1,7 +1,14 @@ "use strict"; -// Name fields in order of preference -export const localizedName = (function () { +/** + * Returns a `coalesce` expression that resolves to the feature's name in a + * language that the user prefers. + * + * @param {boolean} includesLegacyFields - Whether to include the older fields + * that include underscores, for layers that have not transitioned to the + * colon syntax. + */ +function getLocalizedNameExpression(includesLegacyFields) { let userLocales = navigator.languages ?? [navigator.language]; let locales = []; let localeSet = new Set(); // avoid duplicates @@ -18,6 +25,19 @@ export const localizedName = (function () { if (locales.at(-1) === "en") { locales.push("latin"); } - let nameFields = [...locales.map((l) => `name:${l}`), "name"]; + let nameFields = [ + ...locales.flatMap((l) => { + let fields = [`name:${l}`]; + // transportation_label uses an underscore instead of a colon. + // https://github.com/openmaptiles/openmaptiles/issues/769 + if (includesLegacyFields && (l === "de" || l === "en")) + fields.push(`name_${l}`); + return fields; + }), + "name", + ]; return ["coalesce", ...nameFields.map((f) => ["get", f])]; -})(); +} + +export const localizedName = getLocalizedNameExpression(false); +export const legacyLocalizedName = getLocalizedNameExpression(true); diff --git a/src/layer/transportation_label.js b/src/layer/transportation_label.js index 243db3a53..d448d540a 100644 --- a/src/layer/transportation_label.js +++ b/src/layer/transportation_label.js @@ -1,5 +1,6 @@ "use strict"; +import * as Label from "../constants/label.js"; import * as Color from "../constants/color.js"; const highwaySelector = ["match", ["get", "class"]]; @@ -79,12 +80,7 @@ export const label = { ["literal", ["Metropolis Regular Italic"]], ["literal", ["Metropolis Light"]], ], - "text-field": [ - "concat", - ["get", "name:latin"], - " ", - ["get", "name:nonlatin"], - ], + "text-field": Label.legacyLocalizedName, "text-max-angle": 20, "symbol-placement": "line", "text-size": [