Skip to content

Commit

Permalink
Localise error messages (#258)
Browse files Browse the repository at this point in the history
* localise error messages

* Add tests

* default to the english string, not the key

* Disallow invalid keys

* Add test for missing translation

* Add changelog entry
  • Loading branch information
awesomephant authored Feb 17, 2025
1 parent fa392f1 commit 583a96a
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Migrate unit tests to Vitest https://github.com/maplibre/maplibre-gl-geocoder/pull/238
- Make the `reverseGeocode` field in `MaplibreGeocoderAPI` optional https://github.com/maplibre/maplibre-gl-geocoder/pull/245
- Localise error messages https://github.com/maplibre/maplibre-gl-geocoder/pull/258

### Bug fixes 🐛

Expand Down
33 changes: 13 additions & 20 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {EventEmitter} from "events";
import type {Marker, Popup, Map, FlyToOptions, MarkerOptions, default as MaplibreGl} from "maplibre-gl";

import {exceptions} from "./exceptions";
import {placeholder as localization} from "./localization";
import localization from "./localization";

/**
* A regular expression to match coordinates.
Expand Down Expand Up @@ -1052,13 +1052,14 @@ export default class MaplibreGeocoder {

_renderError() {
const errorMessage =
"<div class='maplibre-gl-geocoder--error'>There was an error reaching the server</div>";
`<div class='maplibre-gl-geocoder--error'>${this._localize("errorConnectionFailed")}</div>`;
this._renderMessage(errorMessage);
}

_renderNoResults() {
const errorMessage =
"<div class='maplibre-gl-geocoder--error maplibre-gl-geocoder--no-results'>No results found</div>";
`<div class='maplibre-gl-geocoder--error maplibre-gl-geocoder--no-results'>
${this._localize("errorNoResults")}</div>`;
this._renderMessage(errorMessage);
}

Expand All @@ -1070,23 +1071,15 @@ export default class MaplibreGeocoder {
}

/**
* Get the text to use as the search bar placeholder
* Get a localised string for a given key
*
* If placeholder is provided in options, then use options.placeholder
* Otherwise, if language is provided in options, then use the localized string of the first language if available
* Otherwise use the default
*
* @returns the value to use as the search bar placeholder
*/
private _getPlaceholderText(): string {
if (this.options.placeholder) return this.options.placeholder;
if (this.options.language) {
const firstLanguage = this.options.language.split(",")[0];
const language = subtag.language(firstLanguage);
const localizedValue = localization[language];
if (localizedValue) return localizedValue;
}
return "Search";
* If language is provided in options, attempt to return localized string (defaults to English)
* @param key - key in the localization object
* @returns localized string
*/
private _localize(key: keyof typeof localization): string {
const language = subtag.language(this.options.language.split(',')[0]);
return this.options.language && localization?.[key][language] ? localization[key][language] : localization[key]['en']
}

/**
Expand Down Expand Up @@ -1245,7 +1238,7 @@ export default class MaplibreGeocoder {
* @param placeholder - the text to use as the input element's placeholder
*/
setPlaceholder(placeholder?: string): this {
this.placeholder = placeholder ? placeholder : this._getPlaceholderText();
this.placeholder = placeholder ? placeholder : this.options.placeholder || this._localize("placeholder");
this._inputEl.placeholder = this.placeholder;
this._inputEl.setAttribute("aria-label", this.placeholder);
return this;
Expand Down
14 changes: 12 additions & 2 deletions lib/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,20 @@ const placeholder = {
'fi': 'Hae',//finnish
'is': 'Leita',//icelandic
'ko': '수색',//korean
'pl': 'Szukaj', //polish
'pl': 'Szukaj', //polish
'sl': 'Iskanje', //slovenian
'fa': 'جستجو', //persian(aka farsi)
'ru': 'Поиск'//russian
}

export {placeholder};
const errorNoResults = {
'en': 'No results found',
'de': 'Keine Ergebnisse gefunden'
}

const errorConnectionFailed = {
'en': 'There was an error reaching the server',
'de': 'Verbindung fehlgeschlagen'
}

export default { placeholder, errorNoResults, errorConnectionFailed };
30 changes: 30 additions & 0 deletions test/unit/geocoder.ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,36 @@ describe("Geocoder#inputControl", () => {
expect(map.getContainer().querySelector(".maplibregl-ctrl-geocoder input").placeholder).toBe("Suche");
}
);

test("placeholder localization defaults to English when translation is missing",() => {
setup({ language: "non_existant_language" });
expect(map.getContainer().querySelector(".maplibregl-ctrl-geocoder input").placeholder).toBe("Search");
}
);

test("error message localization", async () => {
setup({language: "de-DE"});
const resultsPromise = geocoder.once("results");
geocoder.query("non_existant_place")
await resultsPromise
expect(map.getContainer().querySelector(".maplibre-gl-geocoder--error").textContent.trim()).toBe("Keine Ergebnisse gefunden");
});

test("error message localization with more than one language specified", async () => {
setup({language: "de-DE,lv,fr"});
const resultsPromise = geocoder.once("results");
geocoder.query("non_existant_place")
await resultsPromise
expect(map.getContainer().querySelector(".maplibre-gl-geocoder--error").textContent.trim()).toBe("Keine Ergebnisse gefunden");
});

test("error message localization defaults to English when translation is missing", async () => {
setup({language: "non_existant_language"});
const resultsPromise = geocoder.once("results");
geocoder.query("non_existant_place")
await resultsPromise
expect(map.getContainer().querySelector(".maplibre-gl-geocoder--error").textContent.trim()).toBe("No results found");
});

test("clear is not called on keydown (tab), no focus trap", () => {
setup({});
Expand Down

0 comments on commit 583a96a

Please sign in to comment.