From 6ad62d95c27ca402c0852c9d633832bc99d555b6 Mon Sep 17 00:00:00 2001 From: dazedanon Date: Wed, 8 Oct 2025 18:30:14 -0500 Subject: [PATCH] Lots of changes in regex and plugin and adjust langregex --- modules/main.py | 7 +-- modules/regex.py | 56 +++++++++++------------- modules/rpgmakermvmz.py | 3 +- modules/rpgmakerplugin.py | 91 +++++++++++++++++++++++++-------------- 4 files changed, 86 insertions(+), 71 deletions(-) diff --git a/modules/main.py b/modules/main.py index 603d967..520df07 100644 --- a/modules/main.py +++ b/modules/main.py @@ -75,11 +75,8 @@ MODULES = [ # Info Message tqdm.write( - Fore.LIGHTYELLOW_EX - + "WARNING: Once the translation starts do not close it unless you want to lose your \ -translated data. If a file fails or gets stuck, translated lines will remain translated so you don't have \ -to worry about being charged twice. You can simply copy the file generated in /translations back over to \ -/files and start the script again. It will skip over any translated text." + Fore.CYAN + + "-Dazed MTL Tool -" + Fore.RESET, end="\n\n", ) diff --git a/modules/regex.py b/modules/regex.py index 35d8469..b837b1c 100644 --- a/modules/regex.py +++ b/modules/regex.py @@ -214,7 +214,7 @@ def translateRegex(data, filename, translatedList): while i < len(data): voice = False lineRegexText = r'●(?:「| |()+(.+?)(?:[」)]|$)+' - lineRegexSpeaker = r"●.+●([^ 「(].+)" + lineRegexSpeaker = r"text\(\"(.+)\"\)" choiceRegex = r"\$menu_item.+?,(.*?)," titleRegex = r"title\s'(.*)'$" speaker = "" @@ -240,41 +240,34 @@ def translateRegex(data, filename, translatedList): # Speaker match = re.search(lineRegexSpeaker, data[i]) if match: - if match.group(1): - if match.group(1) == "主人公": - speaker = "Protagonist" - else: - response = getSpeaker(match.group(1)) - speaker = response[0] - tokens[0] += response[1][0] - tokens[1] += response[1][1] - if translatedList: - data[i] = data[i].replace(match.group(1), speaker) - save_progress_lines(data, filename) - i += 3 - else: - speaker = None - elif data[i] == "Protagonist\n": - speaker = "Protagonist" - i += 1 + response = getSpeaker(match.group(1)) + speaker = response[0] + tokens[0] += response[1][0] + tokens[1] += response[1][1] + data[i] = data[i].replace(match.group(1), speaker) # Dialogue - match = re.search(lineRegexText, data[i]) - jaString = None - if match and match.group(0).replace("\u3000", "") != '\n': - # Set String - jaString = match.group(1) - - # Save Original String - originalString = jaString + # Grab multi-line text + if "\\text" in data[i].strip(): + lines = [] + i += 1 # Pass 1 if not translatedList: + while "\\endtext" not in data[i].strip(): + lines.append(data[i]) + i += 1 + if lines: + jaString = "".join(lines).replace("\n", "") + + # Save Original String + originalString = jaString + # Strip Spaces jaString = jaString.strip() # Remove Textwrap - jaString = jaString.replace('\\n', ' ') + jaString = jaString.replace('\n', ' ') if jaString: if speaker: @@ -305,13 +298,12 @@ def translateRegex(data, filename, translatedList): translatedText = translatedText.replace(">", ")") # Textwrap - translatedText = dazedwrap.wrapText(translatedText, width=WIDTH).replace("\n", "\\n") + translatedText = dazedwrap.wrapText(translatedText, width=WIDTH) # Set Data - if "「" in data[i-1] and "」" not in translatedText: - data[i] = data[i].replace(originalString, f"「{translatedText}」") - else: - data[i] = data[i].replace(originalString, f"{translatedText}") + while "\\endtext" not in data[i].strip(): + del data[i] + data.insert(i, f"{translatedText}\n") save_progress_lines(data, filename) # Choices diff --git a/modules/rpgmakermvmz.py b/modules/rpgmakermvmz.py index 941f774..be7cd4d 100644 --- a/modules/rpgmakermvmz.py +++ b/modules/rpgmakermvmz.py @@ -52,7 +52,7 @@ _speakerCacheLock = threading.Lock() SPEAKER_COLLECTED = [] # Original speaker names collected during parse mode (untranslated) # Regex - Need to change this if you want to translate from/to other languages. Default is Japanese Regex -LANGREGEX = r"[一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]+" +LANGREGEX = r"[\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uFF00-\uFFEF]+" # Get pricing configuration based on the model PRICING_CONFIG = getPricingConfig(MODEL) @@ -1450,6 +1450,7 @@ def searchCodes(page, pbar, jobList, filename): jaString = jaString.replace("・", ".") jaString = jaString.replace("「", '"') jaString = jaString.replace("」", '"') + jaString = jaString.replace("~", '~') # Check if there is text to translate if not re.search(r"\w+", jaString): diff --git a/modules/rpgmakerplugin.py b/modules/rpgmakerplugin.py index e8dffcb..4b5e4c1 100644 --- a/modules/rpgmakerplugin.py +++ b/modules/rpgmakerplugin.py @@ -101,17 +101,21 @@ def handlePlugin(filename, estimate): else: try: - with open("translated/" + filename, "w", encoding="utf_8", errors="ignore") as outFile: - start = time.time() - translatedData = openFiles(filename) + # Perform translation first; incremental progress writes happen during translation. + # We no longer keep the destination file open simultaneously to avoid Windows locking issues + # during atomic os.replace operations inside save_progress_lines. + start = time.time() + translatedData = openFiles(filename) - # Print Result - end = time.time() - outFile.writelines(translatedData[0]) - tqdm.write(getResultString(translatedData, end - start, filename)) - with LOCK: - TOKENS[0] += translatedData[1][0] - TOKENS[1] += translatedData[1][1] + # Ensure final state is flushed (in case no incremental writes occurred for some reason). + save_progress_lines(translatedData[0], filename) + + # Print Result + end = time.time() + tqdm.write(getResultString(translatedData, end - start, filename)) + with LOCK: + TOKENS[0] += translatedData[1][0] + TOKENS[1] += translatedData[1][1] except Exception: traceback.print_exc() return "Fail" @@ -184,18 +188,31 @@ def save_progress_lines(lines, filename, encoding="utf_8"): try: if ESTIMATE: return + global LOCK os.makedirs("translated", exist_ok=True) - tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated") - try: - with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file: - tmp_file.writelines(lines) - os.replace(tmp_path, os.path.join("translated", filename)) - finally: - if os.path.exists(tmp_path): - try: - os.remove(tmp_path) - except OSError: - pass + # Use a single lock to prevent concurrent replace attempts on Windows (which causes PermissionError) + with LOCK: + tmp_fd, tmp_path = tempfile.mkstemp(prefix=f"{filename}.", suffix=".tmp", dir="translated") + try: + with os.fdopen(tmp_fd, "w", encoding=encoding, newline="\n", errors="ignore") as tmp_file: + tmp_file.writelines(lines) + + dest_path = os.path.join("translated", filename) + # Retry a few times in case another process/thread still has the file open momentarily. + for attempt in range(5): + try: + os.replace(tmp_path, dest_path) + break + except PermissionError: + if attempt == 4: + raise + time.sleep(0.1 * (attempt + 1)) + finally: + if os.path.exists(tmp_path): + try: + os.remove(tmp_path) + except OSError: + pass except Exception: traceback.print_exc() @@ -235,37 +252,44 @@ def translatePlugin(data, pbar, filename, translatedList): while i < len(data): voice = False speaker = "" - newline = r"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n" - colorCode = r"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\c" # Custom # Useful Regex's # r'"Text[\\]+":[\\]+"(.+?)[\\]+",' # r'"HelpText[\\]+":[\\]+"(.+?)[\\]+",' # r"this.drawTextEx\(\\'(.+?)\'," - regex = r"this.drawTextEx\(\\'(.+?)\'," + regex = r'Text[\\]+":[\\]+"(.*?)[\\]+?[\\]' matchList = re.findall(regex, data[i]) if len(matchList) > 0: for match in matchList: # Save Original String jaString = match originalString = jaString + newline = None + colorCode = None + + # Make sure it contains Japanese + if not re.search(LANGREGEX, jaString): + continue # Make sure didn't grab \\ if re.search(r"^[\\]+$", jaString): - i += 1 continue # Replace \n and \c - jaString = re.sub(r"\\+n", r"\\n", jaString) - jaString = re.sub(r"\\+C", r"\\C", jaString) + if re.search(r"\\+n", jaString): + newline = re.search(r"\\+n", jaString).group(0) + jaString = re.sub(r"\\+n", r"\\n", jaString) + if re.search(r"\\+C", jaString): + colorCode = re.search(r"\\+C", jaString).group(0) + jaString = re.sub(r"\\+C", r"\\C", jaString) # Remove any textwrap jaString = jaString.replace("\\n", " ") if jaString.replace("\u3000", "") and jaString: # Pass 1 - if setData == False: + if setData == False and jaString.strip(): custom.append(jaString.strip()) # Pass 2 @@ -283,12 +307,13 @@ def translatePlugin(data, pbar, filename, translatedList): translatedText = re.sub(r"([^\\'])'", r"\1՚", translatedText) translatedText = re.sub(r"([^\\'])\"", r"\1՚", translatedText) - # Textwrap - translatedText = dazedwrap.wrapText(translatedText, WIDTH) - # Replace \n and \c - translatedText = re.sub(r"\n", re.escape(newline), translatedText) - translatedText = re.sub(r"\n", re.escape(colorCode), translatedText) + if newline: + # Textwrap + # translatedText = dazedwrap.wrapText(translatedText, WIDTH) + translatedText = re.sub(r"\n", re.escape(newline), translatedText) + if colorCode: + translatedText = re.sub(r"\n", re.escape(colorCode), translatedText) # Set Data with open("log/translations.txt", "a+", encoding="utf-8") as tlFile: