woo
This commit is contained in:
parent
af748bb016
commit
a08fa7aef8
2 changed files with 214 additions and 128 deletions
|
|
@ -122,80 +122,93 @@ class TranslationWorker(QThread):
|
|||
def run_module_in_process(self, filename, estimate_only):
|
||||
"""Run a module handler in a separate process for better control."""
|
||||
try:
|
||||
# Create a separate Python process to run the module
|
||||
# This allows us to terminate it if needed
|
||||
script_content = f'''
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import io
|
||||
from contextlib import redirect_stdout, redirect_stderr
|
||||
|
||||
# Set UTF-8 encoding for stdout to handle Unicode characters
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
# Add project root to path
|
||||
project_root = Path(r"{self.project_root}")
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
try:
|
||||
# Change to project directory
|
||||
os.chdir(str(project_root))
|
||||
|
||||
# Import and run the handler
|
||||
{self.get_import_statement()}
|
||||
|
||||
# Run the handler and capture the result
|
||||
handler_result = {self.get_handler_call()}(r"{filename}", {estimate_only})
|
||||
|
||||
# Print the result
|
||||
if handler_result:
|
||||
print(f"RESULT:{{handler_result}}")
|
||||
else:
|
||||
print("RESULT:Fail")
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
||||
print(f"ERROR:{{error_msg}}")
|
||||
sys.exit(1)
|
||||
'''
|
||||
|
||||
# Write script to temporary file
|
||||
temp_script = self.project_root / "temp_translation_script.py"
|
||||
with open(temp_script, 'w', encoding='utf-8') as f:
|
||||
f.write(script_content)
|
||||
# Use the external subprocess runner script
|
||||
runner_script = self.project_root / "util" / "subprocess_runner.py"
|
||||
if not runner_script.exists():
|
||||
self.emit_log(f"❌ Subprocess runner script not found: {runner_script}")
|
||||
return "Fail"
|
||||
|
||||
# Run the script in a separate process
|
||||
env = os.environ.copy()
|
||||
env['PYTHONIOENCODING'] = 'utf-8' # Force UTF-8 encoding
|
||||
|
||||
process = subprocess.Popen(
|
||||
[sys.executable, str(temp_script)],
|
||||
[
|
||||
sys.executable,
|
||||
str(runner_script),
|
||||
str(self.project_root),
|
||||
self.module_info[0], # module name
|
||||
filename,
|
||||
str(estimate_only)
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
encoding='utf-8',
|
||||
errors='replace',
|
||||
cwd=str(self.project_root),
|
||||
env=env
|
||||
env=env,
|
||||
bufsize=1 # Line buffered
|
||||
)
|
||||
|
||||
# Track the process for potential termination
|
||||
self.running_processes.append(process)
|
||||
|
||||
# Wait for completion
|
||||
stdout, stderr = process.communicate()
|
||||
# Read output in real-time to capture progress
|
||||
stdout_lines = []
|
||||
stderr_lines = []
|
||||
|
||||
def read_stdout():
|
||||
"""Read stdout line by line."""
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
if not line:
|
||||
break
|
||||
line = line.strip()
|
||||
if line.startswith('PROGRESS:'):
|
||||
# Parse progress: PROGRESS:filename:current:total
|
||||
try:
|
||||
parts = line.split(':', 3)
|
||||
if len(parts) == 4:
|
||||
_, desc, current, total = parts
|
||||
self.item_progress_signal.emit(int(current), int(total))
|
||||
# Update translating label with filename
|
||||
if desc:
|
||||
self.emit_log(f"📝 Translating: {desc} ({current}/{total})")
|
||||
except Exception:
|
||||
pass # Ignore malformed progress lines
|
||||
else:
|
||||
stdout_lines.append(line)
|
||||
process.stdout.close()
|
||||
|
||||
def read_stderr():
|
||||
"""Read stderr line by line."""
|
||||
for line in iter(process.stderr.readline, ''):
|
||||
if not line:
|
||||
break
|
||||
stderr_lines.append(line.strip())
|
||||
process.stderr.close()
|
||||
|
||||
# Start reader threads
|
||||
stdout_thread = threading.Thread(target=read_stdout, daemon=True)
|
||||
stderr_thread = threading.Thread(target=read_stderr, daemon=True)
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
# Wait for process completion
|
||||
process.wait()
|
||||
|
||||
# Wait for reader threads to finish
|
||||
stdout_thread.join(timeout=1.0)
|
||||
stderr_thread.join(timeout=1.0)
|
||||
|
||||
# Combine output
|
||||
stdout = '\n'.join(stdout_lines)
|
||||
stderr = '\n'.join(stderr_lines)
|
||||
|
||||
# Remove from tracking
|
||||
if process in self.running_processes:
|
||||
self.running_processes.remove(process)
|
||||
|
||||
# Clean up temp file
|
||||
if temp_script.exists():
|
||||
temp_script.unlink()
|
||||
|
||||
# Check if process was terminated by stop signal
|
||||
if self.should_stop:
|
||||
return "Stopped"
|
||||
|
|
@ -229,82 +242,6 @@ except Exception as e:
|
|||
except Exception as e:
|
||||
self.emit_log(f"❌ Failed to run module process: {str(e)}")
|
||||
return "Fail"
|
||||
|
||||
def get_import_statement(self):
|
||||
"""Get the import statement for the selected module."""
|
||||
module_name = self.module_info[0]
|
||||
if "RPG Maker MV/MZ" in module_name:
|
||||
return "from modules.rpgmakermvmz import handleMVMZ"
|
||||
elif "RPG Maker Ace" in module_name:
|
||||
return "from modules.rpgmakerace import handleACE"
|
||||
elif "CSV" in module_name:
|
||||
return "from modules.csv import handleCSV"
|
||||
elif "Tyrano" in module_name:
|
||||
return "from modules.tyrano import handleTyrano"
|
||||
elif "Kirikiri" in module_name:
|
||||
return "from modules.kirikiri import handleKirikiri"
|
||||
elif "JSON" in module_name:
|
||||
return "from modules.json import handleJSON"
|
||||
elif "Lune" in module_name:
|
||||
return "from modules.lune import handleLune"
|
||||
elif "NScript" in module_name:
|
||||
return "from modules.nscript import handleOnscripter"
|
||||
elif "Wolf RPG 2" in module_name:
|
||||
return "from modules.wolf2 import handleWOLF2"
|
||||
elif "Wolf RPG" in module_name:
|
||||
return "from modules.wolf import handleWOLF"
|
||||
elif "Regex" in module_name:
|
||||
return "from modules.regex import handleRegex"
|
||||
elif "Text" in module_name:
|
||||
return "from modules.text import handleText"
|
||||
elif "RenPy" in module_name:
|
||||
return "from modules.renpy import handleRenpy"
|
||||
elif "Unity" in module_name:
|
||||
return "from modules.unity import handleUnity"
|
||||
elif "Images" in module_name:
|
||||
return "from modules.images import handleImages"
|
||||
elif "Plugin" in module_name:
|
||||
return "from modules.rpgmakerplugin import handlePlugin"
|
||||
else:
|
||||
return "# Unknown module"
|
||||
|
||||
def get_handler_call(self):
|
||||
"""Get the handler function call for the selected module."""
|
||||
module_name = self.module_info[0]
|
||||
if "RPG Maker MV/MZ" in module_name:
|
||||
return "handleMVMZ"
|
||||
elif "RPG Maker Ace" in module_name:
|
||||
return "handleACE"
|
||||
elif "CSV" in module_name:
|
||||
return "handleCSV"
|
||||
elif "Tyrano" in module_name:
|
||||
return "handleTyrano"
|
||||
elif "Kirikiri" in module_name:
|
||||
return "handleKirikiri"
|
||||
elif "JSON" in module_name:
|
||||
return "handleJSON"
|
||||
elif "Lune" in module_name:
|
||||
return "handleLune"
|
||||
elif "NScript" in module_name:
|
||||
return "handleOnscripter"
|
||||
elif "Wolf RPG 2" in module_name:
|
||||
return "handleWOLF2"
|
||||
elif "Wolf RPG" in module_name:
|
||||
return "handleWOLF"
|
||||
elif "Regex" in module_name:
|
||||
return "handleRegex"
|
||||
elif "Text" in module_name:
|
||||
return "handleText"
|
||||
elif "RenPy" in module_name:
|
||||
return "handleRenpy"
|
||||
elif "Unity" in module_name:
|
||||
return "handleUnity"
|
||||
elif "Images" in module_name:
|
||||
return "handleImages"
|
||||
elif "Plugin" in module_name:
|
||||
return "handlePlugin"
|
||||
else:
|
||||
return "lambda f, e: 'Unknown module'"
|
||||
|
||||
def run(self):
|
||||
"""Run the translation process."""
|
||||
|
|
|
|||
149
util/subprocess_runner.py
Normal file
149
util/subprocess_runner.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
"""
|
||||
Subprocess runner for translation modules.
|
||||
This script runs in a separate process to execute translation modules
|
||||
and reports progress back to the GUI.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import io
|
||||
import threading
|
||||
import time
|
||||
|
||||
# Set UTF-8 encoding for stdout to handle Unicode characters
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
# Progress monitoring thread
|
||||
progress_active = True
|
||||
last_reported = {'state': None}
|
||||
|
||||
|
||||
def monitor_progress():
|
||||
"""Monitor module PBAR and report progress."""
|
||||
global progress_active
|
||||
while progress_active:
|
||||
try:
|
||||
# Try to get PBAR from any loaded module
|
||||
for module_name in list(sys.modules.keys()):
|
||||
if module_name.startswith('modules.'):
|
||||
module = sys.modules[module_name]
|
||||
if hasattr(module, 'PBAR') and module.PBAR is not None:
|
||||
pbar = module.PBAR
|
||||
desc = getattr(pbar, 'desc', '') or ''
|
||||
n = getattr(pbar, 'n', 0)
|
||||
total = getattr(pbar, 'total', 0)
|
||||
|
||||
current_state = (desc, n, total)
|
||||
if current_state != last_reported['state']:
|
||||
print(f"PROGRESS:{desc}:{n}:{total}", flush=True)
|
||||
last_reported['state'] = current_state
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
def run_handler(project_root, module_name, filename, estimate_only):
|
||||
"""Run a translation module handler."""
|
||||
global progress_active
|
||||
|
||||
# Add project root to path
|
||||
project_root = Path(project_root)
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
# Start progress monitoring thread
|
||||
monitor_thread = threading.Thread(target=monitor_progress, daemon=True)
|
||||
monitor_thread.start()
|
||||
|
||||
try:
|
||||
# Change to project directory
|
||||
os.chdir(str(project_root))
|
||||
|
||||
# Import the appropriate module and get handler
|
||||
handler = None
|
||||
if "RPG Maker MV/MZ" in module_name:
|
||||
from modules.rpgmakermvmz import handleMVMZ
|
||||
handler = handleMVMZ
|
||||
elif "RPG Maker Ace" in module_name:
|
||||
from modules.rpgmakerace import handleACE
|
||||
handler = handleACE
|
||||
elif "CSV" in module_name:
|
||||
from modules.csv import handleCSV
|
||||
handler = handleCSV
|
||||
elif "Tyrano" in module_name:
|
||||
from modules.tyrano import handleTyrano
|
||||
handler = handleTyrano
|
||||
elif "Kirikiri" in module_name:
|
||||
from modules.kirikiri import handleKirikiri
|
||||
handler = handleKirikiri
|
||||
elif "JSON" in module_name:
|
||||
from modules.json import handleJSON
|
||||
handler = handleJSON
|
||||
elif "Lune" in module_name:
|
||||
from modules.lune import handleLune
|
||||
handler = handleLune
|
||||
elif "NScript" in module_name:
|
||||
from modules.nscript import handleOnscripter
|
||||
handler = handleOnscripter
|
||||
elif "Wolf RPG 2" in module_name:
|
||||
from modules.wolf2 import handleWOLF2
|
||||
handler = handleWOLF2
|
||||
elif "Wolf RPG" in module_name:
|
||||
from modules.wolf import handleWOLF
|
||||
handler = handleWOLF
|
||||
elif "Regex" in module_name:
|
||||
from modules.regex import handleRegex
|
||||
handler = handleRegex
|
||||
elif "Text" in module_name:
|
||||
from modules.text import handleText
|
||||
handler = handleText
|
||||
elif "RenPy" in module_name:
|
||||
from modules.renpy import handleRenpy
|
||||
handler = handleRenpy
|
||||
elif "Unity" in module_name:
|
||||
from modules.unity import handleUnity
|
||||
handler = handleUnity
|
||||
elif "Images" in module_name:
|
||||
from modules.images import handleImages
|
||||
handler = handleImages
|
||||
elif "Plugin" in module_name:
|
||||
from modules.rpgmakerplugin import handlePlugin
|
||||
handler = handlePlugin
|
||||
else:
|
||||
print(f"ERROR:Unknown module: {module_name}")
|
||||
sys.exit(1)
|
||||
|
||||
# Run the handler
|
||||
handler_result = handler(filename, estimate_only)
|
||||
|
||||
# Stop progress monitoring
|
||||
progress_active = False
|
||||
|
||||
# Print the result
|
||||
if handler_result:
|
||||
print(f"RESULT:{handler_result}")
|
||||
else:
|
||||
print("RESULT:Fail")
|
||||
|
||||
except Exception as e:
|
||||
progress_active = False
|
||||
import traceback
|
||||
error_msg = str(e).encode('ascii', 'ignore').decode('ascii')
|
||||
print(f"ERROR:{error_msg}")
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 5:
|
||||
print("ERROR:Invalid arguments")
|
||||
sys.exit(1)
|
||||
|
||||
project_root = sys.argv[1]
|
||||
module_name = sys.argv[2]
|
||||
filename = sys.argv[3]
|
||||
estimate_only = sys.argv[4].lower() == 'true'
|
||||
|
||||
run_handler(project_root, module_name, filename, estimate_only)
|
||||
Loading…
Reference in a new issue