diff --git a/README.md b/README.md index 04f6690..10f7366 100644 --- a/README.md +++ b/README.md @@ -326,8 +326,8 @@ Open the **Workflow** tab and choose **Wolf RPG (WolfDawn)** from the engine sel |------|--------| | **0 Project** | Select the game folder, **Unpack** the `.wolf` archives into a loose `Data/` folder, then **Extract text** (maps, common events, databases, `Game.dat`, external event text, and the project-wide name glossary). Everything is staged into `files/` for translation, including `names.json` (translated later in Phase 0 only). Extraction also snapshots the pristine (untranslated) binaries into `wolf_json/originals/` so Step 4 can inject idempotently. **Set up git tracking** by copying the `gameupdate/` folder (updater scripts, `patch.sh`/`patch.ps1`, and a `.gitignore` that excludes the original game files) into the game root, so the translation project can be tracked with git and later shipped as a git-based patch players apply themselves. Finally, **Format extracted JSON** (dazedformat) normalises `wolf_json/` and `files/` to the same layout the translator writes back (`json.dump`, indent 4) — run it once and commit it as your baseline so later injects produce clean, line-level git diffs instead of reformatting whole files. | | **1 Glossary** | Build `vocab.txt` before translating: copy the WOLF-tailored prompt into Cursor/Copilot with the extracted `files/` JSON, let it discover character names, speech registers, and lore terms, then paste the result into the in-tab editor and save (the shared `vocab.txt` is used by every translation batch to keep names and voice consistent). Item/skill/enemy value names (`names.json`) are curated in Step 2 and harvested into `vocab.txt` automatically during Phase 0 — do not list them here. | -| **2 Names** | Curate `names.json` (item/skill/enemy/variable value names). **Translating all of them breaks the game** - many WOLF value names double as logic keys (compared by value, used as variable/file/event names), so by default none are translated. WolfDawn tags each name with its WOLF database **category** (the `note` field), so instead of judging thousands of names you pick which *categories* are safe. Copy the **names-safety prompt** into a repo-aware AI (Cursor/Copilot with `files/` open); it groups names by category, checks how each is used, and returns a JSON list of the safe categories in a code block. Paste that list and click **Apply** to tick the matching rows (or tick them by hand - each row shows the category, its name count, and an example), then **Save** to `data/wolf_safe_notes.json`. You can also run **Translate safe names (Phase 0)** from here once categories are saved. | -| **3 Translate** | Pick the **Translation mode** (Normal or Batch - Batch uses the Anthropic Batches API, ~50% cheaper, Claude only), then run the `Wolf RPG (WolfDawn)` module in three ordered phases (RPG Maker's DB-first strategy): **Phase 0 · Names → vocab.txt** translates only the safe name categories from Step 2 and harvests them into `vocab.txt` (grouped by bilingual category headers such as `Weapon · 武器`); **Phase 1 · Database text** translates item/skill/state descriptions and system messages from `DataBase.project.json` / `CDataBase.project.json`; **Phase 2 · Dialogue & events** translates maps (`.mps`), `CommonEvent.dat.json`, `Game.dat`, and `Evtext`. Run them in order so later phases benefit from the glossary seeded in Phase 0. Under **Speaker handling**, speaker attribution is automatic - WolfDawn already tags who speaks on each line, so lines with a real nameplate (a face window precedes the name) are always reshaped into the `[Speaker]: line` convention the prompt understands (translating the speaker tag), then restored to WOLF's native `Speaker⏎line` layout on inject. The only judgement call is WolfDawn's low-confidence guesses (a short first line with no face window that may or may not be a name); copy the **speaker-format prompt** to have the repo-aware AI inspect `files/` and recommend ENABLE/DISABLE, then set the single low-confidence checkbox to match (there is no toggle for the reliable nameplates - they need no configuration). Under **Text wrap width**, set whether/where translated dialogue re-wraps to fit WOLF's message box (same `dazedwrap` engine the RPG Maker workflow uses, saved to `.env` as `wolfWrap` / `wolfWidth`); only the dialogue body is wrapped - a speaker's nameplate line is always kept separate so the `⏎` after a name is never folded into the text. Only the `text` fields are filled in; `source` is preserved so injection can verify each line. | +| **2 Names** | Curate `names.json` (item/skill/enemy/variable value names). **Translating all of them breaks the game** - many WOLF value names double as logic keys (compared by value, used as variable/file/event names), so by default none are translated. WolfDawn tags each name with its WOLF database **category** (the `note` field), so instead of judging thousands of names you pick which *categories* are safe. Copy the **names-safety prompt** into a repo-aware AI (Cursor/Copilot with `files/` open); it groups names by category, checks how each is used, and returns a JSON list of the safe categories in a code block. Paste that list and click **Apply** to tick the matching rows (or tick them by hand - each row shows the category, its name count, and an example), then **Save** to `data/wolf_safe_notes.json`. Pick the **Translation mode** here (Normal or Batch - Batch uses the Anthropic Batches API, ~50% cheaper, Claude only); the same choice applies to all later phases. Run **Translate safe names (Phase 0)** once categories are saved - this is the first translation step and harvests item/skill/term names into `vocab.txt`. | +| **3 Translate** | Run the `Wolf RPG (WolfDawn)` module in three ordered phases (RPG Maker's DB-first strategy): **Phase 0 · Names → vocab.txt** translates only the safe name categories from Step 2 and harvests them into `vocab.txt` (grouped by bilingual category headers such as `Weapon · 武器`); **Phase 1 · Database text** translates item/skill/state descriptions and system messages from `DataBase.project.json` / `CDataBase.project.json`; **Phase 2 · Dialogue & events** translates maps (`.mps`), `CommonEvent.dat.json`, `Game.dat`, and `Evtext`. Run them in order so later phases benefit from the glossary seeded in Phase 0. Under **Speaker handling**, speaker attribution is automatic - WolfDawn already tags who speaks on each line, so lines with a real nameplate (a face window precedes the name) are always reshaped into the `[Speaker]: line` convention the prompt understands (translating the speaker tag), then restored to WOLF's native `Speaker⏎line` layout on inject. The only judgement call is WolfDawn's low-confidence guesses (a short first line with no face window that may or may not be a name); copy the **speaker-format prompt** to have the repo-aware AI inspect `files/` and recommend ENABLE/DISABLE, then set the single low-confidence checkbox to match (there is no toggle for the reliable nameplates - they need no configuration). Under **Text wrap width**, set whether/where translated dialogue re-wraps to fit WOLF's message box (same `dazedwrap` engine the RPG Maker workflow uses, saved to `.env` as `wolfWrap` / `wolfWidth`); only the dialogue body is wrapped - a speaker's nameplate line is always kept separate so the `⏎` after a name is never folded into the text. Only the `text` fields are filled in; `source` is preserved so injection can verify each line. | | **4 Inject** | Write the translations back into the game's `Data/` binaries **and** refresh the git-tracked `wolf_json/` with the translated JSON, so the game project's git diff shows both the JSON source and the injected binaries. Injection always reads from a **pristine snapshot** of the original binaries (`wolf_json/originals/`, captured during Step 0 extraction and rebuilt from the `.wolf`/`.wolf.bak` archives if missing) and writes the result into the live `Data/` file. This keeps injection **idempotent** - WolfDawn locates each Japanese source string in the original, so re-injecting after fixing a few lines actually updates the binary instead of silently no-op'ing (the old in-place inject broke once a file had already been translated). Toggle `--en-punct` (convert Japanese punctuation to ASCII) and `--allow-code-drift` (relax the inline-code guard) as needed, and use **Check name consistency** to catch names translated differently across files. **Quick inject** lists the files you've translated so far (present in `translated/`) so you can tick just a few, inject them straight into `Data/`, and review the git diff / test in-game - ideal for iterating. **Inject all translations** writes every document, including the safe name values from Phase 0, across `Data/`. | | **5 Package** | Either run from the loose `Data/` folder (backs up `Data.wolf` → `Data.wolf.bak`), or **Repack** a fresh `Data.wolf`, inheriting the original archive's encryption. | | **6 Saves** | *(Optional)* Update existing `.sav` files so old Japanese saves load cleanly in the translated build. Originals are backed up automatically. | diff --git a/gui/wolf_workflow_tab.py b/gui/wolf_workflow_tab.py index 90f1af2..cd5ed89 100644 --- a/gui/wolf_workflow_tab.py +++ b/gui/wolf_workflow_tab.py @@ -14,13 +14,12 @@ Mirrors the RPGMaker WorkflowTab, driven by the vendored WolfDawn ``wolf`` CLI Step 2 Names - curate names.json (item/skill/enemy value names). Blindly translating all of them breaks games that reference names by value, so a repo-aware AI classifies which categories are safe - to translate and leaves the rest as source. Done before - translating so Phase 0 can seed the glossary from them. + to translate and leaves the rest as source. Pick Normal/Batch + translation mode here and run Phase 0 (names -> vocab.txt). Step 3 Translate - run the "Wolf RPG (WolfDawn)" module over files/ in three - ordered phases (RPGMaker's DB-first strategy): - Phase 0 Names - the safe name categories from Step 2; - their translations are harvested into - vocab.txt so later phases stay consistent + ordered phases (RPGMaker's DB-first strategy; mode set in Step 2): + Phase 0 Names - also runnable from Step 2; harvests safe + name translations into vocab.txt Phase 1 Database - item/skill/state descriptions and system messages (DataBase/CDataBase.project) Phase 2 Dialogue - maps, CommonEvent, Game.dat, Evtext @@ -1058,8 +1057,6 @@ class WolfWorkflowTab(QWidget): "dialogue with consistent item / skill / character names (RPGMaker's DB-first strategy)." )) - self._add_tl_mode_selector(layout) - self._add_phase_buttons(layout) self._add_speaker_options(layout) @@ -1071,8 +1068,8 @@ class WolfWorkflowTab(QWidget): layout.addWidget(self._subheading("Phase 0 · Names → vocab.txt")) layout.addWidget(self._desc( "Translates only the safe name categories you approved in Step 2 and harvests them into " - "vocab.txt (grouped by category, e.g. \"Weapon · 武器\"). Curate safe categories in Step 2 " - "first, or nothing is translated. Also runnable from Step 2." + "vocab.txt (grouped by category, e.g. \"Weapon · 武器\"). Curate safe categories and pick " + "the translation mode in Step 2 first, or nothing is translated. Also runnable from Step 2." )) p0 = self._register(_make_btn("▶ Phase 0 · Translate names", "#00a86b")) p0.clicked.connect( @@ -1248,7 +1245,7 @@ class WolfWorkflowTab(QWidget): return False def _add_tl_mode_selector(self, layout: QVBoxLayout): - """Normal vs Batch selector for the full translation run.""" + """Normal vs Batch selector for all Wolf workflow translation phases.""" row = QHBoxLayout() lbl = QLabel("Translation mode:") lbl.setStyleSheet("color:#cccccc;font-size:12px;font-weight:bold;background:transparent;") @@ -1435,8 +1432,10 @@ class WolfWorkflowTab(QWidget): "After saving, translate only the approved categories. The WolfDawn module skips every " "other name (leaving it identical to the source) and harvests the translated names into " "vocab.txt (grouped by category) so the later Translate phases stay consistent. This is " - "the same as Phase 0 in Step 3; run it here first, or from the Translate step." + "the first translation step - pick Normal or Batch below, then run Phase 0 here or from " + "Step 3 (the same mode applies to all phases)." )) + self._add_tl_mode_selector(layout) tl_btn = self._register(_make_btn("Translate safe names now (Phase 0)", "#00a86b")) tl_btn.clicked.connect( lambda: self._navigate_to_translation(kinds=PHASE_NAMES_KINDS, auto_start=True)