Maplat UIで言語を切り替えてみる&表示状況の保持を実施してみる

最後も1日遅れになってしまいましたが、いよいよMaplat Advent Calendarも最終です。
今日は、Maplat UIで言語を切り替えてみます＆アプリを再初期化した際に表示状況を保持する方法を説明します。
今日の動くものはこちらでみられます。 => [Maplat Advent Calendar Day 25](https://codesandbox.io/s/maplat-advent-calendar-day25-kvuh7)

Maplat UIには多言語化の機能として、

* UIの言語切り替え（日本語`ja`、英語`en`、韓国語`ko`、中国語(繁体`zh-TW`、簡体`zh`)）に対応。<br>それ以外の言語は英語にフォールバック。
* コンテンツの言語切り替え（原理的には何語でもOK）に対応。<br>リソース提供されていない言語は英語、英語も提供されていなければデフォルト言語にフォールバック。
* 言語の検出はブラウザ設定から取得のほか、明示的に指定も可能。

が用意されています。
今回は、この明示的に言語を指定する機能を用いて、言語を切り替えてみます。

今回のコードは次のような感じです。

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Maplat Advent Calendar Day 25</title>
    <link rel="stylesheet" href="app.css" />
  </head>
  <body>
    <div class="mainview">
      <div id="map_div"></div>
    </div>
    <div class="button">
      <button id="ja">日本語</button>
      <button id="en">英語</button>
      <button id="ko">韓国語</button>
      <button id="zh">中国語（簡体）</button>
      <button id="zh-TW">中国語（繁体）</button>
    </div>
  </body>
  <script src="app.js"></script>
</html>
```

```app.js
import "@maplat/ui/dist/maplat.css";
import { MaplatUi } from "@maplat/ui";

var optionBase = {
  appid: "maplat_ac_day25"
};

let app;
let viewpoint;
function viewpointHandler(e) {
  viewpoint = e.detail;
}
function initApp(lang) {
  const optionAdd = {
    lang: lang,
    restore: viewpoint
  };
  const option = Object.assign(optionBase, optionAdd);
  if (app) {
    //app.core.removeEventListner("changeViewpoint", viewpointHandler);
    document.getElementById("map_div").innerHTML = "";
    app = undefined;
  } else {
    document.getElementById("ja").addEventListener("click", function(e) {
      initApp("ja");
    });
    document.getElementById("en").addEventListener("click", function(e) {
      initApp("en");
    });
    document.getElementById("ko").addEventListener("click", function(e) {
      initApp("ko");
    });
    document.getElementById("zh").addEventListener("click", function(e) {
      initApp("zh");
    });
    document.getElementById("zh-TW").addEventListener("click", function(e) {
      initApp("zh-TW");
    });
  }
  app = new MaplatUi(option);
  app.waitReady.then(function() {
    app.core.addEventListener("updateState", viewpointHandler);
  });
}
initApp("ja");
```

```app.css
.mainview {
  position: absolute;
  top: 5%;
  bottom: 5%;
  left: 5%;
  right: 5%;
}
.button {
  position: absolute;
  top: 95%;
  bottom: 0%;
  left: 5%;
  right: 5%;
}
```

```apps/maplat_ac_day25.json
{
  "app_name": {
    "ja": "まぷらっとあどべんとかれんだーでい２５",
    "en": "Maplat Advent Calendar Day25"
  },
  "home_position": [139.5321, 36.249302],
  "default_zoom": 17,
  "start_from": "tatebayashi_ojozu",
  "sources": [
    {
      "mapID": "tatebayashi_ojozu",
      "label": {
        "ja": "綱吉時代",
        "en": "Tsunayoshi Era"
      },
      "setting_file": "https://s.maplat.jp/r/tatebayashimap/maps/tatebayashi_ojozu.json"
    },
    {
      "mapID": "tatebayashi_castle_akimoto",
      "label": {
        "ja": "秋元時代",
        "en": "Akimoto Era"
      },
      "setting_file": "https://s.maplat.jp/r/tatebayashimap/maps/tatebayashi_castle_akimoto.json"
    },
    "osm",
    "gsi"
  ]
}
```
少し解説を加えます。

- 言語設定は、`app = new MaplatUi(option);`の、`options.lang`設定で行います。<br>
  アプリの初期化時にしか設定できない（途中で切り替え不可）ので、ボタンを押して言語を切り替えるたび、新しいMaplat UIインスタンスを生成して表示するアプローチにしています。
- ただ、毎回インスタンスを生成していると、言語が切り替わるたび地図の表示範囲が元の場所に移動しまって面白くありません。<br>そこで、表示状況が変わるたびに（`updateState`イベント）その表示状況を変数`viewpoint`に保持し、インスタンスを作る際の`options.restore`に与えてやることによって、直前の表示状況を引き継ぎながらインスタンスを生成するようにしました。
    - Maplatの表示状況変化通知イベントには、今回使った`updateState`イベントの他に`changeViewpoint`というイベントもあり、発火するタイミングはほぼ一緒ですが、目的が異なります。<br>`changeViewpoint`は表示領域の変化に合わせて何かそれに対する処理を行うイベントで、現在の地図の表示している経緯度、絵地図上のXY座標、地図のズーム、地図の上方向の方角、地図の回転角などその後の処理をさせるのに必要になりそうな情報がてんこ盛りで返されます。<br>それと比較して、`updateState`は表示状況を再現するために必要な情報だけが凝縮して、かつどの地図が選ばれていたかなど追加で必要な情報も加えられて通知され、その通知内容オブジェクトをそのままインスタンス生成時の`options.restore`に渡せば、表示状況回復ができるように設計されています。
- `maplat_ac_day25.json`の中で、`app_name`や各地図の`label`の値などを、日本語`ja`と英語`en`の値を与えて多言語コンテンツ化しています。<br>コンテンツで文字列で与えられる設定項目は、たいていは多言語化できるようにしていますので、試してみてください。

動作状況はこんな感じです。

![言語切り替え](https://t.tilemap.jp/maplat/ui_multilang.gif)
=> なぜか画像が埋め込めないので、こちらから表示してみてください => 
<a target="_blank" href="https://t.tilemap.jp/maplat/ui_multilang.gif">https://t.tilemap.jp/maplat/ui_multilang.gif</a>

さて、思いつきから25日間、Maplat一色でAdvent Calendarやってみましたが、いかがだったでしょうか。
こんなにMaplatについてドキュメント？書いたの初めてですが、多少はMaplatでどんなことができるか、イメージなど沸いたでしょうか。
他にもまだiOS/Android向けネイティブSDKなどあるので、まだまだ足りないのですが、その辺も追々ドキュメントできればいいなと思ってます。
来年も可能ならMaplat Advent Calendarに挑戦してみたいと思います。