Adjust regex, to work with dialogue and speaker

This commit is contained in:
dazedanon 2026-01-21 11:24:52 -06:00
parent 417df900d3
commit 677d23e371
4 changed files with 121 additions and 67 deletions

View file

@ -1077,8 +1077,8 @@ class TranslationTab(QWidget):
["NScript", [".nscript"], handleOnscripter],
["Wolf RPG", [".txt"], handleWOLF],
["Wolf RPG 2", [".txt"], handleWOLF2],
["Regex", [".txt"], handleRegex],
["Text", [".txt"], handleText],
["Regex", [".txt", ".json", ".script", ".csv"], handleRegex],
["Text", [".txt", ".srt"], handleText],
["RenPy", [".rpy"], handleRenpy],
["Unity", [".unity"], handleUnity],
["Images", [".png", ".jpg", ".jpeg"], handleImages],

View file

@ -39,16 +39,16 @@ FILENAME = None
BRACKETNAMES = False
# CSV Configuration Settings (configurable via GUI)
CSV_DELIMITER = "," # CSV delimiter character (comma, semicolon, tab)
SOURCE_COLUMN = 0 # Which column has the source text to translate (0-indexed)
TARGET_COLUMN = 1 # Which column to write translations to
SPEAKER_COLUMN = -1 # Which column has speaker names (-1 = none)
CSV_DELIMITER = " " # CSV delimiter character (comma, semicolon, tab)
SOURCE_COLUMN = 2 # Which column has the source text to translate (0-indexed)
TARGET_COLUMN = 3 # Which column to write translations to
SPEAKER_COLUMN = 1 # Which column has speaker names (-1 = none)
SKIP_HEADER_ROW = False # Skip the first row (header)
USE_TARGET_IF_NOT_EMPTY = False # Use target column text if not empty (T++ style)
WRITE_TO_NEXT_COLUMN = False # Write to column after target instead of overwriting
PARSE_NAME_TAGS = False # Parse :name[] tags in text
PARSE_M_MARKERS = False # Parse \M markers in text
REMOVE_FURIGANA = False # Remove furigana annotations
REMOVE_FURIGANA = True # Remove furigana annotations
SKIP_COMMENT_ROWS = False # Skip rows starting with 'comment'
# Regex - Need to change this if you want to translate from/to other languages. Default is Japanese Regex

View file

@ -201,17 +201,16 @@ def translateRegex(data, filename, translatedList):
speaker = ""
global LOCK, ESTIMATE, FILENAME, PBAR, MISMATCH
i = 0
# Define regex patterns outside loop
lineRegexSpeaker = r'"name":\s?"(.+)",'
choiceRegex = r"\$menu_item.+?,(.*?),"
titleRegex = r"title\s'(.*)'$"
setgamedatatitleRegex = r'\\setgamedatatitle\("(.+?)"\)'
dlgRegex = r'\"text\":\s?\"(.+)\",'
selRegex = r'\\sel\((.+)\)'
while i < len(data):
voice = False
lineRegexText = r'●(?:「| |)+(.+?)(?:[」)]|$)+'
lineRegexSpeaker = r"\\text\(\"(.+?)\"\)"
choiceRegex = r"\$menu_item.+?,(.*?),"
titleRegex = r"title\s'(.*)'$"
setgamedatatitleRegex = r'\\setgamedatatitle\("(.+?)"\)'
dlgRegex = r'\\dlg\("(.+?)"\)'
selRegex = r'\\sel\((.+)\)'
speaker = ""
# Setgamedatatitle
match = re.search(setgamedatatitleRegex, data[i])
@ -260,23 +259,34 @@ def translateRegex(data, filename, translatedList):
tokens[1] += response[1][1]
data[i] = data[i].replace(match.group(1), speaker)
# Dlg (Dialogue prompt/choice)
# Dlg (JSON text field)
match = re.search(dlgRegex, data[i])
if match:
jaString = match.group(1)
# Pass 1 - Collect for batch translation
if not translatedList:
choiceList.append(match.group(1))
# Add with speaker prefix if available
if speaker:
stringList.append(f"[{speaker}]: {jaString}")
else:
stringList.append(jaString)
# Reset speaker after using it
speaker = ""
# Pass 2 - Apply translated text
else:
if choiceList:
if stringList:
# Grab and Pop
translatedText = choiceList[0]
choiceList.pop(0)
translatedText = stringList[0]
stringList.pop(0)
# Set to None if empty list
if len(choiceList) <= 0:
choiceList = None
if len(stringList) <= 0:
stringList = None
# Remove speaker prefix from translation
translatedText = re.sub(r"^\[?(.+?)\]?\s?[|:]\s?", "", translatedText)
# Escape Quotes
translatedText = translatedText.replace('"', '\\"')
@ -414,11 +424,15 @@ def translateRegex(data, filename, translatedList):
if not translatedList:
stringListTL = []
choiceListTL = []
# Set total progress bar for all items
totalItems = len(stringList) + len(choiceList)
if totalItems > 0:
PBAR.total = totalItems
PBAR.refresh()
# String List
if stringList:
PBAR.total = len(stringList)
PBAR.refresh()
response = translateAI(stringList, "Reply with the English Translation", True)
tokens[0] += response[1][0]
tokens[1] += response[1][1]

View file

@ -2534,54 +2534,94 @@ def searchCodes(page, pbar, jobList, filename):
if "code" in codeList[i] and (codeList[i]["code"] == 355 or codeList[i]["code"] == 655) and CODE355655 is True:
jaString = codeList[i]["parameters"][0]
# Patterns: (regex, multiline) - multiline=True means it spans 355 + following 655 codes
patterns = {
# "テキスト-": (r"テキスト-(.+)")
# "=": (r'=\s?(.*)",'),
# "var text": (r"var\stext\d+\s=\s\"(.+)\""),
# "logtxt = ": (r"logtxt\s=\s'(.+)'"
# ".setNickname": (r'.setNickname\(\\?"(.+?)\\?"\)'
# "_subject=": r'_subject=(.+?)(?=[_\\"\]])'
# "text =": (r"text\s*=\s*'(.+[^\\])'"),
# "const text": (r'(const\stext\s?=\s?"(.+)";?)'),
# "ex_a_name": (r'ex_a_name\(\d+,"(.+)"\)'),
# "gameVariables.setValue": (r'\$gameVariables\.setValue\(\d+,\s*"([^"]*)"\)'),
# "BattleManager._logWindow.push('addText'": (r"BattleManager._logWindow.push\('addText',\s'(.+)'\)"),
"BattleManager._logWindow.addText": (r"BattleManager._logWindow.addText\('(.+)'\)"),
# "テキスト-": (r"テキスト-(.+)", False),
# "=": (r'=\s?(.*)",', False),
# "var text": (r"var\stext\d+\s=\s\"(.+)\"", False),
# "logtxt = ": (r"logtxt\s=\s'(.+)'", False),
# ".setNickname": (r'.setNickname\(\\?"(.+?)\\?"\)', False),
# "_subject=": (r'_subject=(.+?)(?=[_\\"\]])', False),
# "text =": (r"text\s*=\s*'(.+[^\\])'", False),
# "const text": (r'(const\stext\s?=\s?"(.+)";?)', False),
# "ex_a_name": (r'ex_a_name\(\d+,"(.+)"\)', False),
# "gameVariables.setValue": (r'\$gameVariables\.setValue\(\d+,\s*"([^"]*)"\)', False),
# "BattleManager._logWindow.push('addText'": (r"BattleManager._logWindow.push\('addText',\s'(.+)'\)", False),
# "BattleManager._logWindow.addText": (r"BattleManager._logWindow.addText\('(.+)'\)", False),
# "this.BLogAdd": (r'this\.BLogAdd\([\s,\d]+"(.+)"\);', False),
# "Fuki_Set": (r'Fuki_Set\([\s,\d\w\W]+?"(.+?)",', False),
# "_EventSetting": (r'_EventSetting[\s,\d\w\W]+?"(.+?)";', False),
# "this.Menu_SexTxtSet(": (r'"(.+)"', True),
# "Rn_RsltTxtArr": (r'"(.+)"', True),
}
for key, (regex) in patterns.items():
for key, (regex, multiline) in patterns.items():
if key in jaString:
match = re.search(regex, jaString)
if match:
# Check if the match contains actual text (not just numbers/special chars)
if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa---\uFF61-\uFF9F]', match.group(1)):
continue
# Skip if IGNORETLTEXT is enabled and no Japanese text
if IGNORETLTEXT and not re.search(LANGREGEX, match.group(1)):
continue
# Pass 1
if setData:
list355655.append(match.group(1))
# Pass 2
else:
# Grab and Replace
translatedText = list355655[0]
list355655.pop(0)
# Ensure no quotes in gameVariables
if "gameVariables.setValue" in codeList[i]["parameters"][0]:
translatedText = translatedText.replace('\"', "'")
# Multi-line pattern: spans 355 + subsequent 655 codes
# Each 655 line is translated separately (as a batch) and stays in its own line
if multiline and codeList[i]["code"] == 355:
textLines = []
textLineIndices = []
j = i + 1
while j < len(codeList) and codeList[j]["code"] == 655:
param = codeList[j]["parameters"][0] if codeList[j]["parameters"] else ""
textMatch = re.search(regex, param)
if textMatch:
text = textMatch.group(1)
if not (IGNORETLTEXT and not re.search(LANGREGEX, text)):
textLines.append(text)
textLineIndices.append(j)
j += 1
if textLines:
if setData:
# Store each line separately for batch translation
for text in textLines:
list355655.append(text)
else:
# Apply each translated line back to its corresponding 655 code
for lineIdx in textLineIndices:
if len(list355655) > 0:
translatedText = list355655[0]
list355655.pop(0)
# Replace quotes with apostrophes to avoid breaking plugin
translatedText = translatedText.replace('\\"', "'")
translatedText = translatedText.replace('"', "'")
origParam = codeList[lineIdx]["parameters"][0]
origMatch = re.search(regex, origParam)
if origMatch:
codeList[lineIdx]["parameters"][0] = origParam.replace(origMatch.group(1), translatedText)
# Ensure ' has exactly 2 backslashes (don't double-escape if already escaped)
if "BattleManager" in codeList[i]["parameters"][0]:
translatedText = re.sub(r"(?<!\\)'", r"\\'", translatedText)
i = j - 1
break
# Single-line pattern
else:
match = re.search(regex, jaString)
if match:
if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa---\uFF61-\uFF9F]', match.group(1)):
continue
# Set
codeList[i]["parameters"][0] = jaString.replace(match.group(1), translatedText)
break
if IGNORETLTEXT and not re.search(LANGREGEX, match.group(1)):
continue
if setData:
list355655.append(match.group(1))
else:
translatedText = list355655[0]
list355655.pop(0)
if "gameVariables.setValue" in codeList[i]["parameters"][0]:
translatedText = translatedText.replace('\"', "'")
if "BattleManager" in codeList[i]["parameters"][0]:
translatedText = re.sub(r"(?<!\\)'", r"\\'", translatedText)
codeList[i]["parameters"][0] = jaString.replace(match.group(1), translatedText)
break
## Event Code: 408 (Script)
if "code" in codeList[i] and (codeList[i]["code"] == 408) and CODE408 is True: