fix(rpgmaker): keep code 101 labels out of dialogue text
- Translate only the inner name while preserving display brackets - Strip temporary speaker context before writing code 401 dialogue - Cover malformed bracketed labels and reruns with a regression test
This commit is contained in:
parent
38ca8e44be
commit
d1023178fe
2 changed files with 59 additions and 5 deletions
|
|
@ -588,6 +588,22 @@ def _101_name_source(cmd, is_var: bool) -> str:
|
|||
return ""
|
||||
|
||||
|
||||
def _101_speaker_name(raw_name: str) -> str:
|
||||
"""Return the translatable name inside a code-101 display wrapper.
|
||||
|
||||
Parameter 4 may use ``【Name】`` as its visible name-window styling. Those
|
||||
brackets belong in the 101 field, not in the ``[Speaker]:`` transport prefix
|
||||
temporarily attached to the following 401 dialogue.
|
||||
"""
|
||||
name = str(raw_name or "").strip()
|
||||
name = re.sub(r"^(?:[\\]+[cC]\[\d+\]\s*)+", "", name)
|
||||
bracketed = re.match(r"^【\s*([^】]+?)\s*】", name)
|
||||
if bracketed:
|
||||
return bracketed.group(1).strip()
|
||||
plain = re.match(r"^([^\\]+)", name)
|
||||
return plain.group(1).strip() if plain else ""
|
||||
|
||||
|
||||
def _entry_orig(entry) -> dict:
|
||||
"""Return _original dict on a database entry, or empty dict if absent."""
|
||||
orig = entry.get("_original") if isinstance(entry, dict) else None
|
||||
|
|
@ -3136,9 +3152,8 @@ def searchCodes(page, pbar, jobList, filename):
|
|||
|
||||
# Get Speaker
|
||||
rawName = _101_name_source(codeList[i], isVar)
|
||||
match = re.search(r"^(?:[\\]+[cC]\[\d+?\])?([^\\]+)", rawName)
|
||||
if match:
|
||||
sourceName = match.group(1)
|
||||
sourceName = _101_speaker_name(rawName)
|
||||
if sourceName:
|
||||
response = getSpeaker(sourceName)
|
||||
totalTokens[0] += response[1][0]
|
||||
totalTokens[1] += response[1][1]
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ def _resolve_case_command(page_list, entry, marked_cases=None):
|
|||
return cmd
|
||||
|
||||
|
||||
def _run_search_codes(page, *, preserve_original=True):
|
||||
def _run_search_codes(page, *, preserve_original=True, speaker_fn=None):
|
||||
"""Full Pass 1 -> mock translate -> Pass 2 cycle."""
|
||||
captured = []
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ def _run_search_codes(page, *, preserve_original=True):
|
|||
return _mock_translate(text, history, batch)
|
||||
|
||||
def speaker(name):
|
||||
return _mock_speaker(name)
|
||||
return speaker_fn(name) if speaker_fn is not None else _mock_speaker(name)
|
||||
|
||||
orig_t = mvmz.translateAI
|
||||
orig_s = mvmz.getSpeaker
|
||||
|
|
@ -194,6 +194,45 @@ class TestMVMZSourceOriginal(unittest.TestCase):
|
|||
self.assertEqual(c122["_original"], "変数テスト")
|
||||
self.assertIn("EN_TRANSLATED", c122["parameters"][4])
|
||||
|
||||
def test_101_display_brackets_do_not_leak_into_401_dialogue(self):
|
||||
speakers_seen = []
|
||||
|
||||
def speaker(name):
|
||||
speakers_seen.append(name)
|
||||
return ["Game Description", [0, 0]]
|
||||
|
||||
page = {
|
||||
"list": [
|
||||
{
|
||||
"code": 101,
|
||||
"indent": 0,
|
||||
"parameters": ["", 0, 0, 2, "【[Game Description]】"],
|
||||
"_original": "【ゲーム説明】",
|
||||
},
|
||||
{
|
||||
"code": 401,
|
||||
"indent": 0,
|
||||
"parameters": ["ここから本編スタートとなります。"],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
translated, captured = _run_search_codes(page, speaker_fn=speaker)
|
||||
cmd101, cmd401 = translated["list"]
|
||||
|
||||
self.assertTrue(speakers_seen)
|
||||
self.assertEqual(set(speakers_seen), {"ゲーム説明"})
|
||||
self.assertEqual(cmd101["parameters"][4], "【Game Description】")
|
||||
self.assertEqual(cmd401["parameters"][0], "EN_TRANSLATED")
|
||||
self.assertNotIn("Game Description", cmd401["parameters"][0])
|
||||
self.assertTrue(
|
||||
any(
|
||||
isinstance(item, str) and item.startswith("[Game Description]: ")
|
||||
for payload in captured
|
||||
for item in (payload if isinstance(payload, list) else [payload])
|
||||
)
|
||||
)
|
||||
|
||||
def test_rerun_uses_original_not_display_text(self):
|
||||
page1, captured1 = _run_search_codes(_load_map_excerpt())
|
||||
originals_snapshot = json.dumps(
|
||||
|
|
|
|||
Loading…
Reference in a new issue