How to Localize a Map

API or service
Map Tiles + MapLibre GL
Task
Language preference → localized map labels
Examples
MapLibre GL
Difficulty
Intermediate
Time
10 min

Your application has users in one or more languages and needs map labels that match their language preference. With a style-based MapLibre map, label text is rendered from feature properties and can be changed without requesting a separate raster image for every language.

Localization is more than replacing every label. Some features may not have a name in the requested language, so the map needs a predictable fallback. The application should also preserve the chosen language when it changes the complete map style.

Plan map-label localization

Before changing label layers, decide:

  • Language code: Use the language selected in the application rather than assuming it from the browser on every map update.
  • Fallback order: Prefer name:<language>, then a broadly readable name such as name:latin, and finally the default name value.
  • Affected layers: Change text layers that display geographic names. Do not overwrite symbol layers used only for route shields, house numbers, or application data.
  • Style changes: Reapply localization after calling map.setStyle(), because the new style creates a new set of basemap layers.
  • Scripts and fonts: Test languages with non-Latin and right-to-left scripts and ensure that the style’s glyphs and renderer support them.

Raster map labels are part of the tile image and cannot be changed by MapLibre or Leaflet after the tile is downloaded. Use a style-based map when runtime label localization is required.

Localize and switch map labels with MapLibre GL

The function below finds symbol layers whose text expression refers to a name and replaces their text field with a localized expression. coalesce keeps a readable fallback when a translation is missing.

function localizeMap(language) {
  const localizedName = [
    "coalesce",
    ["get", `name:${language}`],
    ["get", "name:latin"],
    ["get", "name"]
  ];

  for (const layer of map.getStyle().layers) {
    const textField = layer.layout?.["text-field"];
    const displaysName = JSON.stringify(textField || "").includes("name");

    if (layer.type === "symbol" && textField && displaysName) {
      map.setLayoutProperty(layer.id, "text-field", localizedName);
    }
  }
}

map.on("load", () => localizeMap("de"));

document.querySelector("#map-language").addEventListener("change", event => {
  localizeMap(event.target.value);
});

The language selector can provide codes such as en, de, fr, or uk. If the application also switches full styles, call localizeMap() again from the new style’s style.load event.

Review the selected style’s label layers before production use. A product may intentionally keep international names for some layers while localizing cities, streets, and points of interest.