Following the multilingual support (Japanese, Hiragana, English) added to the historical map service “Rekichizu,” this article introduces how to implement a map with language switching using MapLibre GL JS.

What is Rekichizu?

Rekichizu is a web service that lets you browse maps of the late Edo period (around 1800-1840) in a modern design. Multilingual support was added in November 2025, and the following three styles are provided.

LanguageStyle URL
Japanesehttps://mierune.github.io/rekichizu-style/styles/street/style.json
Hiraganahttps://mierune.github.io/rekichizu-style/styles/street/style_hira.json
Englishhttps://mierune.github.io/rekichizu-style/styles/street/style_en.json

Simple HTML Version

Here is an example implemented with plain HTML + JavaScript without any framework. The display language is switched based on a GET parameter (?lang=en).

Complete HTML File

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>れきちず 多言語対応デモ</title>
  <script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
  <link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: sans-serif; }
    #map { width: 100%; height: calc(100vh - 50px); }
    .controls {
      height: 50px;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      background: #f5f5f5;
      border-bottom: 1px solid #ddd;
    }
    .lang-btn {
      padding: 8px 16px;
      border: 1px solid #ccc;
      border-radius: 4px;
      background: white;
      cursor: pointer;
      font-size: 14px;
      transition: all 0.2s;
    }
    .lang-btn:hover { background: #e0e0e0; }
    .lang-btn.active {
      background: #2196F3;
      color: white;
      border-color: #2196F3;
    }
  </style>
</head>
<body>
  <div class="controls">
    <button class="lang-btn" data-lang="ja">日本語</button>
    <button class="lang-btn" data-lang="ja-Hira">ひらがな</button>
    <button class="lang-btn" data-lang="en">English</button>
  </div>
  <div id="map"></div>

  <script>
    // れきちずのスタイルURL
    const STYLES = {
      'ja': 'https://mierune.github.io/rekichizu-style/styles/street/style.json',
      'ja-Hira': 'https://mierune.github.io/rekichizu-style/styles/street/style_hira.json',
      'en': 'https://mierune.github.io/rekichizu-style/styles/street/style_en.json'
    };

    // GETパラメータから言語を取得
    function getLangFromUrl() {
      const params = new URLSearchParams(window.location.search);
      const lang = params.get('lang');
      return STYLES[lang] ? lang : 'ja'; // デフォルトは日本語
    }

    // 現在の言語
    let currentLang = getLangFromUrl();

    // 地図を初期化
    const map = new maplibregl.Map({
      container: 'map',
      style: STYLES[currentLang],
      center: [139.7671, 35.6812], // 東京駅
      zoom: 12
    });

    map.addControl(new maplibregl.NavigationControl(), 'top-right');

    // ボタンのアクティブ状態を更新
    function updateButtons() {
      document.querySelectorAll('.lang-btn').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.lang === currentLang);
      });
    }

    // URLを更新(履歴に追加)
    function updateUrl(lang) {
      const url = new URL(window.location);
      url.searchParams.set('lang', lang);
      window.history.pushState({}, '', url);
    }

    // 言語切り替え
    function switchLang(lang) {
      if (lang === currentLang) return;

      currentLang = lang;
      map.setStyle(STYLES[lang]);
      updateUrl(lang);
      updateButtons();
    }

    // ボタンのクリックイベント
    document.querySelectorAll('.lang-btn').forEach(btn => {
      btn.addEventListener('click', () => switchLang(btn.dataset.lang));
    });

    // ブラウザの戻る/進むに対応
    window.addEventListener('popstate', () => {
      const lang = getLangFromUrl();
      if (lang !== currentLang) {
        currentLang = lang;
        map.setStyle(STYLES[lang]);
        updateButtons();
      }
    });

    // 初期状態を設定
    updateButtons();
  </script>
</body>
</html>

Usage

  1. Serve the HTML file via a web server (it will not work as a local file)
  2. Access examples:
    • index.html - Japanese (default)
    • index.html?lang=en - English
    • index.html?lang=ja-Hira - Hiragana

Key Points

Getting the GET parameter

const params = new URLSearchParams(window.location.search);
const lang = params.get('lang'); // 'en', 'ja-Hira', or null

Updating the URL (without page navigation)

const url = new URL(window.location);
url.searchParams.set('lang', 'en');
window.history.pushState({}, '', url); // Add to history

Handling browser back/forward

window.addEventListener('popstate', () => {
  // Re-read language from URL and update the map
});

Notes

Layer Re-configuration on Style Switch

When map.setStyle() is called, all added sources and layers are reset. Therefore, you need to listen for the style.load event and re-configure them.

map.setStyle(STYLES[lang]);

// Important: Re-configure layers after style loads
map.once('style.load', () => {
  setupLayers();
});

Data Usage

Rekichizu tile data and styles are available under CC BY-NC-ND 4.0. For commercial use, please contact the Rekichizu operator (MIERUNE, Inc.).

Summary

  • Rekichizu provides three styles: Japanese, Hiragana, and English
  • Specify the language via GET parameter (?lang=en)
  • Dynamically switch styles with map.setStyle()
  • After style change, re-configure layers on the style.load event

By combining historical maps with multilingual support, you can create applications that allow people from overseas to enjoy Japan’s historical place names and routes.