Skip to content

Proper way for translating background map text labels #217

Description

@bastianolea

I was trying to translate a {mapgl} MapLibre map's continent/country/city labels, following these instructions, but could not make it work:

library(mapgl)

# Expresión que toma el nombre en español y, si no existe, usa el nombre por defecto
etiqueta_es <- list("coalesce", list("get", "name:es"), list("get", "name"))

maplibre(
  style = carto_style("dark-matter"),
  attributionControl = FALSE,
  minZoom = 2,
  maxZoom = 11
) |>
  set_layout_property(
    layer_id = "place_country_1",
    name = "text-field",
    value = etiqueta_es
  ) |>
  set_layout_property(
    layer_id = "place_country_2",
    name = "text-field",
    value = etiqueta_es
  ) |>
  # Opcional: continente y estados/provincias también en español
  set_layout_property(
    layer_id = "place_continent",
    name = "text-field",
    value = etiqueta_es
  ) |>
  set_layout_property(
    layer_id = "place_state",
    name = "text-field",
    value = etiqueta_es
  )

After some fiddling, documentation reading, and help from Posit Assistant, I was able to translate the base map into Spanish using the following function:

library(mapgl)

#' Translate map labels to a different language
#'
#' Rewrites the `text-field` layout property of label layers in a MapLibre /
#' Mapbox style so that place names are displayed in the requested language.
#' This works around the fact that setting `text-field` after the map has
#' rendered (via [set_layout_property()]) can fail to take effect when the
#' vector source loads asynchronously: instead, the style itself is modified
#' before the map is created.
#'
#' The style's vector tiles must expose localized name fields following the
#' OpenMapTiles convention (`name:es`, `name:fr`, ...). Carto basemaps
#' (e.g. `carto_style("dark-matter")`) and other OpenMapTiles-based styles
#' satisfy this. If a feature has no name in the requested language, the
#' default `name` field is used as a fallback.
#'
#' @param style Either a URL to a style JSON or an already-parsed style as a
#'   list (e.g. from [jsonlite::fromJSON()] with `simplifyVector = FALSE`).
#' @param language ISO language code used to build the localized name field,
#'   e.g. `"es"`, `"fr"`, `"pt"`, `"de"`.
#' @param source_layers Character vector of `source-layer` names whose symbol
#'   layers should be translated. Defaults to `"place"`, which covers country,
#'   continent, state and city labels in OpenMapTiles styles.
#'
#' @return The modified style as a list, ready to pass to [maplibre()] (or
#'   [mapboxgl()]) via the `style` argument.
#'
#' @examples
#' \dontrun{
#' maplibre(style = translate_labels(carto_style("dark-matter"), "es"))
#'
#' # Translate water and road labels too
#' maplibre(
#'   style = translate_labels(
#'     carto_style("positron"),
#'     language = "fr",
#'     source_layers = c("place", "water_name", "transportation_name")
#'   )
#' )
#' }
#'
#' @export
translate_labels <- function(style, language = "en", source_layers = "place") {
  if (is.character(style)) {
    style <- jsonlite::fromJSON(style, simplifyVector = FALSE)
  }
  
  # Use the localized name, falling back to the default name when missing
  text_field <- list(
    "coalesce",
    list("get", paste0("name:", language)),
    list("get", "name")
  )
  
  style$layers <- lapply(style$layers, function(layer) {
    is_label <- identical(layer$type, "symbol") &&
      !is.null(layer$`source-layer`) &&
      layer$`source-layer` %in% source_layers
    if (is_label) {
      layer$layout$`text-field` <- text_field
    }
    layer
  })
  
  style
}

maplibre(
  style = translate_labels(carto_style("dark-matter"), language = "es"),
  attributionControl = FALSE,
  minZoom = 2,
  maxZoom = 11
)

Now base map text appears in Spanish instead of english!

I was wondering if there was another proper method for translating base map text with {mapgl} that I missed, of if I did a mistake with set_layout_property(), or maybe this is missing functionality that could be improved with the proposed function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions