# Lowmoor 変更まとめ（1.5.2 → 1.6.0 → 1.6.1 → 1.6.3）

2026-08-22 作成。Steam が 1.6.0 を配信したのを受けて、旧版（`app.asar.en.bak` = 1.5.2）と
新版を突き合わせて調べた結果と、日本語化側で必要になった対応の記録。

---

## 1. 規模

| | 1.5.2 | 1.6.0 |
|---|---|---|
| `game/index.html` | 2.03 MB / 26,469 行 | **3.97 MB / 43,311 行** |
| トップレベル宣言 | 1,207 | **2,000**（+813、削除20） |
| セーブのスキーマ | v13 | **v17** |

**ゲーム本体がほぼ倍になっています。** 作者の言葉を借りれば
「An update too large for this window: the full patch notes are the v1.6.0 post on Steam」
（このウィンドウに収まらない規模の更新。完全なパッチノートは Steam の v1.6.0 投稿にある）。

ソース中のコメントには `v1.9.0` から `v2.10.0` までの内部版番号が散在しており、
Steam の「1.6.0」は作者の内部リリースを長期間ぶんまとめたものと読めます。

---

## 2. 作者のパッチノート（ゲーム内 PATCH_NOTES より、2026-08-21 付）

> **The Steam bundle: the fight on the die, a signature move for every trade, pets, feats and desks.**

- 戦闘がダイス判定になった。命中判定・ダメージダイス・ステータスブロックを持つ獣。装備は**4つの名前つき枠**に。
- 詠唱者は INT / WIS / CHA から戦う。**全職業に固有の必殺技**があり、その横の「＋」から強化を開く。
- **ペットが3種**（櫃・骨犬・蛭）。連れ歩けるのは1匹で、報酬もその1匹だけ。
- **功績は13個**になり、papers の枠は3。
- **雇い人が次の年代記にランクを持ち越す。** 需品係の庭が上限を上げる。
- 種族と職業の贈り物を作り直し。商店・名誉録・ギルドハウスがいずれも拡張。
- **設定にプレイスタイル切替と3種のデスク**が追加。

---

## 3. データ表の増減（実測）

| 表 | 1.5.2 | 1.6.0 | |
|---|---|---|---|
| モンスター | 179 | 179 | 変わらず（ただし**20種が入れ替わり**） |
| ボス | 31 | 31 | 変わらず |
| 実績 | 100 | 100 | 変わらず（Steam実績と1対1のため固定） |
| 功績（Feats） | 11 | **13** | +2 |
| ギルドハウス増築 | 8 | **13** | +5 |
| 名誉録の行 | 14 | **20** | +6 |
| 雇い人 / 祝祭日 / 呪文 / 技 | 21 / 10 / 32 / 19 | 同左 | 変わらず |

**入れ替わったモンスター20種**（1.5.2 には無かった名前）:

```
warren ratling / copy-thrall / lens-warden / loosed armature / roll-thrall
steam mephit / foundation-slough / blank warden / ground-drake / sum-taker
shale-lizard / moor-skulker / werebear / kennel-brute / harpy
minotaur skeleton / gnoll / sprite / quasit / hippogriff
```

---

## 4. 新しく入った仕組み（ソースから確認できたもの）

| 名前 | 中身 |
|---|---|
| **TECHNIQUES** | 戦技。職業ごとの必殺技とその強化。 |
| **BATTLE_WORDS** | 「戦の言葉」。呪文とは別枠の能力で、`SPELLS` には入らず `gainSpell` も通らないが、**MPの井戸は共有**する。その取り合いが調整の要になっている。 |
| **TREE_\***（約20個の宣言） | 才能ツリー。列は Power / Duration / Mana（内部名 weight / reach / thrift）。格子には字面と段位だけを出し、名前と数値はツールチップに置く設計。 |
| **PREP_\*** | 一つの年代記ぶんだけ買える「準備」。4種が `G.preparations` に入り、この版から保存キーになった。 |
| **rung / forge** | 装備の段位（強化）。 |
| **DREAM_\* / LIGHT_\* / PACT_\* / SEAM_\* / NOVA_\*** | 上記に付随する各種の仕掛け。 |

**新しいメニュー項目 3つ**: `Armoury`（武具庫）／ `Pets`（ペット）／ `Memorial Wall`（慰霊の壁）

**新しい保存キー 5つ**: `lowmoor.desk.v1` `lowmoor.armfilt.v1` `lowmoor.logkinds.v1` `lowmoor.forge.v1` `lowmoor.setup.v1`

---

## 5. 消えた仕組み

`LEANINGS`（常置注文の傾向）、`hwOf` / `noteHighWater`（歴代最高装備の記録）、
`OUTFIT_MAX`、`WAIN_CARRY_STAGES`、`WORKS_REGRADE`、`examinerWord`、`DISPATCH_MAX`、
`ROSTER_ASKS`、`assignHireling2`、`improveItem`、`gradeCost`、`hpRegen`、`coverSvg` ほか計20個。

装備まわりが「4つの名前つき枠」に作り直されたことに伴う整理と読めます。

---

## 6. セーブについて

**スキーマが v13 → v17 に上がりました。** 1.5.2 で進めていた年代記は 1.6.0 では
読めない可能性が高いです。これはゲーム本体の仕様変更で、日本語化とは無関係です。

加えて、日本語版で作った年代記は内部値（種族・職業・装備部位・獣の名前）が日本語に
なるため、英語版に戻すと参照が外れます。版を移る前に `Export Save` でコードを
控えておくのが確実です。

---

## 7. 日本語化側の対応

### 翻訳

| | |
|---|---|
| 新規に訳した文 | **2,012 件 / 54,661 文字**（PLaMo、約25分） |
| 翻訳メモリ | 5,894 → **8,685 件** |
| 新規モンスター20種 | **手訳**（ノール、ハーピー、ヒッポグリフ、ワーベア等） |
| 画面上の日本語比率 | **86%** |
| 残る未訳 | 59 件（JWT・CSSセレクタ・テンプレート断片など、訳してはいけないもの） |

### 更新の過程で見つけて直した不具合 5件

**① 抽出の絞り込みがスクリプトに入っていなかった（こちらの不備）**
`out-fragment-safe` `out2-plain-go` など4種の絞り込みを、その場かぎりのコマンドで
作っていた。そのため更新時に前版のファイルが使われ、1.6.0 で増えたツールチップが
まるごと抽出対象から漏れた。日本語比率が 92% → 68% に落ちて気づいた。
真の未訳は 903 件ではなく 2,012 件だった。4つの抽出スクリプトすべてに組み込み済み。

**② `（CON）` を「残った伏せ字」と誤検出**
伏せ字の検出が「括弧＋大文字1〜3字」を無条件に拾うため、能力値の略号に反応し、
正しく訳せている文を **50件中47件** 突き返していた。1.6.0 で説明文にこの書き方が
増えて表面化。実際に立てた符号（A, B, C…）の範囲だけを見るよう修正。

**③ キーの書き換えが暴走して起動時クラッシュ**
「クォートなしのオブジェクトキーも一緒に訳す」処理の対象が 27 → 237 件に増え、
その中に `CHART_QUARTERS[q.id]` のように**変数で引くキー**が混ざった。変数側は
data から来るので書き換えようがなく、署名した瞬間に落ちた。
参照経路を確かめた11語だけの許可リストに変更（表示の日本語を少し諦める側に倒した）。

**④ CSS が翻訳された**
`"background:var(--desk); margin:0;"` が「背景: var(--desk); マージン: 0;」に。
**lint が検出**（前回入れた検査が働いた）。`prop:value` 形も門で止めるよう拡張。

**⑤ 書き換え規則 4件が空振り**
作者が `log()` に第三引数 `"guild"` を足す、選択待ちボタンに「重要」印を追加する等の
変更を入れていた。すべて追随。その過程で、訳文中の `;` で正規表現が切れて構文エラーに
なる問題も踏んだので、末尾を飲み込まない形に直した。

### 検証結果

| 項目 | 結果 |
|---|---|
| 未捕捉例外 / console.error | 0 件 |
| ゲージ 23 本 | clip不正 0 / 幅ゼロ 0 |
| 複数形 s の残り | 0 |
| 伏せ字の残り | 0 |
| 文字化け・テンプレート式の露出 | 0 |
| LINT / 構文チェック | clean / OK |
| セーブコードの往復 | OK（v17） |

---

## 7.5 追い込み（2026-08-22 追記）

画面を全メニュー巡回して、英語のまま出ている文字列を数える道具（`tools/sweep-en.mjs`）を
作り、残りを潰しました。**291 件 → 17 件**。残る 17 件は「英語のままが正しい」もの
だけです（`30k gp` などの通貨単位、デスクの意匠名 Windows 98 / Mac OS 8 / GNOME 1、
ライセンスの URL）。**画面上の日本語比率は 86% → 92%。**

見つかった原因は、いずれも訳文ではなく**抽出側の穴**でした。

**① テンプレートリテラルの中が丸ごと未抽出**（最大の穴）

```js
`<div class="armstore"><button data-arm-equip="${escAttr(r.id)}">Equip</button></div>`
```

抽出器は「`${` があるテンプレートは触らない」で避けていたため、この `Equip` は
一度も抽出されていませんでした。画面には **1,032 箇所**出ていました。
`tools/extract4.mjs` を新設。`${}` の入れ子を数えてテンプレートを正しく切り出し、
穴を1文字の番兵に置き換えた「仮想HTML」を組み立てて、テキストノードと
`title` / `data-help` 等の属性値だけを取り出します。192 箇所を回収。

**② `${...}` の中の文字列リテラルも未抽出**

```js
`<span class="m">${esc(has ? petGrowthSay(p) : "not yet taken")}</span>`
```

走査がバッククォートからバッククォートまでを一つの文字列として読んでいたので、
穴の中の `"not yet taken"` が見えていませんでした。入れ子を数える走査
（`tools/jsscan.mjs`）で穴の中だけを別に拾うようにし、**310 件**を回収。

**③ 語彙表の差し替えで鍵が 20 個消えていた**（1.6.0 で入った退行）

`lexicon.mjs` は語順のために語彙表を関数ごと日本語で書き下ろす作りですが、
その中身が 1.5.x 時代のままでした。1.6.0 で原文の表が 8 鍵 → 28 鍵に増えたため、
差し替えると 20 鍵が消え、`mechLine` のフォールバックに落ちて

```
+1 keeneye.   +0.03 procCeil.   +2 footing.   +0.75 debuff.   …
```

が贈り物・才能・雇い人のツールチップに並んでいました。4つの表を 1.6.0 の
全鍵ぶん書き直し（世界の語り口と平明な言い方の2声）、さらに
**「差し替えで原文の鍵が失われたらビルドを止める」検査**を入れました。
黙って通っていたのが本当の問題だったので、同じ見落としは次からビルドが拒否します。

**④ 絞り込みの正規表現が「A␣」で始まる文言を全部捨てていた**

SVG パスを除く判定が先頭1文字だけを見ており、`A` が円弧コマンドなので
`A Good Boy` `A Larger Satchel` `A Hundred Lids` といった実績名・強化名が
まとめて捨てられていました。全体がパスの字種の場合だけ落とすよう修正し、
**176 件**の未訳を発掘。PLaMo で訳したうえで、多義語（chest / leg / hand /
stand / yard / quire）の訳語をそろえて 135 件を手で直しました。

**⑤ 綴りで守ると表示側まで巻き添えになる**

`el.style.display = "none"` を守るための門が、`$("chartwrit").textContent = ... : "none"`
まで止めていました。**「位置からして表示だと分かる箇所」は別の門にかける**方式に変更。
対象は、静的HTMLのテキストノードと属性、テンプレートの地の文、
`textContent` / `title` / `placeholder` への代入、表の `eff:` / `line:` の返り値。
ここでは構造用の門（structural-key・identifier-property・browser-api-value）を通さず、
壊れ方の門（タグ不一致・プレースホルダ欠落・CSS値）だけを見ます。

**⑥ 抽出器が4系統になり、同じ場所を二重に置き換えていた**

範囲の途中で終わった置換のせいで構文が壊れました
（`…します。` の後ろに `ne line and never…` が残る形）。重なりを検出して
片方を見送るようにし、見送った件数を出すようにしました。

**あわせて直したこと**

- 回帰テストの既定が `build/index-auto.html` を見ており、それが前バージョンの
  置き土産だったため、直したはずの不具合がテストにだけ出続けていました。
  毎ビルド作り直される `index-test.html` を見るように変更し、古い成果物は削除。
- `mkapp.mjs` を追加。検証用の派生ファイルをビルドごとに作り直します。

### この回の検証

| 項目 | 結果 |
|---|---|
| 未捕捉例外 / console.error | 0 件 |
| ゲージ 23 本 | clip不正 0 / 幅ゼロ 0 |
| 文字化け・`${}` の露出・実体参照の混入 | 0 |
| 画面上の日本語比率 | **92%**（前回 86%） |
| 画面に残る英語 | 17 件（すべて意図的） |
| LINT / 構文チェック | clean / OK |
| セーブコードの往復 | OK（v17） |

---

## 8. 反映

```powershell
cd C:\Users\Administrator\Documents\Lowmoor\release
.\install-ja.ps1
```

次回以降の更新手順は `更新の手順.md` を参照。

---

## 9. 1.6.1 対応（2026-08-22）

Steam が 1.6.1 を配信。**システム側の小規模更新で、文面はほとんど変わっていません**
（新規に訳す必要があったのは 102 件・5,774 文字だけ）。そこでこの回は、
残っていた英語の掃き出しと誤訳の修正に充てました。**画面上の日本語比率 86% → 93%。**

### 直した不具合（道具側）

**① 退避（app.asar.en.bak）が更新前のまま残り、原文を失った**

`install-ja.ps1` が「退避が既にあれば何もしない」だったため、1.6.0 が配信されて
app.asar が新しい英語版に入れ替わったあとに日本語版を入れると、退避は 1.5.2 のまま、
1.6.0 の英語原文は上書きされて消えました。1.6.1 を訳そうとして初めて気づき、
Steam の整合性確認で取り直すことになりました。

- `install-ja.ps1`: 退避は「英語版で、かつ今の退避より新しい版」のときだけ取り直す。
  古い退避は `app.asar.en.<版>.bak` として残す。日本語版が入っているときは触らない。
- `update.mjs`: 読もうとしている原文が手元の `app/` より古ければ、展開せずに止める。

**② `extract4.mjs`（テンプレート内の地の文）が更新手順に入っていなかった**

前の版の `out4-tpl.json`（＝古いオフセット）がそのまま使われるところでした。
抽出物が原文より古ければビルドを止める検査も追加。

**③ 巡回ツールが「日本語混じりの文」を訳済みと見なして飛ばしていた**

`看破` と `足場` の説明文が英語のまま残っていたのに検出できなかったのはこれ。
日本語が1文字でもあれば済み、としていたため、途中まで訳された文が丸ごと見えていませんでした。
英語の連なりが実質的に残っているかで判定するよう変更。

**④ 語彙表の差し替えが CRLF で隣の宣言を飲み込んだ**

`MECH_PROCS` の終端を `;
` で当てていたが、原文の改行は CRLF なので `;` の次は `
`。
走査が止まらず、直前に差し替えた `WORLD_PROCS` の末尾まで飲み込み、`return` だけが
宙に浮いて「Illegal return statement」になりました。`;
?
` に修正し、
**「差し替え範囲に別の宣言が入っていたら止める」検査**を追加。

**⑤ `.dataset.help =` を「触ってはいけない dataset」として保護していた**

値がそのままツールチップ本文になる場所なので、名誉録のリセット説明などが英語で残っていました。
`help` / `helptitle` / `helpstats` は保護対象から外し、表示位置として扱うよう変更。

**⑥ 死んだ規則の掃除**

`wintitle` の書き換え規則が、テンプレートの地の文も訳すようになった結果
`Lowmoor` が「ロウムーア」に変わって当たらなくなっていました。訳語に依存しない形に修正。
冒険者票の見出しを力ずくで置換していた 1.5.x 時代の規則 9 件は、通常の経路で
訳されるようになったので削除（当たらない規則を残すと、毎回の警告が雑音になる）。

### 直した誤訳

**能力値・呪文表**（利用者からの指摘）

- `Fires` → 「炎」を **「発動率」**、`Upon` → 「の上に」を **「発動条件」**
- 学派の略称 `Road`（未訳）→ **道行き**、`Stroke` → **一撃**、`Fury` → **猛り**
- **看破・足場の説明文が未訳**だったのを翻訳
- 装備の要約行 `dmg` → **打撃**、`Def` → **防御**

**装備の枠名**

`Armour` / `Accessory` が英語のまま、`Main hand` / `Off hand` は
「メインハンド」「手近なところで」と不揃いでした。この4語は `G.equip` の **キー**で
そのままセーブに入るため、内部の値は触らず、**表の升目に出すときだけ**
鎧／利き手／盾手／装身具に読み替える形にしました（既存のセーブはそのまま読めます）。

**戦闘ログを関数ごと書き直し**

```
旧: あなたが切り開く追い詰められたゼラチナス・キューブのために9、それはあなたに5. It stands at 33 of 42.
新: はぐれのレヴナントに斬りつけ、7。返す一撃を受けて 3。残り 104 / 111。
```

英語は「動詞 目的語」、日本語は「目的語 動詞」。断片ごとに訳しても語順は直らないので、
9 つの分岐すべてを日本語の語順で書き下ろしました（世界の語り口／簡明な言葉の二声とも）。

**用語のブレ 73 か所**

原文がゲーム内の意味で使っていて、かつ訳文に誤読が出ているものだけを直しました
（"lace by the yard" の「ヤード」や "in your chest" の「胸」は正しいので触っていません）。

| 原語 | 誤訳 | 修正 |
|---|---|---|
| Roll | 振る | 名誉録 |
| rank cap | 階級帽 | 階級上限 |
| hand | 手 | 雇い人 |
| stand | 舞台装置・立札 | 段 |
| the yard | ヤード | 需品係の庭 |
| log | 丸太 | 記録 |
| mimic | 模倣者・擬態生物 | ミミック |
| chest | 胸板 | 櫃 |
| Barracks | バラックス | 兵舎 |
| sending | 送電 | 送り |

ほか、成績表の「獣たちを舐め」→「討ち取った獣」、
「床の障害物除去完了」→「踏破した階層」、保存表示「保存済みちょうど今」→「たった今保存」など。

### この回の検証

| 項目 | 結果 |
|---|---|
| 未捕捉例外 / console.error | 0 件 |
| ゲージ 23 本 | clip不正 0 / 幅ゼロ 0 |
| 文字化け・`${}` の露出・実体参照の混入 | 0 |
| 画面上の日本語比率 | **93%**（前回 86%） |
| 画面に残る英語 | 18 件（通貨単位 gp・デスクの意匠名・ライセンス表記。すべて意図的） |
| LINT / 構文チェック | clean / OK |
| セーブコードの往復 | OK（v17） |
| 翻訳メモリ / 手訳 | 8,856 件 / 1,004 件 |

Steam スレッドへの追記文は `steam-post-1.6.1.md` にあります。

---

## 10. 音が出なくなった不具合（2026-08-24 修正）

**1.6.1 対応版で、ゲームの音がすべて止まっていました。日本語化が原因です。**

### 何が起きていたか

Web Audio と canvas の**列挙値**（ブラウザが綴りを決めている文字列）が訳されていました。

| 場所 | 原文 | 訳されて | 起きたこと |
|---|---|---|---|
| `tone.type = …` ×4 | `"lowpass"` | 「ローパス」 | 代入時に例外。音の組み立てが途中で止まる |
| `audioCtx.state === …` ×3 | `"running"` | 「流れる」 | **永久に偽**。`audioLive()` が常に false になり、`beep()` も `schedule()` も何もせず戻る |
| `function beep(…, type=…)` | `"square"` | 「平方」 | 発振器の既定波形が不正になり例外 |
| `ctx.textBaseline = …` ×3 | `"middle"` | 「中間」 | ブラウザが黙って無視。図表の文字が上下にずれる |
| `ctx.font = …` ×4 | `"px Tahoma, sans-serif"` | 「px Tahoma、サンセリフ体」 | 字体指定が不正になり、図表が既定フォントに落ちる |

とくに 2 番目が効いていました。**例外も lint も出ず、画面も普通に出て、音だけが消えます。**

### なぜ門をすり抜けたか

「ブラウザ API に渡る文字列は訳さない」門は前からありましたが、拾い方が足りませんでした。

- `apiValues` は `{type:"sine"}` のような**オブジェクト直値**と `.style.X =` は見ていたが、
  **`.type = "lowpass"` という代入**は見ていなかった。
- `runtimeCmp` は比較の左辺が `location` / `navigator` / `document` … のときだけ拾う作りで、
  **`audioCtx.state`** は対象外だった。
- `function beep(…, type="square")` の**既定引数**は、どの形にも当てはまらなかった。
- `ctx.font` は `"bold " + n + "px Tahoma, sans-serif"` と**連結で組み立てる**ので、
  リテラル単体（`"px Tahoma, sans-serif"`）を見ても API 値だと分からなかった。

### 直したこと

**門（patch.mjs）**

- **API 代入の範囲**という考え方を追加。`type` / `oversample` / `font` / `textBaseline` /
  `lineCap` など綴りの決まったプロパティへの代入は、**右辺の式ぜんぶ**を触らない範囲にする。
  連結で組み立てる `font` も、これで守れる。
- **状態プロパティとの比較**（`.state` / `.readyState` / `.visibilityState` / `.protocol` …）は、
  左辺が何であれ保護する。
- **値そのものの禁止表**を追加（`sine` `square` `lowpass` `running` `middle` `alphabetic` …）。
  既定引数や変数経由で渡る分は、これで押さえる。小文字ちょうどのものだけなので、
  画面に出る `Center` のような語は巻き込まない。

**検査（二重にした）**

- `patch.mjs` の LINT に 4 パターン追加。**訳されていればビルドが止まる。**
- `tools/apienum.mjs` — ビルド全体を走査して、API の列挙値に日本語が入っていないか見る。
- `tools/audiotest.mjs` — **実際に音が鳴るところまで確かめる。**
  Web Audio のノード生成と `start()` を数え、`beep()` が途中で戻っていないか、
  列挙値の代入で例外が出ていないかを見る。壊れた版で失敗し、直した版で通ることを確認済み。

  ```
  壊れた版: audioLive=false / ノード 0 / start 0   → 失敗
  直した版: audioLive=true  / ノード 4 / start 2   → OK
  ```

- `update.mjs` の手順にこの二つを組み込み。以後の更新では必ず通る。

### 反省

これは「例外も lint も出ないのに壊れている」型の三度目です
（一度目はゲージが真っ白、二度目は窓が小窓になる、今回は音が消える）。
毎回、**その壊れ方を検出する仕掛けを足す**ことで塞いできましたが、
今回のように「比較が永久に偽になる」形は、静的検査だけでは次の綴りで再発します。
そのため今回は、**結果を実際に測る試験**（音が鳴りに行っているか）まで用意しました。

---

## 11. 1.6.3 対応（2026-08-26）

**この版でゲームのコードが難読化（minify）されました。** 日本語化の作りに関わる
一番大きな変化なので、まずそこから書きます。

### 何が変わったか

```
1.6.2 まで:  function roundLine(f, round, name){ … }      43,311 行
1.6.3 から:  ...d.push(plainWords?"you hit "+a+" for "+n… 全体が 1 行
```

- 変数名・関数名がすべて 1〜2 文字に潰れました（`MECH_ADD` → `Le`、`sNum` → `H`）
- 全体が 1 行になりました（`index.html` は 43,311 行 → 2,895 行、3.97MB → 2.54MB）
- **残っているのは文字列リテラルとオブジェクトのキー**です。キーは data から
  引くので潰せず、`critDmg` `keeneye` `procCeil` などはそのままです

翻訳そのもの（文字列を位置指定で差し替える）は影響を受けませんが、
**語順を直すための書き換え**は、名前を目印にしていたので全滅しました。

### 直したこと

**① 走査器が正規表現を飛ばせず、位置がずれていた**（最も重い不具合）

難読化で正規表現リテラルが激増した結果、

```js
/["']/.test(x)
```

の中の `"` を「文字列の始まり」と読んでしまい、そこから先の位置が全部ずれました。
その状態で訳を当てるので、**コードの断片を文字列だと思って訳して**構文が壊れました。

```
壊れた出力: "…the Guild's own stores…" の途中から始まる偽の文字列が日本語に
```

`/` が割り算か正規表現かを直前のトークンで判定する処理を入れ、走査器を
`jsscan.mjs` 一つに統一しました（patch と extract に写しが二つあったのも整理）。
**この修正だけで、当たる訳文が 8,014 件 → 9,552 件に増えました。**

**② 語順の書き換えを「名前」ではなく「位置」で当てる方式に変更**

`structure.mjs` を新設。難読化されたコードから

- 語彙表 4 つと補助関数（`sNum` `sPct` `mPct` `fmtFig`）の潰された名前
- `mechLine`（数値行を引く関数）の範囲

を **その場で割り出し**（`minimap.mjs`）、書き換えを「原文の位置を指定した編集」として
返します。訳文の適用と同じ仕組みに乗るので、重なりの排除もそのまま効きます。

語彙表そのものは英語のまま残し、**引く側の関数を日本語で包む**方式にしました。
表を丸ごと置き換えると、表が参照する定数まで潰された名前で書く必要があり、
次の版でまた外れるからです。用意していない鍵は元の実装に渡すので、
取りこぼしても英語で出るだけで壊れません（現在 71 鍵中 68 鍵が日本語、
残る 3 つは潰された定数を参照するため英語のまま）。

同じ方式で、戦闘ログ・装備の枠名・保存からの経過・名誉録の段位表示・
複数形の s・不定冠詞、計 16 箇所を書き換えています。

**③ 未訳リストにコードの断片が混入して、翻訳が停止した**

連結を割って断片を拾う抽出器が、難読化コードから 4KB の JS ブロブを
「訳す候補」として出していました。それを PLaMo に渡すと生成が詰まり、
**872 件中 387 件がコードで、翻訳が丸ごと止まりました**。
「JavaScript に見える文字列は訳さない」判定を足し、未訳は 1,269 件 → 328 件に。

**④ 版番号が読めなくなっていた**

`const GAME_VERSION = "1.6.2"` が `const e="1.6.3"` になりました。
パッチノートの先頭（`{v:"1.6.3",date:"…"}`）から拾う形に変更（`verdetect.mjs`）。

これを見落としたまま `install-ja.ps1` を流したため、版の比較が
「読めない＝同じ版」と誤判定し、**1.6.3 の英語原版を退避せずに上書き**しました。
（1.6.1 のときと同じ失敗を、別の原因で繰り返しました。）

- `install-ja.ps1`: 版番号の読み取りを難読化に対応。加えて
  **版が読めないときは日付つきで必ず控える**ようにしました。
  「読めない」を「同じ」と扱わないのが要点です
- 退避は、手元に展開してある英語版を詰め直して復旧済み（`app.asar.en.bak` = 1.6.3）

**⑤ 検査の側も名前に頼っていた**

- 音の確認が `setSound` / `beep` を名前で呼んでいて動かなくなりました。
  **設定画面のチェックボックス**（`#opt-sound` / `#opt-music` は HTML 側なので
  潰れない）を押す方式に変更。英語原版と同じ結果（ノード 78・start 34 回）を確認
- セーブ往復の確認が `chronicleCode()` を呼んでいたので、
  **書き出しの窓を開いて中身を読む**方式に変更
- 検証用ファイルを作る `mkapp.mjs` の目印が変わっていて、
  古いファイルに対して検査を走らせていました。両方の書き方に対応

### 翻訳

| | |
|---|---|
| 対応バージョン | **1.6.3** |
| 新規に訳した文 | 328 件 / 9,013 文字（うち 200 件をモデル、4 件を手訳） |
| 翻訳メモリ | **9,458 件** |
| 手訳（上書き層） | **1,015 件** |
| 画面上の日本語比率 | **91%** |
| 画面に残る英語 | **17 件**（通貨単位 gp・デスクの意匠名・ライセンス表記。すべて意図的） |

### システム側に触れていないかの点検

ご要望の点検です。英語の原版と日本語版を機械的に突き合わせ、
**訳文以外が変わっていないか**を確かめる `systemcheck.mjs` を作りました。

| 見た項目 | 結果 |
|---|---|
| localStorage の鍵（訳すとセーブが読めなくなる） | 4 種すべて一致 |
| `getElementById` / `querySelector` | 59 種すべて一致 |
| `classList` の操作 | 54 種すべて一致 |
| `setAttribute` の名前 | 6 種すべて一致 |
| `addEventListener` の種別 | 20 種すべて一致 |
| Web Audio / canvas の列挙値 | 10 種すべて一致 |
| 状態の比較（`.state` など） | 一致 |
| `fetch` の宛先 | 変更なし（0 件） |
| `style` への代入 | 13 種すべて一致 |
| セーブのスキーマ番号 | v17 のまま |
| `<script>` の数 | 2 のまま |

**消えたものは 0 件** — システム側の文字列は一つも訳されていません。
増えているのは、こちらが意図して足している字体切替の要素（`opt-jafont` と
その初期化）だけで、これは翻訳ではありません。

あわせて実行時の確認も通しています。

| 項目 | 結果 |
|---|---|
| 未捕捉例外 / console.error | 0 件 |
| ゲージ 23 本 | clip不正 0 / 幅ゼロ 0 |
| 文字化け・`${}` の露出 | 0 |
| 音（英語原版との比較） | 一致（ノード 78 / start 34 回） |
| API の列挙値に日本語 | 0 件 |
| セーブコードの往復 | OK（v17、`ハードウィン グレイムーア`、壊れた文字なし） |
| 訳文データの壊れた文字 | 0 件（tm 9,458 件・手訳 1,015 件を走査） |
| LINT / 構文チェック | clean / OK |

なお回帰テストの表示で冒険者名が化けて見えたので調べましたが、
**セーブは正常**で、テスト側の復号（`decodeURIComponent(escape(atob(...)))`）が
多バイト文字で壊れていたのが原因でした。`TextDecoder` に直しています。
