Search for content

Creating a Localized Map App

In this tutorial we extend the Map App code sample to display a localized map based on vector tiles from PTV Developer.

 

Showing a localized map in a browser

All supported languages are listed in the Languages concept. Localized labels are available for countries, states, cities, roads, buildings and backgrounds. This example will show how to display multi names by displaying two lines with the localized label and the original label below.

HTML code

As an example we provide a simple index.html file where we instantiate the MapLibre renderer and set the displayed language. Use MARC country codes in lower case to display the desired language:

<!DOCTYPE html>
<html>
<head>
   <meta charset='utf-8' />
   <title>MapLibre GL JS Examples</title>
   <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
   <script type="text/javascript" src="https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.js"></script>
   <link rel="stylesheet" type="text/css" href="https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.css">
   <style>
       body { margin:0; padding:0; }
       #map { position:absolute; top:0; bottom:0; width:100%; }
   </style>
</head>
<body>
<div id='map'></div>
<script>
     maplibregl.setRTLTextPlugin(
   'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-rtl-text/v0.2.3/mapbox-gl-rtl-text.js',
   null,
   true // Lazy load the plugin
   );
   var apiKey = 'YOUR_API_KEY';
   var map = new maplibregl.Map({
       // You need a customAttribution if you do not use map styles provided by PTV or if you have to add additional copyright attribution.
       // attributionControl: true,
       // customAttribution: '©2023, PTV Group, HERE',
       container: 'map',
       zoom: 11,
       pitch: 0,
       minZoom: 2,
       center: [8.4055677, 49.0070036],
       antialias: true,
       hash: true,
       // you can also use your own style "https://<your_servername>/style.json"
       style: "https://vectormaps-resources.myptv.com/styles/latest/standard.json",
       transformRequest: (url, resourceType) => {
           if (resourceType === 'Tile' && url.startsWith('https://api.myptv.com')) {
               return {
                   url: url + '?apiKey=' + apiKey
               }
           }
       }
   });
   map.addControl(new maplibregl.NavigationControl());
    var showMultiNames = true;
   //use the desired language code based on MARC country codes in lower case.
   //a list of supported languages can be found here: https://developer.myptv.com/Documentation/Vector%20Maps%20API/Concepts/Languages.htm
   var language = "eng";
   map.on('styledata', function() {
       alterNames();
   });
  function setMapProperty(labelName)
   {
        map.setLayoutProperty(labelName, 'text-field',
                   ['case',
                   ['==', ['get', 'country_language_code'], ['upcase', language]],
                   ['get', 'name'],
                   ['==', ['get', 'name'], ['get','name_' + language]], // if names are same, show only one
                   ['get', 'name'],
                   ['==', ['get','name_' + language], null], //
                   ['case',
                       ['!=', ['get','name_trans'], null],
                       ['format',
                           ['get','name_trans'],
                           { 'font-scale': 1.0 },
                           '\n',
                           ['get', 'name'],
                           { 'font-scale': 0.8, 'text-font': ['literal', ['Noto Sans Italic']] }
                       ],
                       ['get', 'name']
                   ],
                   ['!=', ['get','name_' + language], null],
                   ['format',
                           ['get','name_' + language],
                           { 'font-scale': 1.0 },
                           '\n',
                           ['get', 'name'],
                           { 'font-scale': 0.8, 'text-font': ['literal', ['Noto Sans Italic']] }
                   ],
                   ['get', 'name']]);  // fallback
   }

   function alterNames()
   {
       // Use setLayoutProperty to set the value of a layout property in a style layer.
       // The three arguments are the id of the layer, the name of the layout property,
       // and the new property value.
       if(language == "nat")
       {
           map.setLayoutProperty('LBL_Country_Big',    'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_Country_Medium', 'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_Country_Small',  'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_State',  'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorCapital',   'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorCapital',   'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorVeryLarge', 'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorVeryLarge', 'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorLarge',     'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorLarge',     'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorMedium',    'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorMedium',    'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorSmall',     'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorSmall',     'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMajorVillage',   'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_CityMinorVillage',   'text-field', ['get', 'name']);
           map.setLayoutProperty('LBL_Hamlet',             'text-field', ['get', 'name']);

           map.setLayoutProperty('TSP_RoadResidential_Label', 'text-field', ['get', 'street_name']);
           map.setLayoutProperty('TSP_RoadLocal_Label',       'text-field', ['get', 'street_name']);
           map.setLayoutProperty('TSP_RoadArterial_Label',    'text-field', ['get', 'street_name']);
           map.setLayoutProperty('TSP_RoadFederal_Label',     'text-field', ['get', 'street_name']);
           map.setLayoutProperty('TSP_RoadHighway_Label',     'text-field', ['get', 'street_name']);
           map.setLayoutProperty('TSP_RoadFerry_Label',       'text-field', ['get', 'ferry_name']);
       }
       else if(language == "trans")
       {
           map.setLayoutProperty('TSP_RoadResidential_Label', 'text-field', ['coalesce',['get','street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadLocal_Label',       'text-field', ['coalesce',['get','street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadArterial_Label',    'text-field', ['coalesce',['get','street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadFederal_Label',     'text-field', ['coalesce',['get','street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadHighway_Label',     'text-field', ['coalesce',['get','street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadFerry_Label',       'text-field', ['coalesce',['get','ferry_name_trans'],['get', 'ferry_name']]);
           map.setLayoutProperty('LBL_CityMajorCapital',   'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorCapital',   'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMajorVeryLarge', 'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorVeryLarge', 'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMajorLarge',     'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorLarge',     'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMajorMedium',    'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorMedium',    'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMajorSmall',     'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorSmall',     'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMajorVillage',   'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_CityMinorVillage',   'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_Hamlet',             'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);

           map.setLayoutProperty('LBL_Country_Big',    'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_Country_Medium', 'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_Country_Small',  'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_State',  'text-field', ['coalesce',['get','name_trans'],['get', 'name']]);
       }
       else
       {
           if(showMultiNames)
           {
               setMapProperty('LBL_CityMajorCapital');
               setMapProperty('LBL_CityMinorCapital');
               setMapProperty('LBL_CityMajorVeryLarge');
               setMapProperty('LBL_CityMinorVeryLarge');
               setMapProperty('LBL_CityMajorLarge');
               setMapProperty('LBL_CityMinorLarge');
               setMapProperty('LBL_CityMajorMedium');
               setMapProperty('LBL_CityMinorMedium');
               setMapProperty('LBL_CityMajorSmall');
               setMapProperty('LBL_CityMinorSmall');
               setMapProperty('LBL_CityMajorVillage');
               setMapProperty('LBL_CityMinorVillage');
               setMapProperty('LBL_Hamlet');
           }
           else
           {
               map.setLayoutProperty('LBL_CityMajorCapital',   'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorCapital',   'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMajorVeryLarge', 'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorVeryLarge', 'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMajorLarge',     'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorLarge',     'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMajorMedium',    'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorMedium',    'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMajorSmall',     'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorSmall',     'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMajorVillage',   'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_CityMinorVillage',   'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);
               map.setLayoutProperty('LBL_Hamlet',             'text-field', ['coalesce',['get','name_' + language],['get', 'name_trans'],['get', 'name']]);

           }
           map.setLayoutProperty('TSP_RoadResidential_Label', 'text-field', ['coalesce',['get','street_name_' + language],['get', 'street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadLocal_Label',       'text-field', ['coalesce',['get','street_name_' + language],['get', 'street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadArterial_Label',    'text-field', ['coalesce',['get','street_name_' + language],['get', 'street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadFederal_Label',     'text-field', ['coalesce',['get','street_name_' + language],['get', 'street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadHighway_Label',     'text-field', ['coalesce',['get','street_name_' + language],['get', 'street_name_trans'],['get', 'street_name']]);
           map.setLayoutProperty('TSP_RoadFerry_Label',       'text-field', ['coalesce',['get','ferry_name_'  + language],['get', 'ferry_name_trans' ],['get', 'ferry_name' ]]);
           map.setLayoutProperty('LBL_Country_Big',    'text-field', ['coalesce',['get','name_' + language],['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_Country_Medium', 'text-field', ['coalesce',['get','name_' + language],['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_Country_Small',  'text-field', ['coalesce',['get','name_' + language],['get','name_trans'],['get', 'name']]);
           map.setLayoutProperty('LBL_State',  'text-field', ['coalesce',['get','name_' + language],['get','name_trans'],['get', 'name']]);
       }
   }
   map.addControl(new maplibregl.GeolocateControl({
       positionOptions: {
       enableHighAccuracy: true
       },
       trackUserLocation: true
       })
   );
</script>
</body>
</html>