Skip to content

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 fallback
  • name:de, name:fr, name:ja, … — per-language

The expression below picks the requested language, falls back to romanized, then to local.

Apply

js
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.

GroupCodes
Western Europeanen, de, fr, es, pt, pt-BR, it, nl, nl-BE, ca, gl, eu, ga, cy, gd, oc
Nordicsv, da, no, nb, nn, fi, is, fo, se
Central Europeanpl, cs, sk, hu, ro, sl, hr, bs, sr, sr-Latn, mk, sq
Eastern Europeanru, uk, be, lt, lv, et
Balkans / Greekbg, el
Turkic / Caucasiantr, az, kk, ky, uz, tk, hy, ka, ce
Middle Eastar, fa, ps, he, ku, ckb
South Asianhi, bn, ur, pa, gu, ta, te, kn, ml, mr, si, ne
East Asianzh, zh-Hans, zh-Hant, zh-HK, zh-TW, ja, ko
Southeast Asianth, vi, id, ms, tl, km, lo, my
Africanam, sw, af, zu, xh, st, tn, ts, ss, ve, nr, ha, yo, ig, so, om
Universal fallbackname: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:

js
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.

js
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):

js
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.