From 600ce598dfc7eb2599775cb3c96aeae5ee862669 Mon Sep 17 00:00:00 2001 From: dazedanon Date: Wed, 1 Apr 2026 15:00:47 -0500 Subject: [PATCH] More fixes --- gui/workflow_tab.py | 31 +++++++++++++++++++++++++++++-- modules/rpgmakermvmz.py | 14 ++++++++------ util/translation.py | 7 ++++--- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/gui/workflow_tab.py b/gui/workflow_tab.py index 6ede557..8e9322b 100644 --- a/gui/workflow_tab.py +++ b/gui/workflow_tab.py @@ -437,6 +437,17 @@ def _make_toggle_btn(text: str) -> QPushButton: return btn +# ───────────────────────────────────────────────────────────────────────────── +# Helpers +# ───────────────────────────────────────────────────────────────────────────── + +class _PlainPasteTextEdit(QTextEdit): + """QTextEdit that always pastes as plain text to avoid spurious newlines.""" + + def insertFromMimeData(self, source): # noqa: N802 + self.insertPlainText(source.text()) + + # ───────────────────────────────────────────────────────────────────────────── # Main widget # ───────────────────────────────────────────────────────────────────────────── @@ -813,11 +824,27 @@ class WorkflowTab(QWidget): "\n" "\n" " 101 param[4] name { \"code\": 101, \"parameters\": [\"\", 0, 2, 2, \"るな\"] }\n" - " \\\\n or \\\\k escape code anywhere inside a 401 line\n" + " \\\\n or \\\\k escape code with ANGLE BRACKETS anywhere inside a 401 line\n" " 【Name】 alone on a line, or 【Name】dialogue on the same line\n" " [Name] alone on a line, or [Name]dialogue on the same line\n" " \\\\c[N]Name\\\\c[0] color-wrapped name on its own 401 line\n" " Name: line ending with a full-width colon\n" + "\n" + "## CRITICAL — \\\\N[X] / \\\\n[X] (square bracket + number) is NOT a speaker format\n" + "\n" + " \\\\N[ActorID] and \\\\n[ActorID] (e.g. \\\\N[1], \\\\n[2]) are RPGMaker actor variable\n" + " substitution codes. They expand to an actor's name at runtime, but the translation tool\n" + " handles them purely as text substitution during translation — they are NEVER treated as\n" + " a speaker name tag.\n" + "\n" + " A 401 line containing ONLY \\\\N[X], or narration text that embeds \\\\N[X] (e.g.\n" + " \"ローターが\\\\N[1]の乳首に装着される!\"), does NOT match any always-on speaker format.\n" + " Do NOT count \\\\N[X] / \\\\n[X] codes as always-on speaker detection hits.\n" + "\n" + " If a game's ONLY speaker indicator is a standalone \\\\N[X] line followed by dialogue,\n" + " check whether FIRSTLINESPEAKERS would catch it (the standalone line must be < 40 chars\n" + " AND contain at least one Japanese character — a bare \\\\N[1] with no Japanese text does\n" + " NOT qualify for FIRSTLINESPEAKERS either).\n" "\n" "\n" "\n" @@ -1586,7 +1613,7 @@ class WorkflowTab(QWidget): ) layout.addWidget(format_hint) - self.vocab_editor = QTextEdit() + self.vocab_editor = _PlainPasteTextEdit() self.vocab_editor.setMinimumHeight(80) self.vocab_editor.setMaximumHeight(160) self.vocab_editor.setFont(QFont("Consolas", 9)) diff --git a/modules/rpgmakermvmz.py b/modules/rpgmakermvmz.py index c081963..94e6c43 100644 --- a/modules/rpgmakermvmz.py +++ b/modules/rpgmakermvmz.py @@ -148,8 +148,8 @@ CODE408 = False # Variables CODE122 = False -CODE122_VAR_MIN = 0 -CODE122_VAR_MAX = 2000 +CODE122_VAR_MIN = 890 +CODE122_VAR_MAX = 891 # Plugins / Scripts CODE355655 = False @@ -218,7 +218,7 @@ PATTERNS_355655 = { "AddAddress": (r'AddAddress\(\d+,\s*\\?"(.+?)\\?"', False), } # Subset of PATTERNS_355655 keys that should be processed (empty = none). -ENABLED_PATTERNS_355655: set = set() +ENABLED_PATTERNS_355655: set = {"BattleManager._logWindow.push('addText'"} def handleMVMZ(filename, estimate): @@ -1886,7 +1886,7 @@ def searchCodes(page, pbar, jobList, filename): # Inline speaker detection — Name「/Name: "/Name: (/[Name] "/[Name] ( if len(speakerList) == 0 and INLINE401SPEAKERS: inlineSpeakerMatch = re.match( - r'^(?:\[([^\]]{1,30})\]\s*|([^\s「」。、!?…\\\n“”"(:\[\]]{1,20})(?:[:::]\s*)?(?=[「“"(]))(.*)', + r'^(?:\[([^\]]{1,30})\]\s*|([^\s「」。、!?…\\\n“”"(:\[\]]{1,20})(?:[:::]?\s*)(?=[「“"(]))(.*)', jaString, re.DOTALL ) if inlineSpeakerMatch: @@ -2623,8 +2623,10 @@ def searchCodes(page, pbar, jobList, filename): if isinstance(codeList[i]["parameters"][0], str) and codeList[i]["parameters"][0].strip(): reduceWidthFlag = True jaString = codeList[i]["parameters"][4] - # Check for Var - elif len(codeList[i]["parameters"]) > 0: + # Check for Var (only when parameters[0] is not a face file, + # i.e. fewer than 4 params — standard code 101 always has 4: + # [faceFile, faceIndex, background, position]) + elif 0 < len(codeList[i]["parameters"]) < 4: jaString = codeList[i]["parameters"][0] isVar = True if not isinstance(jaString, str): diff --git a/util/translation.py b/util/translation.py index 7fb88ba..f685b3b 100644 --- a/util/translation.py +++ b/util/translation.py @@ -1398,11 +1398,11 @@ def translateAI(text, history, config, filename=None, pbar=None, lock=None, mism # Ellipsis-only bypass: strings whose translatable content is purely '…' characters # (e.g. "「………」") should never be sent to the AI — just convert brackets and pass through. def _is_ellipsis_only(s): - inner = str(s).strip().lstrip('「').rstrip('」').strip() - return bool(inner) and all(c == '\u2026' for c in inner) + inner = str(s).strip().lstrip('「『').rstrip('」』').strip() + return bool(inner) and all(c in '\u2026\u30FC' for c in inner) def _convert_ellipsis(s): - return str(s).replace('「', '"').replace('」', '"') + return str(s).replace('「', '"').replace('」', '"').replace('『', '"').replace('』', '"') if isinstance(tItem, list): if all(_is_ellipsis_only(s) for s in tItem): @@ -1717,6 +1717,7 @@ def translateAI(text, history, config, filename=None, pbar=None, lock=None, mism return line line = line.replace("Placeholder Text", "").strip() line = line.replace("「", '"').replace("」", '"') + line = line.replace("『", '"').replace("』", '"') return line final_translations = [_clean_extracted_line(line) for line in extracted] else: