Change the Map Language
Every Maptoolkit community style ships as a set of stylesheets — one with local place names, plus one per translation, for example summer.json (local names) and summer-en.json (English names). This map lets you switch the language of every place label — cities, water bodies, POIs, peaks — anywhere in the world, by loading the matching stylesheet with map.setStyle(). All 7 styles (summer, light, hiking, winter, dark, street, cycling) follow this same <style>-<language>.json naming.
import { MaptoolkitLogoControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-gl-logo/+esm';
const LANGUAGES = [
{ label: 'Local', code: null },
{ label: 'العربية', code: 'ar' },
{ label: 'čeština', code: 'cs' },
{ label: 'Deutsch', code: 'de' },
{ label: 'English', code: 'en' },
{ label: 'Español', code: 'es' },
{ label: 'Français', code: 'fr' },
{ label: 'हिन्दी', code: 'hi' },
{ label: 'Magyar', code: 'hu' },
{ label: 'Italiano', code: 'it' },
{ label: '日本語', code: 'ja' },
{ label: '한국어', code: 'ko' },
{ label: 'Polski', code: 'pl' },
{ label: '中文', code: 'zh' }
];
// Every style is published per language, e.g. summer.json (local names) and
// summer-en.json (English names). The same <style>-<language>.json naming
// applies to all 7 Maptoolkit styles, so swap styleBase to switch this map
// to light, hiking, winter, dark, street, or cycling.
const styleBase = 'https://styles.maptoolkit.org/summer';
function styleUrl(code) {
return code ? `${styleBase}-${code}.json` : `${styleBase}.json`;
}
const map = new maplibregl.Map({
container: 'map', attributionControl: { customAttribution: '' },
style: styleUrl(null),
center: [17.71561, 47.64616], zoom: 3.6, bearing: 0, pitch: 0
});
function applyLanguage(code) {
map.setStyle(styleUrl(code));
}
// Dropdown UI: a trigger button showing the current language, and a panel
// listing every language with the stylesheet it loads.
(function initLangDropdown() {
const root = document.getElementById('mapLang');
const trigger = root.querySelector('.map-lang-trigger');
const panel = root.querySelector('.map-lang-panel');
const current = root.querySelector('.map-lang-current');
LANGUAGES.forEach(function (lang, i) {
const opt = document.createElement('button');
opt.type = 'button';
opt.className = 'map-lang-option' + (i === 0 ? ' active' : '');
opt.role = 'option';
opt.innerHTML = '<span></span><span class="map-lang-field"></span>';
opt.children[0].textContent = lang.label;
opt.children[1].textContent = styleUrl(lang.code).split('/').pop();
opt.addEventListener('click', function () {
current.textContent = lang.label;
panel.querySelectorAll('.map-lang-option').forEach(function (o) { o.classList.toggle('active', o === opt); });
root.classList.remove('open');
trigger.setAttribute('aria-expanded', 'false');
applyLanguage(lang.code);
});
panel.appendChild(opt);
});
trigger.addEventListener('click', function (e) {
e.stopPropagation();
const open = root.classList.toggle('open');
trigger.setAttribute('aria-expanded', String(open));
});
document.addEventListener('click', function (e) {
if (!root.contains(e.target)) {
root.classList.remove('open');
trigger.setAttribute('aria-expanded', 'false');
}
});
})();
map.addControl(new MaptoolkitLogoControl());<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/maplibre-gl.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/maplibre-gl.css" />
<style>
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
#map { width: 100%; height: 100%; }
.map-lang { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1; font: 13px/1.2 system-ui, sans-serif; }
.map-lang-trigger {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 10px; background: #fff; border: none; border-radius: 6px;
font-weight: 700; font-size: 13px; color: #222; cursor: pointer;
box-shadow: 0 1px 4px rgba(0,0,0,.3);
}
.map-lang-caret { width: 12px; height: 12px; color: #888; transition: transform .15s; }
.map-lang.open .map-lang-caret { transform: rotate(180deg); }
.map-lang-panel {
position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%); min-width: 170px;
background: #fff; border-radius: 8px; padding: 4px;
box-shadow: 0 4px 14px rgba(0,0,0,.3);
display: none; max-height: 280px; overflow-y: auto;
}
.map-lang.open .map-lang-panel { display: block; }
.map-lang-option {
display: flex; justify-content: space-between; align-items: center; width: 100%;
background: transparent; border: none; padding: 6px 10px; border-radius: 6px;
font-size: 12.5px; color: #222; cursor: pointer; text-align: left; gap: 16px;
}
.map-lang-option:hover { background: #f1f1f1; }
.map-lang-option.active { background: #1a73e8; color: #fff; }
.map-lang-option .map-lang-field { font-family: ui-monospace, monospace; font-size: 11px; color: #888; }
.map-lang-option.active .map-lang-field { color: rgba(255,255,255,.7); }
</style>
</head>
<body>
<div class="map-lang" id="mapLang">
<button class="map-lang-trigger" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="map-lang-current">Local</span>
<svg class="map-lang-caret" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</button>
<div class="map-lang-panel" role="listbox"></div>
</div>
<div id="map"></div>
<script type="module">
import { MaptoolkitLogoControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-gl-logo/+esm';
const LANGUAGES = [
{ label: 'Local', code: null },
{ label: 'العربية', code: 'ar' },
{ label: 'čeština', code: 'cs' },
{ label: 'Deutsch', code: 'de' },
{ label: 'English', code: 'en' },
{ label: 'Español', code: 'es' },
{ label: 'Français', code: 'fr' },
{ label: 'हिन्दी', code: 'hi' },
{ label: 'Magyar', code: 'hu' },
{ label: 'Italiano', code: 'it' },
{ label: '日本語', code: 'ja' },
{ label: '한국어', code: 'ko' },
{ label: 'Polski', code: 'pl' },
{ label: '中文', code: 'zh' }
];
// Every style is published per language, e.g. summer.json (local names) and
// summer-en.json (English names). The same <style>-<language>.json naming
// applies to all 7 Maptoolkit styles, so swap styleBase to switch this map
// to light, hiking, winter, dark, street, or cycling.
const styleBase = 'https://styles.maptoolkit.org/summer';
function styleUrl(code) {
return code ? `${styleBase}-${code}.json` : `${styleBase}.json`;
}
const map = new maplibregl.Map({
container: 'map', attributionControl: { customAttribution: '' },
style: styleUrl(null),
center: [17.71561, 47.64616], zoom: 3.6, bearing: 0, pitch: 0
});
function applyLanguage(code) {
map.setStyle(styleUrl(code));
}
// Dropdown UI: a trigger button showing the current language, and a panel
// listing every language with the stylesheet it loads.
(function initLangDropdown() {
const root = document.getElementById('mapLang');
const trigger = root.querySelector('.map-lang-trigger');
const panel = root.querySelector('.map-lang-panel');
const current = root.querySelector('.map-lang-current');
LANGUAGES.forEach(function (lang, i) {
const opt = document.createElement('button');
opt.type = 'button';
opt.className = 'map-lang-option' + (i === 0 ? ' active' : '');
opt.role = 'option';
opt.innerHTML = '<span></span><span class="map-lang-field"></span>';
opt.children[0].textContent = lang.label;
opt.children[1].textContent = styleUrl(lang.code).split('/').pop();
opt.addEventListener('click', function () {
current.textContent = lang.label;
panel.querySelectorAll('.map-lang-option').forEach(function (o) { o.classList.toggle('active', o === opt); });
root.classList.remove('open');
trigger.setAttribute('aria-expanded', 'false');
applyLanguage(lang.code);
});
panel.appendChild(opt);
});
trigger.addEventListener('click', function (e) {
e.stopPropagation();
const open = root.classList.toggle('open');
trigger.setAttribute('aria-expanded', String(open));
});
document.addEventListener('click', function (e) {
if (!root.contains(e.target)) {
root.classList.remove('open');
trigger.setAttribute('aria-expanded', 'false');
}
});
})();
map.addControl(new MaptoolkitLogoControl());
</script>
</body>
</html>