80+ Language Map Labels
Switch label language at runtime with one MapLibre expression. No tile rebuild.
How it works
Every place / road / POI in our tiles carries up to ~80 localized name attributes:
name— primary (local language as tagged in OSM)name:latin— universal romanized fallbackname:de,name:fr,name:ja, … — per-language
The expression below picks the requested language, falls back to romanized, then to local.
Apply
function setLang(map, lang) {
['place_label', 'transportation_name', 'poi_label'].forEach(layer => {
map.setLayoutProperty(layer, 'text-field', [
'coalesce',
['get', `name:${lang}`],
['get', 'name:latin'],
['get', 'name']
]);
});
}
setLang(map, 'de');Supported codes
Full set (BCP-47 language tags). All present on tiles built v2 onwards.
| Group | Codes |
|---|---|
| Western European | en, de, fr, es, pt, pt-BR, it, nl, nl-BE, ca, gl, eu, ga, cy, gd, oc |
| Nordic | sv, da, no, nb, nn, fi, is, fo, se |
| Central European | pl, cs, sk, hu, ro, sl, hr, bs, sr, sr-Latn, mk, sq |
| Eastern European | ru, uk, be, lt, lv, et |
| Balkans / Greek | bg, el |
| Turkic / Caucasian | tr, az, kk, ky, uz, tk, hy, ka, ce |
| Middle East | ar, fa, ps, he, ku, ckb |
| South Asian | hi, bn, ur, pa, gu, ta, te, kn, ml, mr, si, ne |
| East Asian | zh, zh-Hans, zh-Hant, zh-HK, zh-TW, ja, ko |
| Southeast Asian | th, vi, id, ms, tl, km, lo, my |
| African | am, sw, af, zu, xh, st, tn, ts, ss, ve, nr, ha, yo, ig, so, om |
| Universal fallback | name:latin (always present), name:nonlatin |
If a place has no name in the requested language, MapLibre's coalesce falls back to name:latin, then to name. Result: never blank.
RTL languages
Arabic, Hebrew, Persian render right-to-left correctly. Enable the optional RTL plugin once, before creating the map:
maplibregl.setRTLTextPlugin(
'https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js',
null,
true
);CJK / vertical scripts
Japanese / Chinese / Korean render horizontally by default. Vertical text is not supported by MapLibre.
Mixed language UI
Common pattern: switch map language to match the user's UI locale.
map.on('styledata', () => setLang(map, document.documentElement.lang));Server-side
If you serve styles from your own server, bake the language into the style for delivery to MapLibre clients that can't run the expression switch (rare):
function styleForLanguage(baseStyle, lang) {
const out = structuredClone(baseStyle);
for (const layer of out.layers) {
if (layer.layout?.['text-field']) {
layer.layout['text-field'] = [
'coalesce',
['get', `name:${lang}`],
['get', 'name:latin'],
['get', 'name']
];
}
}
return out;
}Coverage
Coverage of each language varies by region — name:de exists for most German place names but only some Swahili, etc. The fallback chain handles this transparently.