log dir dazu gemacht. Ausgabe der Übersetzuung als json möglich

This commit is contained in:
2025-12-03 20:10:06 +01:00
parent a967e2e35e
commit 12cb8fd99c
2 changed files with 199 additions and 37 deletions
+2
View File
@@ -10,6 +10,7 @@ set PROJECT_LIB=%PROJECT%\lib
set PROJECT_DATA=%PROJECT%\data set PROJECT_DATA=%PROJECT%\data
set PROJECT_WORK=%PROJECT%\work set PROJECT_WORK=%PROJECT%\work
set PROJECT_TEST=%PROJECT%\testdata set PROJECT_TEST=%PROJECT%\testdata
set PROJECT_LOG=%PROJECT%\logs
set PROJECT_TRANSLATION=%PROJECT%\translation set PROJECT_TRANSLATION=%PROJECT%\translation
set SIVAS_TEILESTAMM=\\195.243.223.3\sivas\jit\programme\KSbExcelExportSivasTeilestamm.exe set SIVAS_TEILESTAMM=\\195.243.223.3\sivas\jit\programme\KSbExcelExportSivasTeilestamm.exe
@@ -18,6 +19,7 @@ set SIVAS_EXCEL_EXPORT_DIR=%PROJECT_DATA%
if not exist %PROJECT%\work mkdir %PROJECT%\work if not exist %PROJECT%\work mkdir %PROJECT%\work
if not exist %PROJECT%\data mkdir %PROJECT%\data if not exist %PROJECT%\data mkdir %PROJECT%\data
if not exist %PROJECT%\translation mkdir %PROJECT%\translation if not exist %PROJECT%\translation mkdir %PROJECT%\translation
if not exist %PROJECT%\logs mkdir %PROJECT%\logs
set PROJECT_IO_RESULTS=Z:\Automatisierung\Konvertierungstools\4_io-Konvertierer set PROJECT_IO_RESULTS=Z:\Automatisierung\Konvertierungstools\4_io-Konvertierer
set PROJECT_BOM_RESULTS=Z:\Automatisierung\Konvertierungstools\3_Kabellaengen-Konvertierer set PROJECT_BOM_RESULTS=Z:\Automatisierung\Konvertierungstools\3_Kabellaengen-Konvertierer
+197 -37
View File
@@ -1,4 +1,5 @@
import argparse import argparse
import json
import os import os
import re import re
import sys import sys
@@ -15,7 +16,8 @@ Dieses Programm:
- liest eine DXF Datei und sammelt alle TEXT und MTEXT Objekte - liest eine DXF Datei und sammelt alle TEXT und MTEXT Objekte
ODER liest Texte aus einer TXT Datei (ein Text pro Zeile) ODER liest Texte aus einer TXT Datei (ein Text pro Zeile)
- filtert die Texte basierend auf Mustern in translator.cfg - filtert die Texte basierend auf Mustern in translator.cfg
- schreibt die Ergebnisse in eine Excel- oder Textdatei - übersetzt optional Texte mit Trigrammen, Bigrammen und Einzelwörtern aus translation/<LANG>.cfg
- schreibt die Ergebnisse in eine Excel- oder JSON-Datei
- speichert die Ausgabedatei im PROJECT_WORK Verzeichnis - speichert die Ausgabedatei im PROJECT_WORK Verzeichnis
""" """
@@ -30,6 +32,69 @@ def check_environment_var(env_str: str) -> Path:
sys.exit(1) sys.exit(1)
def load_translation_config(translation_lang: str, translation_dir: Path) -> tuple[dict[str, str], dict[str, str], dict[str, str]]:
"""
Lädt eine Übersetzungs-Config-Datei (z.B. CSK.cfg, EN.cfg, FR.cfg).
Args:
translation_lang: Sprach-Code (z.B. "CSK", "EN", "FR")
translation_dir: Verzeichnis mit Übersetzungs-Configs (aus PROJECT_TRANSLATION)
Returns:
Tuple mit (Trigramme-Dict, Bigramme-Dict, Single-Dict)
"""
config_file = translation_dir / f"{translation_lang}.cfg"
if not config_file.exists():
print(f"FEHLER: Übersetzungs-Konfiguration nicht gefunden: {config_file}")
sys.exit(1)
# RawConfigParser mit case-sensitive Keys
config = RawConfigParser()
# Überschreibe optionxform um Groß-/Kleinschreibung zu erhalten
config.optionxform = str
try:
config.read(config_file, encoding='utf-8')
except Exception as e:
print(f"Fehler beim Lesen der Übersetzungs-Konfiguration: {e}")
sys.exit(1)
trigramme = {}
bigramme = {}
single = {}
# Lade Trigramme
if config.has_section('trigramme'):
for key in config['trigramme']:
original = key
translation = config['trigramme'][key]
if translation and not translation.startswith('#'):
trigramme[original] = translation
# Lade Bigramme
if config.has_section('bigramme'):
for key in config['bigramme']:
original = key
translation = config['bigramme'][key]
if translation and not translation.startswith('#'):
bigramme[original] = translation
# Lade Single
if config.has_section('single'):
for key in config['single']:
original = key
translation = config['single'][key]
if translation and not translation.startswith('#'):
single[original] = translation
print(f"\nÜbersetzungs-Config geladen ({translation_lang}):")
print(f" Trigramme: {len(trigramme)}")
print(f" Bigramme: {len(bigramme)}")
print(f" Einzelwörter: {len(single)}")
return trigramme, bigramme, single
def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]: def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
""" """
Liest die ignore_pattern aus der translator.cfg Datei. Liest die ignore_pattern aus der translator.cfg Datei.
@@ -50,6 +115,8 @@ def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
# RawConfigParser verhindert dass Backslashes in Regex-Mustern escaped werden # RawConfigParser verhindert dass Backslashes in Regex-Mustern escaped werden
config = RawConfigParser() config = RawConfigParser()
# Überschreibe optionxform um Groß-/Kleinschreibung zu erhalten
config.optionxform = str
try: try:
config.read(config_file, encoding='utf-8') config.read(config_file, encoding='utf-8')
except Exception as e: except Exception as e:
@@ -84,6 +151,50 @@ def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
return wildcard_patterns, regex_patterns return wildcard_patterns, regex_patterns
def translate_text(text: str, trigramme: dict[str, str], bigramme: dict[str, str], single: dict[str, str]) -> str:
"""
Übersetzt einen Text durch Ersetzen von Trigrammen, Bigrammen und Einzelwörtern.
Ersetzungen erfolgen in dieser Reihenfolge: Trigramme → Bigramme → Einzelwörter.
Args:
text: Zu übersetzender Text
trigramme: Dictionary mit Drei-Wort-Phrasen
bigramme: Dictionary mit Zwei-Wort-Phrasen
single: Dictionary mit Einzelwörtern
Returns:
Übersetzter Text (leer wenn keine Übersetzung gefunden wurde)
"""
translated_text = text
has_translation = False
# 1. Trigramme ersetzen (längste Phrasen zuerst)
for original, translation in trigramme.items():
if original in translated_text:
translated_text = translated_text.replace(original, translation)
has_translation = True
# 2. Bigramme ersetzen
for original, translation in bigramme.items():
if original in translated_text:
translated_text = translated_text.replace(original, translation)
has_translation = True
# 3. Einzelwörter ersetzen
words = translated_text.split()
translated_words = []
for word in words:
if word in single:
translated_words.append(single[word])
has_translation = True
else:
translated_words.append(word)
translated_text = ' '.join(translated_words)
# Gib nur übersetzten Text zurück wenn tatsächlich etwas übersetzt wurde
return translated_text if has_translation else ""
def should_ignore_text(text: str, wildcard_patterns: list[str], regex_patterns: list[str], debug: bool = False) -> bool: def should_ignore_text(text: str, wildcard_patterns: list[str], regex_patterns: list[str], debug: bool = False) -> bool:
""" """
Prüft ob ein Text ignoriert werden soll basierend auf den Mustern. Prüft ob ein Text ignoriert werden soll basierend auf den Mustern.
@@ -245,13 +356,16 @@ def read_texts_from_file(filename: Path) -> list[str]:
sys.exit(1) sys.exit(1)
def write_texts_to_excel(texts: list[str], output_path: Path): def write_texts_to_excel(texts: list[str], output_path: Path,
translation_dicts: tuple[dict[str, str], dict[str, str], dict[str, str]] = None):
""" """
Schreibt die Texte in die erste Spalte einer Excel-Datei. Schreibt die Texte in die erste Spalte einer Excel-Datei.
Optional: Schreibt Übersetzungen in die zweite Spalte.
Args: Args:
texts: Liste der zu schreibenden Texte texts: Liste der zu schreibenden Texte
output_path: Pfad zur Ausgabe-Excel-Datei output_path: Pfad zur Ausgabe-Excel-Datei
translation_dicts: Optional: Tuple mit (Trigramme, Bigramme, Single) für Übersetzungen
""" """
wb = Workbook() wb = Workbook()
ws = wb.active ws = wb.active
@@ -259,61 +373,95 @@ def write_texts_to_excel(texts: list[str], output_path: Path):
# Kopfzeile # Kopfzeile
ws['A1'] = "Text" ws['A1'] = "Text"
if translation_dicts:
ws['B1'] = "Übersetzung"
# Texte in die erste Spalte schreiben # Texte schreiben
for idx, text in enumerate(texts, start=2): for idx, text in enumerate(texts, start=2):
ws[f'A{idx}'] = text ws[f'A{idx}'] = text
# Spaltenbreite anpassen # Optional: Übersetzung in zweite Spalte
if translation_dicts:
trigramme, bigramme, single = translation_dicts
translated = translate_text(text, trigramme, bigramme, single)
if translated: # Nur wenn Übersetzung gefunden wurde
ws[f'B{idx}'] = translated
# Sonst bleibt die Zelle leer
# Spaltenbreiten anpassen
ws.column_dimensions['A'].width = 50 ws.column_dimensions['A'].width = 50
if translation_dicts:
ws.column_dimensions['B'].width = 50
try: try:
wb.save(output_path) wb.save(output_path)
print(f"Excel-Datei erfolgreich erstellt: {output_path}") print(f"Excel-Datei erfolgreich erstellt: {output_path}")
if translation_dicts:
print(f" Mit Übersetzungen in Spalte B")
except Exception as e: except Exception as e:
print(f"Fehler beim Schreiben der Excel-Datei: {e}") print(f"Fehler beim Schreiben der Excel-Datei: {e}")
sys.exit(1) sys.exit(1)
def write_texts_to_textfile(texts: list[str], ignored_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]] = None):
""" """
Schreibt die Texte in eine UTF-8 Textdatei. Schreibt die Texte in eine JSON-Datei mit drei Blöcken.
Jeder Text wird in einer eigenen Zeile geschrieben (auch Multiline-Texte).
Die Datei enthält zwei Teile: akzeptierte und ignorierte Texte.
Args: Args:
texts: Liste der akzeptierten Texte texts: Liste der akzeptierten Texte
ignored_texts: Liste der ignorierten Texte ignored_texts: Liste der ignorierten Texte
output_path: Pfad zur Ausgabe-Textdatei output_path: Pfad zur Ausgabe-JSON-Datei
translation_dicts: Optional: Tuple mit (Trigramme, Bigramme, Single) für Übersetzungen
""" """
output_data = {}
# Block 1: Übersetzte Texte (als Liste von Dicts mit source/target)
# Block 2: Nicht übersetzte Texte (nur akzeptierte Texte ohne Übersetzung)
if translation_dicts:
trigramme, bigramme, single = translation_dicts
translations = []
untranslated_texts = []
for text in texts:
translated = translate_text(text, trigramme, bigramme, single)
if translated: # Übersetzung vorhanden
translations.append({
"source": text,
"target": translated
})
else: # Keine Übersetzung vorhanden
untranslated_texts.append(text)
output_data["translations"] = translations
output_data["texts"] = untranslated_texts
else:
# Ohne Übersetzungs-Config: alle akzeptierten Texte sind nicht übersetzt
output_data["translations"] = []
output_data["texts"] = texts
# Block 3: Ignorierte Texte (als Liste)
output_data["ignored"] = ignored_texts
try: try:
with open(output_path, 'w', encoding='utf-8') as f: with open(output_path, 'w', encoding='utf-8') as f:
# Schreibe akzeptierte Texte json.dump(output_data, f, ensure_ascii=False, indent=2)
for text in texts:
# Multiline-Texte werden in einer Zeile geschrieben (Zeilenumbrüche ersetzen)
text_single_line = text.replace('\n', '\\n').replace('\r', '\\r')
f.write(text_single_line + '\n')
# Trennzeile print(f"JSON-Datei erfolgreich erstellt: {output_path}")
f.write('\n-- durch translator.cfg ausgeschlossen --\n\n') if translation_dicts:
print(f" Übersetzungen: {len(output_data['translations'])}")
# Schreibe ignorierte Texte print(f" Nicht übersetzte Texte: {len(output_data['texts'])}")
for text in ignored_texts: else:
# Multiline-Texte werden in einer Zeile geschrieben (Zeilenumbrüche ersetzen) print(f" Akzeptierte Texte: {len(output_data['texts'])}")
text_single_line = text.replace('\n', '\\n').replace('\r', '\\r')
f.write(text_single_line + '\n')
print(f"Textdatei erfolgreich erstellt: {output_path}")
print(f" Akzeptierte Texte: {len(texts)}")
print(f" Ignorierte Texte: {len(ignored_texts)}") print(f" Ignorierte Texte: {len(ignored_texts)}")
except Exception as e: except Exception as e:
print(f"Fehler beim Schreiben der Textdatei: {e}") print(f"Fehler beim Schreiben der JSON-Datei: {e}")
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Extrahiert TEXT und MTEXT Objekte aus einer DXF Datei oder filtert Texte aus einer TXT Datei', description='Extrahiert TEXT und MTEXT Objekte aus einer DXF Datei oder filtert Texte aus einer TXT Datei. Optional mit Übersetzungsfunktion.',
prog='translate' prog='translate'
) )
@@ -352,8 +500,14 @@ if __name__ == '__main__':
'-t', '--export-type', '-t', '--export-type',
action='store', action='store',
default='excel', default='excel',
choices=['excel', 'text'], choices=['excel', 'json'],
help='Exportformat: excel (Standard) oder text (UTF-8 Textdatei)' help='Exportformat: excel (Standard) oder json (JSON-Datei)'
)
parser.add_argument(
'--translate',
action='store',
metavar='LANG',
help='Übersetzt Texte mit Config aus translation/<LANG>.cfg (z.B. CSK, EN, FR)'
) )
args = parser.parse_args() args = parser.parse_args()
@@ -373,6 +527,12 @@ if __name__ == '__main__':
# Lade Ignore-Muster aus Konfigurationsdatei # Lade Ignore-Muster aus Konfigurationsdatei
wildcard_patterns, regex_patterns = load_ignore_patterns(cfg_dir) wildcard_patterns, regex_patterns = load_ignore_patterns(cfg_dir)
# Optional: Lade Übersetzungs-Config
translation_dicts = None
if args.translate:
translation_dir = check_environment_var('PROJECT_TRANSLATION')
translation_dicts = load_translation_config(args.translate, translation_dir)
if args.debug: if args.debug:
print("DEBUG-Modus aktiviert") print("DEBUG-Modus aktiviert")
@@ -433,22 +593,22 @@ if __name__ == '__main__':
if args.export_type == 'excel': if args.export_type == 'excel':
if not output_filename.endswith('.xlsx'): if not output_filename.endswith('.xlsx'):
output_filename += '.xlsx' output_filename += '.xlsx'
else: # text else: # json
if not output_filename.endswith('.txt'): if not output_filename.endswith('.json'):
output_filename += '.txt' output_filename += '.json'
else: else:
# Standardname basierend auf Eingabedatei # Standardname basierend auf Eingabedatei
if args.export_type == 'excel': if args.export_type == 'excel':
output_filename = filename.stem + "_texts.xlsx" output_filename = filename.stem + "_texts.xlsx"
else: # text else: # json
output_filename = filename.stem + "_texts.txt" output_filename = filename.stem + "_texts.json"
output_path = work_dir / output_filename output_path = work_dir / output_filename
# Schreibe Texte in gewähltem Format # Schreibe Texte in gewähltem Format
if args.export_type == 'excel': if args.export_type == 'excel':
write_texts_to_excel(texts, output_path) write_texts_to_excel(texts, output_path, translation_dicts)
else: # text else: # json
write_texts_to_textfile(texts, ignored_texts, output_path) write_texts_to_json(texts, ignored_texts, output_path, translation_dicts)
print("Verarbeitung erfolgreich abgeschlossen.") print("Verarbeitung erfolgreich abgeschlossen.")