From 67562dc2bb99578cec24572149631d73eec7b1aa Mon Sep 17 00:00:00 2001 From: Jonathan Lurie Date: Wed, 6 Nov 2024 13:58:29 +0100 Subject: [PATCH] more robust language switching --- CHANGELOG.md | 2 +- src/Map.ts | 27 ++++++++++++++++----------- src/tools.ts | 28 ++++++++++++++++++++++++++++ tsconfig.json | 4 ++-- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac4a0e3..eccd094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.4.2 ### Bug Fixes -- The language switching is now more robust and preserves the original formatting from the style (`Map.setPrimareyLangage()`) (https://github.com/maptiler/maptiler-sdk-js/pull/134) +- The language switching is now more robust and preserves the original formatting from the style (`Map.setPrimaryLangage()`) (https://github.com/maptiler/maptiler-sdk-js/pull/134) ## 2.4.1 ### Bug Fixes diff --git a/src/Map.ts b/src/Map.ts index 7485251..d182775 100644 --- a/src/Map.ts +++ b/src/Map.ts @@ -26,9 +26,11 @@ import { defaults } from "./defaults"; import { MaptilerLogoControl } from "./MaptilerLogoControl"; import { changeFirstLanguage, + checkNamePattern, combineTransformRequest, displayNoWebGlWarning, displayWebGLContextLostWarning, + replaceLanguage, } from "./tools"; import { getBrowserLanguage, Language, type LanguageInfo } from "./language"; import { styleToStyle } from "./mapstyle"; @@ -1127,19 +1129,22 @@ export class Map extends maplibregl.Map { // Testing the different case where the text-field property should NOT be updated: if (typeof textFieldLayoutProp === "string") { - // If the field is a string that DOES NOT contain an opening curly bracket. - // (This happens when the label is a hardcoded string that does not refer to a property) - if (!textFieldLayoutProp.includes("{")) { - continue; - } + const { contains, exactMatch } = checkNamePattern(textFieldLayoutProp); - // If the text field does not contain the "name" substring. - // This happens when dealing with {ref}, {housenumber}, {height}, etc. - if (!textFieldLayoutProp.includes("name")) { - continue; - } + // If the current text-fiels does not contain any "{name:xx}" pattern + if (!contains) continue; - this.setLayoutProperty(id, "text-field", replacer); + // In case of an exact match, we replace by an object representation of the label + if (exactMatch) { + this.setLayoutProperty(id, "text-field", replacer); + } else { + // In case of a non-exact match (such as "foo {name:xx} bar") + // we create a "concat" object expresion composed of the original elements with new replacer + // in-betweem + const newReplacer = replaceLanguage(textFieldLayoutProp, replacer); + + this.setLayoutProperty(id, "text-field", newReplacer); + } } // The value of text-field is an object diff --git a/src/tools.ts b/src/tools.ts index 8f7be33..2acbc3d 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -268,3 +268,31 @@ export function changeFirstLanguage( exploreNode(expr); return expr; } + +/** + * Tst if a string matches the pattern "{name:xx}" in a exact way or is a loose way (such as "foo {name:xx}") + */ +export function checkNamePattern(str: string): { contains: boolean; exactMatch: boolean } { + const regex = /\{name:[a-zA-Z]{2}\}/; + return { + contains: regex.test(str), + exactMatch: new RegExp(`^${regex.source}$`).test(str), + }; +} + +/** + * Replaces the occurences of {name:xx} in a string by a provided object-expression to return a concat object expression + */ +export function replaceLanguage( + origLang: string, + newLang: maplibregl.ExpressionSpecification, +): maplibregl.ExpressionSpecification { + const elementsToConcat = origLang.split(/\{name:[a-zA-Z]{2}\}/); + + const allElements = elementsToConcat.flatMap((item, i) => + i === elementsToConcat.length - 1 ? [item] : [item, newLang], + ); + + const expr = ["concat", ...allElements] as maplibregl.ExpressionSpecification; + return expr; +} diff --git a/tsconfig.json b/tsconfig.json index 879d3bb..14e795f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,10 @@ "compilerOptions": { "baseUrl": "src", "moduleResolution": "Node", - "target": "ES2020", + "target": "es2021", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["es2021", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */