|
Title: WinOLS Translator (Python Script) Post by: Misterdray on October 31, 2025, 08:40:36 PM Just wanted to share a Python Script that can be used to translate a WinOLS .json export from German to English which can then be imported back into WinOLS as English. When using this script, you must be connected to the internet as it uses Google Translation and it does take a little bit of time to do. I have also included a script that can be used to split of the .json file into multiple files so the translation can go quicker. These multiple files can still be imported back into WinOLS individually.
TRANSLATOR SCRIPT ____________________________________ import json import asyncio from googletrans import Translator import chardet import re import time import tkinter as tk from tkinter import filedialog async def translate_json(input_file, output_file, retries=3, delay=1.5): translator = Translator() # --- Detect encoding --- with open(input_file, "rb") as f: raw_data = f.read() encoding = chardet.detect(raw_data)["encoding"] or "utf-8" print(f"Detected encoding: {encoding}") text = raw_data.decode(encoding, errors="replace") # --- Clean invalid chars --- cleaned_text = re.sub(r"[\x00-\x08\x0B-\x0C\x0E-\x1F]", "", text) data = json.loads(cleaned_text) async def safe_translate(text): if not text.strip(): return text for attempt in range(retries): try: result = await translator.translate(text, src="de", dest="en") return result.text except Exception as e: print(f"Error translating '{text}': {e} (attempt {attempt+1}/{retries})") await asyncio.sleep(delay) print(f"Keeping original text for '{text}' (translation failed).") return text async def translate_field(obj): if isinstance(obj, dict): for key, value in obj.items(): if key in ["IDName", "Name", "FolderName"] and isinstance(value, str): obj[key] = await safe_translate(value) else: await translate_field(value) elif isinstance(obj, list): for item in obj: await translate_field(item) await translate_field(data) with open(output_file, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=4) print(f"Translation complete. Saved as {output_file}") if __name__ == "__main__": # --- File selection --- root = tk.Tk() root.withdraw() # Hide main window print("Select the input JSON file...") input_path = filedialog.askopenfilename( title="Select JSON file to translate", filetypes=[("JSON Files", "*.json"), ("All Files", "*.*")] ) if not input_path: print("No input file selected. Exiting.") exit() print("Choose where to save the translated JSON file...") output_path = filedialog.asksaveasfilename( title="Save translated JSON file as", defaultextension=".json", filetypes=[("JSON Files", "*.json")], initialfile="translated.json" ) if not output_path: print("No output path. Exiting.") exit() asyncio.run(translate_json(input_path, output_path)) Title: Re: WinOLS Translator (Python Script) Post by: Misterdray on October 31, 2025, 08:45:33 PM ____________________________________ Split .json SCRIPT ____________________________________ import json import os import math import tkinter as tk from tkinter import filedialog def split_list(lst, n): """Return exactly n lists distributing elements as evenly as possible.""" total = len(lst) base = total // n rem = total % n sizes = [(base + (1 if i < rem else 0)) for i in range(n)] out = [] idx = 0 for s in sizes: out.append(lst[idx: idx + s]) idx += s return out def split_items(items, n): """Split a list of (key,value) pairs into n chunks (lists of pairs).""" total = len(items) base = total // n rem = total % n sizes = [(base + (1 if i < rem else 0)) for i in range(n)] out = [] idx = 0 for s in sizes: out.append(items[idx: idx + s]) idx += s return out def split_json_file(skip_empty=False): root = tk.Tk() root.withdraw() input_path = filedialog.askopenfilename( title="Select a JSON file", filetypes=[("JSON Files", "*.json")] ) if not input_path: print("No file selected. Exiting.") return # number of splits while True: try: num_splits = int(input("How many files would you like to split it into? ").strip()) if num_splits < 1: print("Enter a positive integer.") continue break except ValueError: print("Enter a valid integer.") # read using windows-1252 (as you said) try: with open(input_path, "r", encoding="windows-1252") as f: data = json.load(f) except Exception as e: print("Failed to read JSON:", e) return # prepare output base and folder output_dir = filedialog.askdirectory(title="Select folder to save split files") if not output_dir: print("No folder selected. Exiting.") return default_base = os.path.splitext(os.path.basename(input_path))[0] + "_part" base_name = input(f"Enter base name for split files (default: '{default_base}'): ").strip() or default_base # Helper to write a JSON object to disk def write_json(obj, idx, total_width): filename = f"{base_name}_{str(idx).zfill(total_width)}.json" path = os.path.join(output_dir, filename) with open(path, "w", encoding="utf-8") as out: json.dump(obj, out, indent=2, ensure_ascii=False) return path # Decide splitting strategy wrote_any = False total_width = len(str(num_splits)) if isinstance(data, list): # straightforward: split list elements parts = split_list(data, num_splits) for i, part in enumerate(parts, start=1): if skip_empty and len(part) == 0: print(f"Skipping empty part {i}") continue path = write_json(part, i, total_width) print(f"Saved {path} ({len(part)} items)") wrote_any = True elif isinstance(data, dict): keys = list(data.keys()) if len(keys) > 1: # split top-level key/value pairs across files items = [(k, data[k]) for k in keys] chunks = split_items(items, num_splits) for i, chunk in enumerate(chunks, start=1): if skip_empty and len(chunk) == 0: print(f"Skipping empty part {i}") continue out_dict = {k: v for k, v in chunk} path = write_json(out_dict, i, total_width) print(f"Saved {path} ({len(chunk)} keys)") wrote_any = True elif len(keys) == 1: # single key at top-level — inspect its value top_key = keys[0] inner = data[top_key] if isinstance(inner, list): # split inner list and wrap back with same top-level key parts = split_list(inner, num_splits) for i, part in enumerate(parts, start=1): if skip_empty and len(part) == 0: print(f"Skipping empty part {i}") continue out_obj = {top_key: part} path = write_json(out_obj, i, total_width) print(f"Saved {path} ({len(part)} items under '{top_key}')") wrote_any = True elif isinstance(inner, dict): # split inner dict items across files and wrap back inner_items = list(inner.items()) chunks = split_items(inner_items, num_splits) for i, chunk in enumerate(chunks, start=1): if skip_empty and len(chunk) == 0: print(f"Skipping empty part {i}") continue out_inner = {k: v for k, v in chunk} out_obj = {top_key: out_inner} path = write_json(out_obj, i, total_width) print(f"Saved {path} ({len(chunk)} keys under '{top_key}')") wrote_any = True else: # scalar or unknown single-object — can't meaningfully split inner structure print("Top-level is a single key with a scalar/non-splittable value.") # We'll create first file with the full object and optionally empty others (or skip) if not skip_empty: for i in range(1, num_splits + 1): obj = data if i == 1 else ({} if isinstance(data, dict) else []) path = write_json(obj, i, total_width) print(f"Saved {path} ({'full object' if i==1 else 'empty'})") wrote_any = True else: path = write_json(data, 1, total_width) print(f"Saved {path} (full object)") wrote_any = True else: # empty dict print("Top-level JSON object is an empty object {}.") for i in range(1, num_splits + 1): if skip_empty: print(f"Skipping empty part {i}") continue path = write_json({}, i, total_width) print(f"Saved {path} (empty object)") wrote_any = True else: # scalar (string/number/bool/null) print("Top-level JSON is a scalar (not a list or dict).") if not skip_empty: for i in range(1, num_splits + 1): obj = data if i == 1 else None path = write_json(obj, i, total_width) print(f"Saved {path} ({'value' if i==1 else 'null'})") wrote_any = True else: path = write_json(data, 1, total_width) print(f"Saved {path} (scalar)") wrote_any = True if not wrote_any: print("No files were written (maybe all parts were empty and skip_empty=True).") else: print("Splitting complete!") if __name__ == "__main__": # If you prefer to skip writing empty parts, call with skip_empty=True split_json_file(skip_empty=False) |