CHAPTER 19 · 全23項目
日本語・英語と設定の保存
文言を辞書に集め、CanvasとHTMLの表示をまとめて切り替えます。
主な参照先:STRINGS / detectLang / T / applyLang / localStorage
アドレスの指定と保存済みの設定を優先する
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 で始まれば日本語、それ以外は英語です。ストレージが使えなくても検出処理を続けます。
固定文言も、値を埋め込む文言も同じ入口にする
function T(key, ...args) {
const v = STRINGS[lang][key];
return typeof v === "function" ? v(...args) : v;
}STRINGS の値は、普通の文字列だけでなく関数にもできます。ゲージや残数、ボスのレベルを埋め込む文言は関数にし、T() が必要な引数を渡します。呼び出し元は文字列か関数かを意識する必要がありません。操作説明の hint は4行分の配列で、applyLang() が改行タグでつないで表示します。
切り替えるときに更新するもの
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 | ハイスコア |