diff --git a/examples/zh-HK.html b/examples/zh-HK.html new file mode 100644 index 0000000..618f8df --- /dev/null +++ b/examples/zh-HK.html @@ -0,0 +1,35 @@ + + + + + Mapbox GL Language + + + + + + + + +
+ + + + diff --git a/index.js b/index.js index 942ad48..a893f7f 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,12 @@ +/* accept lowercased values from common locale selectors */ +const ALT_LOCALES = { + 'zh-cn': 'zh-Hans', + 'zh-hk': 'zh-Hant', + 'zh-mo': 'zh-Hant', + 'zh-sg': 'zh-Hans', + 'zh-tw': 'zh-Hant', +}; + /** * Create a new [Mapbox GL JS plugin](https://www.mapbox.com/blog/build-mapbox-gl-js-plugins/) that * modifies the layers of the map style to use the `text-field` that matches the browser language. @@ -115,7 +124,15 @@ function findStreetsSource(style) { * @returns {object} the modified style */ MapboxLanguage.prototype.setLanguage = function (style, language) { - if (this.supportedLanguages.indexOf(language) < 0) throw new Error(`Language ${ language } is not supported`); + language = ALT_LOCALES[language.toLowerCase()] || language; + + while (this.supportedLanguages.indexOf(language) < 0) { + if (language.indexOf('-') > -1) { + language = language.slice(0, language.lastIndexOf('-')); + } else { + throw new Error(`Language ${ language } is not supported`); + } + } const streetsSource = this._languageSource || findStreetsSource(style); if (!streetsSource) return style; @@ -142,16 +159,18 @@ MapboxLanguage.prototype._initialStyleUpdate = function () { }; function browserLanguage(supportedLanguages) { - const language = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage); - const parts = language && language.split('-'); - let languageCode = language; - if (parts.length > 1) { - languageCode = parts[0]; - } - if (supportedLanguages.indexOf(languageCode) > -1) { - return languageCode; + let language = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage); + language = ALT_LOCALES[language.toLowerCase()] || language; + + while (supportedLanguages.indexOf(language) < 0) { + if (language.indexOf('-') > -1) { + // reduce longer locales (en-US, zh-Hant-TW) to shorter forms + language = language.slice(0, language.lastIndexOf('-')); + } else { + return null; + } } - return null; + return language; } MapboxLanguage.prototype.onAdd = function (map) { diff --git a/test/index.test.js b/test/index.test.js index 2349ae5..5ad0659 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -165,5 +165,40 @@ test('MapboxLanguage', (t) => { t.end(); }); + test('longer locales', (t) => { + const language = new MapboxLanguage(); + const layers = [{ + 'id': 'state-label-sm', + 'source': 'composite', + 'source-layer': 'state_label', + 'layout': { + 'text-letter-spacing': 0.15, + 'text-field': ['get', 'name'] + } + }]; + const style = makeStyle(layers); + + const enStyle = language.setLanguage(style, 'en-US'); + t.deepEqual(enStyle.layers[0].layout, { + 'text-letter-spacing': 0.15, + 'text-field': [ + 'coalesce', + ['get', 'name_en'], + ['get', 'name'] + ] + }, 'shorter locale name'); + + const zhStyle = language.setLanguage(style, 'zh-HK'); + t.deepEqual(zhStyle.layers[0].layout, { + 'text-letter-spacing': 0.15, + 'text-field': [ + 'coalesce', + ['get', 'name_zh-Hant'], + ['get', 'name'] + ] + }, 'zh hans/hant name'); + t.end(); + }); + t.end(); });