ソースコード解説・目次

CHAPTER 19 · 全23項目

日本語・英語と設定の保存

文言を辞書に集め、CanvasとHTMLの表示をまとめて切り替えます。

主な参照先:STRINGS / detectLang / T / applyLang / localStorage

アドレスの指定と保存済みの設定を優先する

game.html · L172–184ソースを見る ↗
function detectLang() {
  // 共有された ?lang=en などのアドレスで開いた時は、その言語を保存した設定より優先する(保存はしない)。
  try {
    const asked = /[?&]lang=([a-z]+)/.exec(location.search)?.[1];
    if (Object.hasOwn(STRINGS, asked)) return asked;
  } catch (e) {}
  try {
    const saved = localStorage.getItem(LANG_KEY);
    if (Object.hasOwn(STRINGS, saved)) return saved;
  } catch (e) {}
  const tag = typeof navigator !== "undefined" ? String(navigator.language || "") : "";
  return tag.toLowerCase().startsWith("ja") ? "ja" : "en";
}

アドレスに ?lang=en などが付いていて、その言語が辞書にあれば、それを最優先にします(共有された英語のリンクから開いた場合など。保存はしません)。次に、ブラウザに保存した値が辞書に存在すればそれを採用します。保存値がなければブラウザの言語を調べ、ja で始まれば日本語、それ以外は英語です。ストレージが使えなくても検出処理を続けます。

固定文言も、値を埋め込む文言も同じ入口にする

game.html · L189–192ソースを見る ↗
function T(key, ...args) {
  const v = STRINGS[lang][key];
  return typeof v === "function" ? v(...args) : v;
}

STRINGS の値は、普通の文字列だけでなく関数にもできます。ゲージや残数、ボスのレベルを埋め込む文言は関数にし、T() が必要な引数を渡します。呼び出し元は文字列か関数かを意識する必要がありません。操作説明の hint は4行分の配列で、applyLang() が改行タグでつないで表示します。

切り替えるときに更新するもの

game.html · L1326–1343ソースを見る ↗
function applyLang(next) {
  if (next && next !== lang) {
    lang = next;
    try { localStorage.setItem(LANG_KEY, lang); } catch (e) {}
  }
  if (document.documentElement) document.documentElement.lang = lang;
  const hintEl = document.getElementById("hint");
  if (hintEl) hintEl.innerHTML = T("hint").join("<br>");
  const shareEl = document.getElementById("shareLink");
  if (shareEl) {
    const share = SHARE[lang];
    shareEl.href = `https://x.com/intent/post?text=${encodeURIComponent(share.text)}&url=${encodeURIComponent(share.url)}`;
    document.getElementById("shareLabel").textContent = share.label;
  }
  for (const code in langButtons) langButtons[code].setAttribute("aria-pressed", String(code === lang));
  refreshActionButtons();
  redrawIfPaused();
}

HTMLの言語属性、操作説明、X への投稿リンク、言語ボタンの aria-pressed、必殺技ボタンを更新します。投稿リンクは、日本語ではゲーム本体の game.html を、英語では英語のカード画像を出す入口ページ game.en.html を共有します。game.en.html は開くとすぐ ?lang=en 付きの game.html へ移ります。リンクの文言と URL は画面に描く文言ではないので、STRINGS とは別の SHARE にまとめています。Canvasは通常なら次のフレームで描き直されますが、ポーズ中はループが止まるため redrawIfPaused() で即座に更新します。

保存キー内容
astro-defender-lang選択した表示言語
astro-defender-mutedミュートの有無
astro-defender-hiscoreハイスコア