Multi Language translation impl. Eine .json Datei enthält die ÜBersetztungen von allen Sprachen die übersetzt werden sollen. Dazu müssen diese Sektione allerdings auch befüllt sein
This commit is contained in:
+101
-7
@@ -29,8 +29,11 @@ class TestRunner:
|
||||
self.testdata_dir = Path(os.environ.get('PROJECT_TEST', self.project_root / "testdata"))
|
||||
self.work_dir = Path(os.environ.get('PROJECT_WORK', self.project_root / "work"))
|
||||
self.bin_dir = Path(os.environ.get('PROJECT_BIN', self.project_root / "bin"))
|
||||
self.lib_dir = Path(os.environ.get('PROJECT_LIB', self.project_root / "lib"))
|
||||
self.cfg_dir = Path(os.environ.get('PROJECT_CFG', self.project_root / "cfg"))
|
||||
self.getexdraw_bat = self.bin_dir / "getexdraw.bat"
|
||||
self.ioconverter_bat = self.bin_dir / "ioconverter.bat"
|
||||
self.translate_py = self.lib_dir / "translate.py"
|
||||
|
||||
self.test_results = []
|
||||
self.failed_tests = []
|
||||
@@ -128,6 +131,80 @@ class TestRunner:
|
||||
except Exception as e:
|
||||
return False, f"Exception during execution: {str(e)}"
|
||||
|
||||
def run_translate(self, test_filename):
|
||||
"""Execute translate.py for given test file with three variants: raw, cs, multilang"""
|
||||
dxf_file = self.testdata_dir / f"{test_filename}.dxf"
|
||||
if not dxf_file.exists():
|
||||
return False, f"Test file {dxf_file} not found"
|
||||
|
||||
try:
|
||||
# Set up environment for translate.py
|
||||
env = os.environ.copy()
|
||||
env['PROJECT_TRANSLATION'] = str(self.cfg_dir / "translation")
|
||||
|
||||
# Variant 1: Raw extraction (no translation)
|
||||
cmd_raw = [
|
||||
sys.executable,
|
||||
str(self.translate_py),
|
||||
'--extract',
|
||||
'--filename', str(dxf_file),
|
||||
'--export-type', 'json',
|
||||
'--outname', f'{test_filename}_raw'
|
||||
]
|
||||
result_raw = subprocess.run(cmd_raw, capture_output=True, text=True, env=env)
|
||||
|
||||
# Variant 2: CS translation (single language)
|
||||
cmd_cs = [
|
||||
sys.executable,
|
||||
str(self.translate_py),
|
||||
'--extract',
|
||||
'--filename', str(dxf_file),
|
||||
'--export-type', 'json',
|
||||
'--outname', f'{test_filename}_cs',
|
||||
'--translate', 'CS'
|
||||
]
|
||||
result_cs = subprocess.run(cmd_cs, capture_output=True, text=True, env=env)
|
||||
|
||||
# Variant 3: Multilang translation (CS,EN)
|
||||
cmd_multilang = [
|
||||
sys.executable,
|
||||
str(self.translate_py),
|
||||
'--extract',
|
||||
'--filename', str(dxf_file),
|
||||
'--export-type', 'json',
|
||||
'--outname', f'{test_filename}_multilang',
|
||||
'--translate', 'CS,EN'
|
||||
]
|
||||
result_multilang = subprocess.run(cmd_multilang, capture_output=True, text=True, env=env)
|
||||
|
||||
# Check if all expected output files were created
|
||||
expected_raw = self.work_dir / f"{test_filename}_raw.json"
|
||||
expected_cs = self.work_dir / f"{test_filename}_cs.json"
|
||||
expected_multilang = self.work_dir / f"{test_filename}_multilang.json"
|
||||
|
||||
missing_files = []
|
||||
if not expected_raw.exists():
|
||||
missing_files.append(f"{test_filename}_raw.json")
|
||||
if not expected_cs.exists():
|
||||
missing_files.append(f"{test_filename}_cs.json")
|
||||
if not expected_multilang.exists():
|
||||
missing_files.append(f"{test_filename}_multilang.json")
|
||||
|
||||
if missing_files:
|
||||
error_msg = f"translate.py failed - expected output files not found: {', '.join(missing_files)}"
|
||||
if result_raw.returncode != 0:
|
||||
error_msg += f"\n\nRaw variant STDOUT:\n{result_raw.stdout}\nSTDERR:\n{result_raw.stderr}"
|
||||
if result_cs.returncode != 0:
|
||||
error_msg += f"\n\nCS variant STDOUT:\n{result_cs.stdout}\nSTDERR:\n{result_cs.stderr}"
|
||||
if result_multilang.returncode != 0:
|
||||
error_msg += f"\n\nMultilang variant STDOUT:\n{result_multilang.stdout}\nSTDERR:\n{result_multilang.stderr}"
|
||||
return False, error_msg
|
||||
else:
|
||||
return True, "Success"
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Exception during execution: {str(e)}"
|
||||
|
||||
def cleanup_test_files(self, test_filename):
|
||||
"""Remove the work folder for the given test"""
|
||||
if not self.clean:
|
||||
@@ -149,7 +226,11 @@ class TestRunner:
|
||||
# Check what files actually exist and determine comparison strategy based on mode
|
||||
errors_file = self.work_dir / test_filename / f"{test_filename}_errors.json"
|
||||
|
||||
if self.mode == 'ioconverter':
|
||||
if self.mode == 'translation':
|
||||
# For translation mode: compare _raw, _cs, and _multilang variants
|
||||
file_suffixes = ['_raw', '_cs', '_multilang']
|
||||
# Translation files are directly in work_dir, not in subdirectory
|
||||
elif self.mode == 'ioconverter':
|
||||
# For ioconverter mode: check for _positionsconv.json
|
||||
positions_file = self.work_dir / test_filename / f"{test_filename}_positionsconv.json"
|
||||
|
||||
@@ -178,8 +259,12 @@ class TestRunner:
|
||||
return False, f"No generated files found for {test_filename}", []
|
||||
|
||||
for suffix in file_suffixes:
|
||||
# Generated file should be in work/<testfilename>/<testfilename><suffix>.json
|
||||
generated_file = self.work_dir / test_filename / f"{test_filename}{suffix}.json"
|
||||
# For translation mode, files are directly in work_dir
|
||||
if self.mode == 'translation':
|
||||
generated_file = self.work_dir / f"{test_filename}{suffix}.json"
|
||||
else:
|
||||
# For other modes, files are in work/<testfilename>/ subdirectory
|
||||
generated_file = self.work_dir / test_filename / f"{test_filename}{suffix}.json"
|
||||
|
||||
# Reference file should be in testdata/<testfilename><suffix>.json
|
||||
reference_file = self.testdata_dir / f"{test_filename}{suffix}.json"
|
||||
@@ -237,8 +322,10 @@ class TestRunner:
|
||||
|
||||
result = TestResult(test_filename)
|
||||
|
||||
# Step 1: Run the appropriate batch script based on mode
|
||||
if self.mode == 'ioconverter':
|
||||
# Step 1: Run the appropriate script based on mode
|
||||
if self.mode == 'translation':
|
||||
success, msg = self.run_translate(test_filename)
|
||||
elif self.mode == 'ioconverter':
|
||||
success, msg = self.run_ioconverter(test_filename)
|
||||
else:
|
||||
success, msg = self.run_getexdraw(test_filename)
|
||||
@@ -370,11 +457,18 @@ def main():
|
||||
action='store_true',
|
||||
help='Run ioconverter.bat tests'
|
||||
)
|
||||
mode_group.add_argument(
|
||||
'--translation',
|
||||
action='store_true',
|
||||
help='Run translate.py tests (extract text with raw, CS, and multilang variants)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Determine mode - default to getexdraw if neither is specified
|
||||
if args.ioconverter:
|
||||
# Determine mode - default to getexdraw if none is specified
|
||||
if args.translation:
|
||||
mode = 'translation'
|
||||
elif args.ioconverter:
|
||||
mode = 'ioconverter'
|
||||
else:
|
||||
mode = 'getexdraw'
|
||||
|
||||
+307
-101
@@ -525,16 +525,49 @@ def read_texts_from_file(filename: Path) -> list[str]:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def detect_json_structure(data: dict) -> tuple[str, list[str]]:
|
||||
"""
|
||||
Erkennt die Struktur einer JSON-Datei (alte oder hierarchische mehrsprachige Struktur).
|
||||
|
||||
Args:
|
||||
data: Geladene JSON-Daten als Dictionary
|
||||
|
||||
Returns:
|
||||
Tuple mit (Struktur-Typ, Liste der Sprachen)
|
||||
- Struktur-Typ: "legacy" (alte Struktur) oder "multilang" (mehrsprachige hierarchische Struktur)
|
||||
- Liste der Sprachen: leer bei legacy, z.B. ["EN", "FR", "CS"] bei multilang
|
||||
"""
|
||||
# Prüfe ob alte Struktur (hat 'untranslated' oder 'translations' Keys)
|
||||
if 'untranslated' in data or 'translations' in data:
|
||||
return "legacy", []
|
||||
|
||||
# Prüfe ob neue hierarchische Struktur (hat [LANG] Keys)
|
||||
languages = []
|
||||
for key in data.keys():
|
||||
if key.startswith('[') and key.endswith(']') and len(key) > 2:
|
||||
# Extrahiere Sprachcode aus [LANG]
|
||||
lang = key[1:-1]
|
||||
languages.append(lang)
|
||||
|
||||
if languages:
|
||||
return "multilang", languages
|
||||
|
||||
# Unbekannte Struktur
|
||||
return "unknown", []
|
||||
|
||||
|
||||
def read_texts_from_json(filename: Path) -> list[str]:
|
||||
"""
|
||||
Liest Texte aus dem 'untranslated' Block einer JSON-Datei.
|
||||
Erwartet eine Struktur mit "untranslated": [{"source": "...", "target": ""}, ...]
|
||||
Liest Texte aus einer JSON-Datei.
|
||||
Unterstützt beide Strukturen:
|
||||
- Alte Struktur: "untranslated": [{"source": "...", "target": ""}, ...]
|
||||
- Hierarchische Struktur: "[LANG]": {"untranslated": [...], ...}
|
||||
|
||||
Args:
|
||||
filename: Pfad zur JSON-Datei
|
||||
|
||||
Returns:
|
||||
Alphabetisch sortierte Liste aller "source" Texte aus dem untranslated Block
|
||||
Alphabetisch sortierte Liste aller "source" Texte aus den untranslated Blöcken
|
||||
"""
|
||||
try:
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
@@ -544,33 +577,77 @@ def read_texts_from_json(filename: Path) -> list[str]:
|
||||
print(f"FEHLER: JSON-Datei hat ungültige Struktur (erwartet Object, bekam {type(data).__name__})")
|
||||
sys.exit(1)
|
||||
|
||||
if 'untranslated' not in data:
|
||||
print(f"FEHLER: JSON-Datei enthält keinen 'untranslated' Block")
|
||||
# Erkenne Struktur
|
||||
structure_type, languages = detect_json_structure(data)
|
||||
|
||||
texts_set = set() # Verwende Set um Duplikate zu vermeiden
|
||||
|
||||
if structure_type == "legacy":
|
||||
# Alte Struktur
|
||||
if 'untranslated' not in data:
|
||||
print(f"FEHLER: JSON-Datei enthält keinen 'untranslated' Block")
|
||||
sys.exit(1)
|
||||
|
||||
untranslated = data['untranslated']
|
||||
if not isinstance(untranslated, list):
|
||||
print(f"FEHLER: 'untranslated' Block hat ungültige Struktur (erwartet Array)")
|
||||
sys.exit(1)
|
||||
|
||||
for idx, entry in enumerate(untranslated):
|
||||
if not isinstance(entry, dict):
|
||||
print(f"WARNUNG: Eintrag {idx} in 'untranslated' ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
if 'source' not in entry:
|
||||
print(f"WARNUNG: Eintrag {idx} in 'untranslated' hat kein 'source' Feld, überspringe")
|
||||
continue
|
||||
|
||||
source_text = entry['source']
|
||||
if source_text: # Ignoriere leere Texte
|
||||
texts_set.add(source_text)
|
||||
|
||||
print(f"Texte aus JSON-Datei gelesen (alte Struktur): {len(texts_set)}")
|
||||
|
||||
elif structure_type == "multilang":
|
||||
# Hierarchische mehrsprachige Struktur
|
||||
print(f"Erkannte mehrsprachige Struktur mit Sprachen: {', '.join(languages)}")
|
||||
|
||||
for lang in languages:
|
||||
lang_key = f"[{lang}]"
|
||||
if lang_key not in data:
|
||||
continue
|
||||
|
||||
lang_data = data[lang_key]
|
||||
if not isinstance(lang_data, dict):
|
||||
print(f"WARNUNG: [{lang}] Block ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
# Lese aus untranslated Block
|
||||
if 'untranslated' in lang_data:
|
||||
untranslated = lang_data['untranslated']
|
||||
if not isinstance(untranslated, list):
|
||||
print(f"WARNUNG: [{lang}][untranslated] ist kein Array, überspringe")
|
||||
continue
|
||||
|
||||
for idx, entry in enumerate(untranslated):
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
|
||||
if 'source' not in entry:
|
||||
continue
|
||||
|
||||
source_text = entry['source']
|
||||
if source_text:
|
||||
texts_set.add(source_text)
|
||||
|
||||
print(f"Texte aus JSON-Datei gelesen (mehrsprachige Struktur): {len(texts_set)}")
|
||||
|
||||
else:
|
||||
print(f"FEHLER: JSON-Datei hat unbekannte Struktur")
|
||||
sys.exit(1)
|
||||
|
||||
untranslated = data['untranslated']
|
||||
if not isinstance(untranslated, list):
|
||||
print(f"FEHLER: 'untranslated' Block hat ungültige Struktur (erwartet Array)")
|
||||
sys.exit(1)
|
||||
|
||||
texts = []
|
||||
for idx, entry in enumerate(untranslated):
|
||||
if not isinstance(entry, dict):
|
||||
print(f"WARNUNG: Eintrag {idx} in 'untranslated' ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
if 'source' not in entry:
|
||||
print(f"WARNUNG: Eintrag {idx} in 'untranslated' hat kein 'source' Feld, überspringe")
|
||||
continue
|
||||
|
||||
source_text = entry['source']
|
||||
if source_text: # Ignoriere leere Texte
|
||||
texts.append(source_text)
|
||||
|
||||
# Sortiere alphabetisch
|
||||
texts.sort()
|
||||
|
||||
print(f"Texte aus JSON-Datei gelesen: {len(texts)}")
|
||||
# Konvertiere Set zu sortierter Liste
|
||||
texts = sorted(texts_set)
|
||||
return texts
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
@@ -581,13 +658,19 @@ def read_texts_from_json(filename: Path) -> list[str]:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def load_translations_from_json(filename: Path) -> dict[str, str]:
|
||||
def load_translations_from_json(filename: Path, target_lang: str = None) -> dict[str, str]:
|
||||
"""
|
||||
Liest Übersetzungen aus dem 'translations' Block einer JSON-Datei.
|
||||
Erwartet eine Struktur mit "translations": [{"source": "...", "target": "..."}, ...]
|
||||
Liest Übersetzungen aus einer JSON-Datei.
|
||||
Unterstützt beide Strukturen:
|
||||
- Alte Struktur: "translations": [{"source": "...", "target": "..."}, ...]
|
||||
- Hierarchische Struktur: "[LANG]": {"translated": [...], ...}
|
||||
|
||||
Bei hierarchischer Struktur werden Übersetzungen aus allen Sprachen oder nur der angegebenen Sprache gelesen.
|
||||
Wenn mehrere Übersetzungen für denselben source existieren, wird die letzte verwendet (Sprache mit höherer Priorität).
|
||||
|
||||
Args:
|
||||
filename: Pfad zur JSON-Datei
|
||||
target_lang: Optional: Bei hierarchischer Struktur nur Übersetzungen dieser Sprache laden
|
||||
|
||||
Returns:
|
||||
Dictionary mit source -> target Mappings
|
||||
@@ -600,31 +683,83 @@ def load_translations_from_json(filename: Path) -> dict[str, str]:
|
||||
print(f"FEHLER: JSON-Datei hat ungültige Struktur (erwartet Object, bekam {type(data).__name__})")
|
||||
sys.exit(1)
|
||||
|
||||
if 'translations' not in data:
|
||||
print(f"FEHLER: JSON-Datei enthält keinen 'translations' Block")
|
||||
sys.exit(1)
|
||||
|
||||
translations_list = data['translations']
|
||||
if not isinstance(translations_list, list):
|
||||
print(f"FEHLER: 'translations' Block hat ungültige Struktur (erwartet Array)")
|
||||
sys.exit(1)
|
||||
# Erkenne Struktur
|
||||
structure_type, languages = detect_json_structure(data)
|
||||
|
||||
translations = {}
|
||||
for idx, entry in enumerate(translations_list):
|
||||
if not isinstance(entry, dict):
|
||||
print(f"WARNUNG: Eintrag {idx} in 'translations' ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
if 'source' not in entry or 'target' not in entry:
|
||||
print(f"WARNUNG: Eintrag {idx} in 'translations' fehlt 'source' oder 'target', überspringe")
|
||||
continue
|
||||
if structure_type == "legacy":
|
||||
# Alte Struktur
|
||||
if 'translations' not in data:
|
||||
print(f"FEHLER: JSON-Datei enthält keinen 'translations' Block")
|
||||
sys.exit(1)
|
||||
|
||||
source = entry['source']
|
||||
target = entry['target']
|
||||
if source and target: # Ignoriere leere Einträge
|
||||
translations[source] = target
|
||||
translations_list = data['translations']
|
||||
if not isinstance(translations_list, list):
|
||||
print(f"FEHLER: 'translations' Block hat ungültige Struktur (erwartet Array)")
|
||||
sys.exit(1)
|
||||
|
||||
for idx, entry in enumerate(translations_list):
|
||||
if not isinstance(entry, dict):
|
||||
print(f"WARNUNG: Eintrag {idx} in 'translations' ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
if 'source' not in entry or 'target' not in entry:
|
||||
print(f"WARNUNG: Eintrag {idx} in 'translations' fehlt 'source' oder 'target', überspringe")
|
||||
continue
|
||||
|
||||
source = entry['source']
|
||||
target = entry['target']
|
||||
if source and target: # Ignoriere leere Einträge
|
||||
translations[source] = target
|
||||
|
||||
print(f"Übersetzungen aus JSON-Datei geladen (alte Struktur): {len(translations)}")
|
||||
|
||||
elif structure_type == "multilang":
|
||||
# Hierarchische mehrsprachige Struktur
|
||||
print(f"Erkannte mehrsprachige Struktur mit Sprachen: {', '.join(languages)}")
|
||||
|
||||
# Filtere Sprachen falls target_lang angegeben
|
||||
langs_to_load = [target_lang] if target_lang and target_lang in languages else languages
|
||||
|
||||
for lang in langs_to_load:
|
||||
lang_key = f"[{lang}]"
|
||||
if lang_key not in data:
|
||||
continue
|
||||
|
||||
lang_data = data[lang_key]
|
||||
if not isinstance(lang_data, dict):
|
||||
print(f"WARNUNG: [{lang}] Block ist kein Object, überspringe")
|
||||
continue
|
||||
|
||||
# Lese aus translated Block
|
||||
if 'translated' in lang_data:
|
||||
translated = lang_data['translated']
|
||||
if not isinstance(translated, list):
|
||||
print(f"WARNUNG: [{lang}][translated] ist kein Array, überspringe")
|
||||
continue
|
||||
|
||||
for idx, entry in enumerate(translated):
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
|
||||
if 'source' not in entry or 'target' not in entry:
|
||||
continue
|
||||
|
||||
source = entry['source']
|
||||
target = entry['target']
|
||||
if source and target:
|
||||
translations[source] = target
|
||||
|
||||
if target_lang:
|
||||
print(f"Übersetzungen für Sprache [{target_lang}] aus JSON-Datei geladen: {len(translations)}")
|
||||
else:
|
||||
print(f"Übersetzungen aus JSON-Datei geladen (mehrsprachige Struktur, alle Sprachen): {len(translations)}")
|
||||
|
||||
else:
|
||||
print(f"FEHLER: JSON-Datei hat unbekannte Struktur")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Übersetzungen aus JSON-Datei geladen: {len(translations)}")
|
||||
return translations
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
@@ -959,63 +1094,117 @@ def write_texts_to_excel(texts: list[str], output_path: Path,
|
||||
|
||||
|
||||
def write_texts_to_json(texts: list[str], ignored_texts: list[str], output_path: Path,
|
||||
translation_dicts: tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]] = None):
|
||||
translation_dicts: tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]] = None,
|
||||
translation_dicts_all: dict[str, tuple] = None,
|
||||
translation_languages: list[str] = None):
|
||||
"""
|
||||
Schreibt die Texte in eine JSON-Datei mit drei Blöcken.
|
||||
Schreibt die Texte in eine JSON-Datei.
|
||||
|
||||
Die JSON-Struktur enthält:
|
||||
Bei einer Sprache (alte Struktur):
|
||||
- "translations": Liste von {source, target} für übersetzte Texte
|
||||
- "untranslated": Liste von {source, target: ""} für nicht übersetzte Texte
|
||||
- "ignored": Liste von Strings für gefilterte/ignorierte Texte
|
||||
|
||||
Bei mehreren Sprachen (hierarchische Struktur):
|
||||
- "[EN]": {"translated": [...], "untranslated": [...]}
|
||||
- "[FR]": {"translated": [...], "untranslated": [...]}
|
||||
- "ignored": Liste von Strings für gefilterte/ignorierte Texte
|
||||
|
||||
Args:
|
||||
texts: Liste der akzeptierten Texte
|
||||
ignored_texts: Liste der ignorierten Texte
|
||||
output_path: Pfad zur Ausgabe-JSON-Datei
|
||||
translation_dicts: Optional: Tuple mit (Multi, Trigramme, Bigramme, Single) für Übersetzungen
|
||||
translation_dicts: Optional: Tuple mit (Multi, Trigramme, Bigramme, Single) für eine Sprache (backwards compatibility)
|
||||
translation_dicts_all: Optional: Dict mit {LANG: (multi, trigramme, bigramme, single)} für mehrere Sprachen
|
||||
translation_languages: Optional: Liste der Sprachen in der Reihenfolge der Verarbeitung
|
||||
"""
|
||||
output_data = {}
|
||||
|
||||
# Block 1: Übersetzte Texte (als Liste von Dicts mit source/target)
|
||||
# Block 2: Nicht übersetzte Texte (als Liste von Dicts mit source und leerem target)
|
||||
if translation_dicts:
|
||||
multi, trigramme, bigramme, single = translation_dicts
|
||||
translations = []
|
||||
untranslated = []
|
||||
# Mehrsprachige hierarchische Struktur
|
||||
if translation_dicts_all and translation_languages and len(translation_languages) > 1:
|
||||
for lang in translation_languages:
|
||||
if lang not in translation_dicts_all:
|
||||
continue
|
||||
|
||||
for text in texts:
|
||||
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||
if translated: # Übersetzung vorhanden
|
||||
translations.append({
|
||||
"source": text,
|
||||
"target": translated
|
||||
})
|
||||
else: # Keine Übersetzung vorhanden
|
||||
untranslated.append({
|
||||
"source": text,
|
||||
"target": ""
|
||||
})
|
||||
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
||||
translations = []
|
||||
untranslated = []
|
||||
|
||||
output_data["translations"] = translations
|
||||
output_data["untranslated"] = untranslated
|
||||
for text in texts:
|
||||
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||
if translated: # Übersetzung vorhanden
|
||||
translations.append({
|
||||
"source": text,
|
||||
"target": translated
|
||||
})
|
||||
else: # Keine Übersetzung vorhanden
|
||||
untranslated.append({
|
||||
"source": text,
|
||||
"target": ""
|
||||
})
|
||||
|
||||
# Hierarchische Struktur: [LANG] als Schlüssel
|
||||
output_data[f"[{lang}]"] = {
|
||||
"translated": translations,
|
||||
"untranslated": untranslated
|
||||
}
|
||||
|
||||
# Ignorierte Texte am Ende (ohne Sprachzuordnung)
|
||||
output_data["ignored"] = ignored_texts
|
||||
|
||||
# Alte Struktur (eine Sprache oder keine Übersetzung)
|
||||
else:
|
||||
# Ohne Übersetzungs-Config: alle akzeptierten Texte sind nicht übersetzt
|
||||
output_data["translations"] = []
|
||||
output_data["untranslated"] = [{"source": text, "target": ""} for text in texts]
|
||||
# Block 1: Übersetzte Texte (als Liste von Dicts mit source/target)
|
||||
# Block 2: Nicht übersetzte Texte (als Liste von Dicts mit source und leerem target)
|
||||
if translation_dicts:
|
||||
multi, trigramme, bigramme, single = translation_dicts
|
||||
translations = []
|
||||
untranslated = []
|
||||
|
||||
# Block 3: Ignorierte Texte (als Liste)
|
||||
output_data["ignored"] = ignored_texts
|
||||
for text in texts:
|
||||
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||
if translated: # Übersetzung vorhanden
|
||||
translations.append({
|
||||
"source": text,
|
||||
"target": translated
|
||||
})
|
||||
else: # Keine Übersetzung vorhanden
|
||||
untranslated.append({
|
||||
"source": text,
|
||||
"target": ""
|
||||
})
|
||||
|
||||
output_data["translations"] = translations
|
||||
output_data["untranslated"] = untranslated
|
||||
else:
|
||||
# Ohne Übersetzungs-Config: alle akzeptierten Texte sind nicht übersetzt
|
||||
output_data["translations"] = []
|
||||
output_data["untranslated"] = [{"source": text, "target": ""} for text in texts]
|
||||
|
||||
# Block 3: Ignorierte Texte (als Liste)
|
||||
output_data["ignored"] = ignored_texts
|
||||
|
||||
try:
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"JSON-Datei erfolgreich erstellt: {output_path}")
|
||||
if translation_dicts:
|
||||
print(f" Übersetzungen: {len(output_data['translations'])}")
|
||||
print(f" Nicht übersetzte Texte: {len(output_data['untranslated'])}")
|
||||
|
||||
# Ausgabe-Statistiken
|
||||
if translation_dicts_all and translation_languages and len(translation_languages) > 1:
|
||||
# Mehrsprachige Struktur
|
||||
for lang in translation_languages:
|
||||
if f"[{lang}]" in output_data:
|
||||
lang_data = output_data[f"[{lang}]"]
|
||||
print(f" [{lang}] Übersetzungen: {len(lang_data['translated'])}, Nicht übersetzt: {len(lang_data['untranslated'])}")
|
||||
else:
|
||||
print(f" Nicht übersetzte Texte: {len(output_data['untranslated'])}")
|
||||
# Alte Struktur
|
||||
if translation_dicts:
|
||||
print(f" Übersetzungen: {len(output_data['translations'])}")
|
||||
print(f" Nicht übersetzte Texte: {len(output_data['untranslated'])}")
|
||||
else:
|
||||
print(f" Nicht übersetzte Texte: {len(output_data['untranslated'])}")
|
||||
|
||||
print(f" Ignorierte Texte: {len(ignored_texts)}")
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Schreiben der JSON-Datei: {e}")
|
||||
@@ -1160,7 +1349,7 @@ if __name__ == '__main__':
|
||||
'--translate',
|
||||
action='store',
|
||||
metavar='LANG',
|
||||
help='Übersetzt Texte mit Config aus translation/<LANG>.cfg (z.B. CS, EN, FR)'
|
||||
help='Übersetzt Texte mit Config aus translation/<LANG>.cfg (z.B. CS, EN, FR). Mehrere Sprachen kommasepariert möglich (z.B. EN,FR,CS)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--lang_source',
|
||||
@@ -1222,25 +1411,41 @@ if __name__ == '__main__':
|
||||
symbol_attr_mapping = load_symbol_attribute_mapping(cfg_dir)
|
||||
symbol_layer_mapping = load_symbol_layer_mapping(cfg_dir)
|
||||
|
||||
# Bestimme Quell- und Ziel-Attributnamen basierend auf Sprachcodes
|
||||
source_attr_name = symbol_attr_mapping.get(args.lang_source, 'TEXT-D')
|
||||
target_attr_name = symbol_attr_mapping.get(args.translate, 'TEXT-CS') if args.translate else 'TEXT-CS'
|
||||
# Parse Sprachen aus --translate Parameter (kommaseparierte Liste)
|
||||
translation_languages = []
|
||||
if args.translate:
|
||||
translation_languages = [lang.strip().upper() for lang in args.translate.split(',')]
|
||||
# Entferne Duplikate und behalte Reihenfolge
|
||||
seen = set()
|
||||
translation_languages = [lang for lang in translation_languages if lang and not (lang in seen or seen.add(lang))]
|
||||
|
||||
# Bestimme Ziel-Layer für Blockattribute (nur relevant bei --todxf)
|
||||
target_layer_name = symbol_layer_mapping.get(args.translate) if args.translate else None
|
||||
# Bestimme Quell-Attributnamen basierend auf Sprachcode
|
||||
source_attr_name = symbol_attr_mapping.get(args.lang_source, 'TEXT-D')
|
||||
|
||||
# Für --todxf: verwende nur die erste Sprache als Ziel (backwards compatibility)
|
||||
target_attr_name = symbol_attr_mapping.get(translation_languages[0], 'TEXT-CS') if translation_languages else 'TEXT-CS'
|
||||
target_layer_name = symbol_layer_mapping.get(translation_languages[0]) if translation_languages else None
|
||||
|
||||
print(f"\nVerwendete Attribut-Namen:")
|
||||
print(f" Quell-Attribut (--lang_source {args.lang_source}): {source_attr_name}")
|
||||
if args.translate:
|
||||
print(f" Ziel-Attribut (--translate {args.translate}): {target_attr_name}")
|
||||
if target_layer_name:
|
||||
print(f" Ziel-Layer (--translate {args.translate}): {target_layer_name}")
|
||||
if translation_languages:
|
||||
if len(translation_languages) == 1:
|
||||
print(f" Ziel-Attribut (--translate {translation_languages[0]}): {target_attr_name}")
|
||||
if target_layer_name:
|
||||
print(f" Ziel-Layer (--translate {translation_languages[0]}): {target_layer_name}")
|
||||
else:
|
||||
print(f" Ziel-Sprachen (--translate): {', '.join(translation_languages)}")
|
||||
|
||||
# Optional: Lade Übersetzungs-Config
|
||||
translation_dicts = None
|
||||
if args.translate:
|
||||
# Optional: Lade Übersetzungs-Configs für alle Sprachen
|
||||
# translation_dicts_all ist ein Dict: {LANG: (multi, trigramme, bigramme, single), ...}
|
||||
translation_dicts_all = {}
|
||||
if translation_languages:
|
||||
translation_dir = check_environment_var('PROJECT_TRANSLATION')
|
||||
translation_dicts = load_translation_config(args.translate, translation_dir)
|
||||
for lang in translation_languages:
|
||||
translation_dicts_all[lang] = load_translation_config(lang, translation_dir)
|
||||
|
||||
# Für backwards compatibility: wenn nur eine Sprache, setze translation_dicts wie früher
|
||||
translation_dicts = translation_dicts_all.get(translation_languages[0]) if len(translation_languages) == 1 else None
|
||||
|
||||
if args.debug:
|
||||
print("DEBUG-Modus aktiviert")
|
||||
@@ -1286,8 +1491,9 @@ if __name__ == '__main__':
|
||||
|
||||
print(f"Übersetzungs-JSON: {translation_json}")
|
||||
|
||||
# Lade Übersetzungen
|
||||
translations = load_translations_from_json(translation_json)
|
||||
# Lade Übersetzungen (verwende erste Sprache als Ziel-Sprache)
|
||||
target_lang = translation_languages[0] if translation_languages else None
|
||||
translations = load_translations_from_json(translation_json, target_lang)
|
||||
|
||||
# Bestimme Ausgabe-DXF
|
||||
output_dxf_name = args.todxf
|
||||
@@ -1415,7 +1621,7 @@ if __name__ == '__main__':
|
||||
if export_type == 'excel':
|
||||
write_texts_to_excel(texts, output_path, translation_dicts)
|
||||
elif export_type == 'json':
|
||||
write_texts_to_json(texts, ignored_texts, output_path, translation_dicts)
|
||||
write_texts_to_json(texts, ignored_texts, output_path, translation_dicts, translation_dicts_all, translation_languages)
|
||||
else: # text
|
||||
write_texts_to_text(texts, ignored_texts, output_path, translation_dicts)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user