From f758e13073423c1b3c9d86afa121591652b88d36 Mon Sep 17 00:00:00 2001 From: dazedanon Date: Thu, 12 Mar 2026 22:41:28 -0500 Subject: [PATCH] sjadfoajiofs --- gui/workflow_tab.py | 239 +++++++++++++++++++++++++++++++++----------- 1 file changed, 180 insertions(+), 59 deletions(-) diff --git a/gui/workflow_tab.py b/gui/workflow_tab.py index 6f65f8d..57d6480 100644 --- a/gui/workflow_tab.py +++ b/gui/workflow_tab.py @@ -71,6 +71,26 @@ PHASE1_CONFIG = { "CODE108": False, } +PHASE1B_CONFIG = { + # Dialogue OFF (handled by Phase 1) + "CODE101": False, + "CODE401": False, + "CODE405": False, + "CODE102": False, + "CODE408": False, + # Only 111 ON — build the var-translation cache from string comparisons + "CODE111": True, + "CODE122": False, + "CODE357": False, + "CODE355655": False, + "CODE657": False, + "CODE356": False, + "CODE320": False, + "CODE324": False, + "CODE325": False, + "CODE108": False, +} + PHASE2_CONFIG = { # Dialogue OFF (already handled by Phase 1) "CODE101": False, @@ -78,10 +98,10 @@ PHASE2_CONFIG = { "CODE405": False, "CODE102": False, "CODE408": False, - # Risky codes ON + # Risky codes ON (111 OFF — cache already built by Phase 1b) "CODE122": True, "CODE357": True, - "CODE111": True, + "CODE111": False, "CODE356": False, # plugin cmd — user can enable manually if needed "CODE108": False, # comment — rarely needed } @@ -755,6 +775,102 @@ class WorkflowTab(QWidget): "(e.g. padding estimates, windows whose pixel width could not be determined directly).\n" ) + _RISKY_PROMPT = ( + "You are helping me safely translate a Japanese RPGMaker MV/MZ game.\n" + "Before I run Phase 2 (risky codes), I need you to audit four code types\n" + "and tell me exactly what is safe to translate and what must be left alone.\n" + "\n" + "Attach the game's event files (CommonEvents.json, Troops.json, Map*.json)\n" + "and plugins.js before running this prompt.\n" + "\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "## AUDIT 1 — Code 111 (Conditional Branch) string comparisons\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "\n" + "Search all event lists for code 111 entries that compare a string value\n" + "(operationType 0 or where parameters[3] is a string literal).\n" + "\n" + "For each one found, report:\n" + " - The variable or switch being tested\n" + " - The string it is compared against (e.g. === 'ノーマル')\n" + " - Whether the same string appears as a value SET by a code 122 elsewhere\n" + " (meaning translating code 122 would break this 111 comparison)\n" + "\n" + "Verdict for each: SAFE TO TRANSLATE / DO NOT TRANSLATE / NEEDS MANUAL CHECK\n" + "\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "## AUDIT 2 — Code 122 (Control Variables) string values\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "\n" + "Search for code 122 entries where parameters[4] is a quoted string.\n" + "For each unique string value found:\n" + " - Is this string also tested in a 111 comparison? → DO NOT TRANSLATE\n" + " - Is this string used as a key / ID in a plugin call or script? → DO NOT TRANSLATE\n" + " - Is this string purely display text (shown to the player)? → SAFE TO TRANSLATE\n" + "\n" + "List any variables by variable-ID that should be blacklisted from translation.\n" + "\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "## AUDIT 3 — Code 357 (Plugin Commands) — which plugins need enabling\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "\n" + "Search all event lists for code 357 entries and collect every unique\n" + "parameters[0] (plugin header string) that contains translatable Japanese text\n" + "in its parameters[3] dict.\n" + "\n" + "The translation module already has built-in handlers for these headers:\n" + " AdvExtentionllk, VisuMZ_4_ProximityMessages, LL_GalgeChoiceWindow\n" + "\n" + "For every OTHER header you find with Japanese text, check whether it matches\n" + "one of these commented-out entries in the module's headerMappings dict:\n" + "\n" + " LL_InfoPopupWIndow → messageText\n" + " QuestSystem → DetailNote\n" + " BalloonInBattle → text\n" + " MNKR_CommonPopupCoreMZ → text\n" + " DestinationWindow → destination\n" + " _TMLogWindowMZ → text\n" + " TorigoyaMZ_NotifyMessage → message\n" + " SoR_GabWindow → arg1\n" + " DarkPlasma_CharacterText → text\n" + " DTextPicture → text\n" + " TextPicture → text\n" + " TRP_SkitMZ → name\n" + " LogWindow → text\n" + " BattleLogOutput → message\n" + " TorigoyaMZ_NotifyMessage_CommandMessage → message\n" + " NUUN_SaveScreen → AnyName\n" + " build/ARPG_Core → Text, SkillByName\n" + "\n" + "For each match, output the EXACT line to uncomment in headerMappings, e.g.:\n" + " \"LL_InfoPopupWIndow\": ([\"messageText\"], None),\n" + "\n" + "For headers with Japanese text that do NOT appear in the list above, describe\n" + "the parameters[3] structure so a new entry can be written manually.\n" + "\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "## Required output format\n" + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + "\n" + "Reply with four sections using these exact headers:\n" + "\n" + "### Code 111 — Dangerous Comparisons\n" + "\n" + "If none found: 'No dangerous string comparisons found.'\n" + "\n" + "### Code 122 — Variable String Safety\n" + "\n" + "If all safe: 'All code 122 string values appear to be display text only.'\n" + "\n" + "### Code 357 — Plugin Handlers to Enable\n" + "For each plugin header with Japanese text:\n" + " • Already handled :
— no action needed\n" + " • Enable in module : uncomment this line in headerMappings:\n" + " \"
\": ([\"\"], None),\n" + " • New entry needed :
— parameters[3] looks like: \n" + "If no 357 codes with Japanese found: 'No code 357 plugin text found.'\n" + ) + # ── Step 1 (Optional): Pre-process ──────────────────────────────── def _build_preprocess(self, layout: QVBoxLayout): @@ -1182,6 +1298,32 @@ class WorkflowTab(QWidget): p1_inner.addLayout(p1_row) layout.addWidget(p1_box) + p1b_box = QGroupBox("Phase 1b – Build Variable Cache (code 111)") + p1b_box.setStyleSheet( + "QGroupBox{color:#ccc;border:1px solid #444;border-radius:3px;" + "margin-top:8px;font-size:11px;}" + "QGroupBox::title{padding:0 6px;}" + ) + p1b_inner = QVBoxLayout(p1b_box) + p1b_desc = QLabel( + "Code ON: 111 (Conditional Branch string comparisons)\n" + "Scans all 111 branches that compare \u2018$gameVariables\u2019 against string values and " + "builds the var_translation_map cache.\n" + "Run this before Phase 2 so that code 122 translated strings are automatically " + "matched when those same strings appear in 111 comparisons." + ) + p1b_desc.setStyleSheet("color:#888;font-size:10px;") + p1b_desc.setWordWrap(True) + p1b_inner.addWidget(p1b_desc) + p1b_row = QHBoxLayout() + run_p1b = _make_btn("⚙ Set Codes \u2192 Go to Translation", "#2a5a7a") + run_p1b.setToolTip("Applies Phase 1b code settings (111 only) and switches to the Translation tab") + run_p1b.clicked.connect(lambda: self._run_phase("1b")) + p1b_row.addWidget(run_p1b) + p1b_row.addStretch() + p1b_inner.addLayout(p1b_row) + layout.addWidget(p1b_box) + p2_box = QGroupBox("Phase 2 – Risky Codes (variables + conditionals)") p2_box.setStyleSheet( "QGroupBox{color:#ccc;border:1px solid #444;border-radius:3px;" @@ -1190,7 +1332,7 @@ class WorkflowTab(QWidget): ) p2_inner = QVBoxLayout(p2_box) p2_desc = QLabel( - "Codes ON: 122 (Control Variables), 357 (Plugin Commands), 111 (Conditional Branch)\n" + "Codes ON: 122 (Control Variables), 357 (Plugin Commands)\n" "Strings here are often used in script comparisons — mistranslations can break game " "logic. Use Scan first to preview what will be translated, then apply and go translate." ) @@ -1198,15 +1340,18 @@ class WorkflowTab(QWidget): p2_desc.setWordWrap(True) p2_inner.addWidget(p2_desc) - p2_row = QHBoxLayout() - scan_p2 = _make_btn("🔍 Scan Risky Strings", "#555") - scan_p2.setToolTip( - "Preview all unique string values in codes 122 / 357 / 111 " - "before deciding what to translate." + copy_risky_row = QHBoxLayout() + copy_risky_btn = _make_btn("📋 Copy Risky Prompt", "#555") + copy_risky_btn.setToolTip( + "Copy a Copilot prompt that audits code 111 string comparisons, " + "code 122 variable safety, and code 357 plugin handlers." ) - scan_p2.clicked.connect(self._scan_risky_strings) - p2_row.addWidget(scan_p2) + copy_risky_btn.clicked.connect(self._copy_risky_prompt) + copy_risky_row.addWidget(copy_risky_btn) + copy_risky_row.addStretch() + p2_inner.addLayout(copy_risky_row) + p2_row = QHBoxLayout() run_p2 = _make_btn("⚙ Set Codes \u2192 Go to Translation", "#7a4a00") run_p2.setToolTip("Applies Phase 2 code settings and switches to the Translation tab") run_p2.clicked.connect(lambda: self._run_phase(2)) @@ -1511,6 +1656,10 @@ class WorkflowTab(QWidget): QApplication.clipboard().setText(self._WRAP_PROMPT) self._log("Text-wrap analysis prompt copied to clipboard.") + def _copy_risky_prompt(self): + QApplication.clipboard().setText(self._RISKY_PROMPT) + self._log("Risky codes analysis prompt copied to clipboard.") + def _apply_wrap_config(self): """Write width / listWidth / noteWidth back into .env.""" import re as _re @@ -1566,9 +1715,16 @@ class WorkflowTab(QWidget): # Step 4 – Translation phases # ───────────────────────────────────────────────────────────────────────── - def _run_phase(self, phase: int): - config = PHASE1_CONFIG if phase == 1 else PHASE2_CONFIG - label = "Phase 1 (safe codes)" if phase == 1 else "Phase 2 (risky codes)" + def _run_phase(self, phase): + if phase == 1: + config = PHASE1_CONFIG + label = "Phase 1 (safe codes)" + elif phase == "1b": + config = PHASE1B_CONFIG + label = "Phase 1b (code 111 cache)" + else: + config = PHASE2_CONFIG + label = "Phase 2 (risky codes)" # Apply config profile so the Translation tab uses the right codes try: @@ -1607,12 +1763,21 @@ class WorkflowTab(QWidget): self._log(" If names are missing or garbled, stop the run and") self._log(" revisit Step 2 (speaker flags) before continuing.") self._log("─" * 54) + elif phase == "1b": + self._log("") + self._log("─" * 54) + self._log("👉 Switch to the Translation tab and start the run.") + self._log(" Phase 1b translates code 111 string comparisons and") + self._log(" writes a var_translation_map cache to log/.") + self._log(" Run Phase 2 afterwards — code 122 strings that match") + self._log(" a cached 111 comparison will reuse the same translation.") + self._log("─" * 54) else: self._log("") self._log("─" * 54) self._log("👉 Switch to the Translation tab and start the run.") - self._log(" Phase 2 targets script/variable strings — review") - self._log(" the Risky String scan output before proceeding.") + self._log(" Phase 2 targets script/variable strings — make sure") + self._log(" Phase 1b has been run first to build the 111 cache.") self._log("─" * 54) # Navigate to the Translation tab (index 0 in content_stack) @@ -1626,50 +1791,6 @@ class WorkflowTab(QWidget): except Exception: pass - # ───────────────────────────────────────────────────────────────────────── - # Risky string scanner (preview mode) - # ───────────────────────────────────────────────────────────────────────── - - def _scan_risky_strings(self): - risky_codes = {122, 357, 111} - collected: dict[int, list[str]] = {c: [] for c in risky_codes} - files_dir = Path("files") - - try: - for fp in sorted(files_dir.glob("*.json")): - data = json.loads(fp.read_text(encoding="utf-8-sig")) - self._collect_risky(data, risky_codes, collected) - - self._log("=" * 50) - self._log("Risky Code String Scan (preview — nothing modified):") - total = 0 - for code in sorted(risky_codes): - strings = sorted(set(collected[code])) - total += len(strings) - self._log(f"\n CODE {code} — {len(strings)} unique string(s):") - for s in strings[:50]: - self._log(f" {repr(s)}") - if len(strings) > 50: - self._log(f" … ({len(strings) - 50} more)") - self._log(f"\n Total unique strings: {total}") - self._log("=" * 50) - except Exception as exc: - self._log(f"❌ Scan error: {exc}") - - def _collect_risky(self, obj, risky_codes: set, collected: dict): - if isinstance(obj, list): - for item in obj: - self._collect_risky(item, risky_codes, collected) - elif isinstance(obj, dict): - code = obj.get("code") - if code in risky_codes: - params = obj.get("parameters") or [] - for p in params: - if isinstance(p, str) and p.strip(): - collected[code].append(p) - for v in obj.values(): - self._collect_risky(v, risky_codes, collected) - # ───────────────────────────────────────────────────────────────────────── # Step 5 – Export to game # ─────────────────────────────────────────────────────────────────────────