multi Block in Übersetzungs config eingefügt.
This commit is contained in:
+325
-33
@@ -16,9 +16,10 @@ 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)
|
||||||
ODER liest den 'untranslated' Block aus einer JSON Datei
|
ODER liest den 'untranslated' Block aus einer JSON Datei
|
||||||
|
ODER übersetzt TEXT/MTEXT direkt in einer DXF und erstellt neue übersetzte DXF
|
||||||
- filtert die Texte basierend auf Mustern in translator.cfg
|
- filtert die Texte basierend auf Mustern in translator.cfg
|
||||||
- übersetzt optional Texte mit Trigrammen, Bigrammen und Einzelwörtern aus translation/<LANG>.cfg
|
- übersetzt optional Texte mit Trigrammen, Bigrammen und Einzelwörtern aus translation/<LANG>.cfg
|
||||||
- schreibt die Ergebnisse in eine Excel- oder JSON-Datei
|
- schreibt die Ergebnisse in eine Excel-, JSON- oder Text-Datei
|
||||||
- speichert die Ausgabedatei im PROJECT_WORK Verzeichnis
|
- speichert die Ausgabedatei im PROJECT_WORK Verzeichnis
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ 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]]:
|
def load_translation_config(translation_lang: str, translation_dir: Path) -> tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
Lädt eine Übersetzungs-Config-Datei (z.B. CSK.cfg, EN.cfg, FR.cfg).
|
Lädt eine Übersetzungs-Config-Datei (z.B. CSK.cfg, EN.cfg, FR.cfg).
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
|||||||
translation_dir: Verzeichnis mit Übersetzungs-Configs (aus PROJECT_TRANSLATION)
|
translation_dir: Verzeichnis mit Übersetzungs-Configs (aus PROJECT_TRANSLATION)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple mit (Trigramme-Dict, Bigramme-Dict, Single-Dict)
|
Tuple mit (Multi-Dict, Trigramme-Dict, Bigramme-Dict, Single-Dict)
|
||||||
"""
|
"""
|
||||||
config_file = translation_dir / f"{translation_lang}.cfg"
|
config_file = translation_dir / f"{translation_lang}.cfg"
|
||||||
|
|
||||||
@@ -60,10 +61,19 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
|||||||
print(f"Fehler beim Lesen der Übersetzungs-Konfiguration: {e}")
|
print(f"Fehler beim Lesen der Übersetzungs-Konfiguration: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
multi = {}
|
||||||
trigramme = {}
|
trigramme = {}
|
||||||
bigramme = {}
|
bigramme = {}
|
||||||
single = {}
|
single = {}
|
||||||
|
|
||||||
|
# Lade Multi (4+ Wörter)
|
||||||
|
if config.has_section('multi'):
|
||||||
|
for key in config['multi']:
|
||||||
|
original = key
|
||||||
|
translation = config['multi'][key]
|
||||||
|
if translation and not translation.startswith('#'):
|
||||||
|
multi[original] = translation
|
||||||
|
|
||||||
# Lade Trigramme
|
# Lade Trigramme
|
||||||
if config.has_section('trigramme'):
|
if config.has_section('trigramme'):
|
||||||
for key in config['trigramme']:
|
for key in config['trigramme']:
|
||||||
@@ -89,11 +99,12 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
|||||||
single[original] = translation
|
single[original] = translation
|
||||||
|
|
||||||
print(f"\nÜbersetzungs-Config geladen ({translation_lang}):")
|
print(f"\nÜbersetzungs-Config geladen ({translation_lang}):")
|
||||||
|
print(f" Multi-Phrasen: {len(multi)}")
|
||||||
print(f" Trigramme: {len(trigramme)}")
|
print(f" Trigramme: {len(trigramme)}")
|
||||||
print(f" Bigramme: {len(bigramme)}")
|
print(f" Bigramme: {len(bigramme)}")
|
||||||
print(f" Einzelwörter: {len(single)}")
|
print(f" Einzelwörter: {len(single)}")
|
||||||
|
|
||||||
return trigramme, bigramme, single
|
return multi, 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]]:
|
||||||
@@ -152,10 +163,10 @@ 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:
|
def translate_text(text: str, multi: dict[str, 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.
|
Übersetzt einen Text durch Ersetzen von Multi-Phrasen, Trigrammen, Bigrammen und Einzelwörtern.
|
||||||
Ersetzungen erfolgen in dieser Reihenfolge: Trigramme → Bigramme → Einzelwörter.
|
Ersetzungen erfolgen in dieser Reihenfolge: Multi → Trigramme → Bigramme → Einzelwörter.
|
||||||
|
|
||||||
Bei Einzelwörtern werden auch Satzzeichen und eingebettete Wörter berücksichtigt:
|
Bei Einzelwörtern werden auch Satzzeichen und eingebettete Wörter berücksichtigt:
|
||||||
- "Weight:" wird zu "Hmotnost:" (Doppelpunkt bleibt erhalten)
|
- "Weight:" wird zu "Hmotnost:" (Doppelpunkt bleibt erhalten)
|
||||||
@@ -166,6 +177,7 @@ def translate_text(text: str, trigramme: dict[str, str], bigramme: dict[str, str
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: Zu übersetzender Text
|
text: Zu übersetzender Text
|
||||||
|
multi: Dictionary mit Multi-Wort-Phrasen (4+ Wörter)
|
||||||
trigramme: Dictionary mit Drei-Wort-Phrasen
|
trigramme: Dictionary mit Drei-Wort-Phrasen
|
||||||
bigramme: Dictionary mit Zwei-Wort-Phrasen
|
bigramme: Dictionary mit Zwei-Wort-Phrasen
|
||||||
single: Dictionary mit Einzelwörtern
|
single: Dictionary mit Einzelwörtern
|
||||||
@@ -176,19 +188,25 @@ def translate_text(text: str, trigramme: dict[str, str], bigramme: dict[str, str
|
|||||||
translated_text = text
|
translated_text = text
|
||||||
has_translation = False
|
has_translation = False
|
||||||
|
|
||||||
# 1. Trigramme ersetzen (längste Phrasen zuerst)
|
# 1. Multi-Phrasen ersetzen (längste Phrasen zuerst)
|
||||||
|
for original, translation in multi.items():
|
||||||
|
if original in translated_text:
|
||||||
|
translated_text = translated_text.replace(original, translation)
|
||||||
|
has_translation = True
|
||||||
|
|
||||||
|
# 2. Trigramme ersetzen
|
||||||
for original, translation in trigramme.items():
|
for original, translation in trigramme.items():
|
||||||
if original in translated_text:
|
if original in translated_text:
|
||||||
translated_text = translated_text.replace(original, translation)
|
translated_text = translated_text.replace(original, translation)
|
||||||
has_translation = True
|
has_translation = True
|
||||||
|
|
||||||
# 2. Bigramme ersetzen
|
# 3. Bigramme ersetzen
|
||||||
for original, translation in bigramme.items():
|
for original, translation in bigramme.items():
|
||||||
if original in translated_text:
|
if original in translated_text:
|
||||||
translated_text = translated_text.replace(original, translation)
|
translated_text = translated_text.replace(original, translation)
|
||||||
has_translation = True
|
has_translation = True
|
||||||
|
|
||||||
# 3. Einzelwörter ersetzen
|
# 4. Einzelwörter ersetzen
|
||||||
words = translated_text.split()
|
words = translated_text.split()
|
||||||
translated_words = []
|
translated_words = []
|
||||||
for word in words:
|
for word in words:
|
||||||
@@ -256,7 +274,7 @@ def should_ignore_text(text: str, wildcard_patterns: list[str], regex_patterns:
|
|||||||
|
|
||||||
def extract_text_from_dxf(filename: Path) -> list[str]:
|
def extract_text_from_dxf(filename: Path) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Extrahiert alle TEXT und MTEXT Objekte aus einer DXF Datei.
|
Extrahiert alle TEXT und MTEXT Objekte sowie TEXT-D Attribute aus Blöcken einer DXF Datei.
|
||||||
Verwendet ein Set, um Duplikate zu vermeiden.
|
Verwendet ein Set, um Duplikate zu vermeiden.
|
||||||
Filtert leere Texte heraus.
|
Filtert leere Texte heraus.
|
||||||
|
|
||||||
@@ -267,9 +285,14 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
|||||||
Alphabetisch sortierte Liste aller gefundenen Texte (ohne Duplikate, ohne leere Texte)
|
Alphabetisch sortierte Liste aller gefundenen Texte (ohne Duplikate, ohne leere Texte)
|
||||||
"""
|
"""
|
||||||
texts_set = set() # Set für eindeutige Texte
|
texts_set = set() # Set für eindeutige Texte
|
||||||
total_count = 0
|
text_count = 0
|
||||||
|
mtext_count = 0
|
||||||
|
block_count = 0
|
||||||
empty_count = 0
|
empty_count = 0
|
||||||
|
|
||||||
|
# Attribute die ein Block haben muss, damit TEXT-D extrahiert wird
|
||||||
|
required_attributes = {'IO', 'ID', 'VERW', 'BEZEICHNUNG', 'KENNZEICHNUNG', 'TEXT-D'}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
doc = ezdxf.readfile(filename)
|
doc = ezdxf.readfile(filename)
|
||||||
msp = doc.modelspace()
|
msp = doc.modelspace()
|
||||||
@@ -277,7 +300,7 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
|||||||
# Sammle alle TEXT Objekte
|
# Sammle alle TEXT Objekte
|
||||||
for entity in msp.query('TEXT'):
|
for entity in msp.query('TEXT'):
|
||||||
if entity.dxf.text:
|
if entity.dxf.text:
|
||||||
total_count += 1
|
text_count += 1
|
||||||
text = entity.dxf.text.strip() # Entferne führende/nachfolgende Leerzeichen
|
text = entity.dxf.text.strip() # Entferne führende/nachfolgende Leerzeichen
|
||||||
|
|
||||||
# Ignoriere leere Texte
|
# Ignoriere leere Texte
|
||||||
@@ -290,7 +313,7 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
|||||||
# Sammle alle MTEXT Objekte
|
# Sammle alle MTEXT Objekte
|
||||||
for entity in msp.query('MTEXT'):
|
for entity in msp.query('MTEXT'):
|
||||||
if entity.text:
|
if entity.text:
|
||||||
total_count += 1
|
mtext_count += 1
|
||||||
text = entity.text.strip() # Entferne führende/nachfolgende Leerzeichen
|
text = entity.text.strip() # Entferne führende/nachfolgende Leerzeichen
|
||||||
|
|
||||||
# Ignoriere leere Texte
|
# Ignoriere leere Texte
|
||||||
@@ -300,11 +323,37 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
|||||||
|
|
||||||
texts_set.add(text)
|
texts_set.add(text)
|
||||||
|
|
||||||
|
# Sammle TEXT-D aus Blöcken mit den erforderlichen Attributen
|
||||||
|
for entity in msp.query('INSERT'):
|
||||||
|
if entity.has_attrib:
|
||||||
|
# Sammle alle vorhandenen Attribute des Blocks
|
||||||
|
block_attributes = set()
|
||||||
|
text_d_value = None
|
||||||
|
|
||||||
|
for attrib in entity.attribs:
|
||||||
|
block_attributes.add(attrib.dxf.tag)
|
||||||
|
if attrib.dxf.tag == 'TEXT-D':
|
||||||
|
text_d_value = attrib.dxf.text.strip() if attrib.dxf.text else None
|
||||||
|
|
||||||
|
# Prüfe ob Block alle erforderlichen Attribute hat
|
||||||
|
if required_attributes.issubset(block_attributes) and text_d_value:
|
||||||
|
block_count += 1
|
||||||
|
|
||||||
|
# Ignoriere leere Texte
|
||||||
|
if not text_d_value:
|
||||||
|
empty_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
texts_set.add(text_d_value)
|
||||||
|
|
||||||
# Konvertiere Set zu sortierter Liste
|
# Konvertiere Set zu sortierter Liste
|
||||||
texts = sorted(texts_set)
|
texts = sorted(texts_set)
|
||||||
|
|
||||||
print(f"Anzahl gefundener TEXT/MTEXT Objekte: {total_count}")
|
print(f"Anzahl gefundener TEXT Objekte: {text_count}")
|
||||||
|
print(f"Anzahl gefundener MTEXT Objekte: {mtext_count}")
|
||||||
|
print(f"Anzahl gefundener TEXT-D in Blöcken: {block_count}")
|
||||||
print(f"Leere Texte ignoriert: {empty_count}")
|
print(f"Leere Texte ignoriert: {empty_count}")
|
||||||
|
total_count = text_count + mtext_count + block_count
|
||||||
print(f"Duplikate entfernt: {total_count - empty_count - len(texts)}")
|
print(f"Duplikate entfernt: {total_count - empty_count - len(texts)}")
|
||||||
print(f"Eindeutige Texte extrahiert: {len(texts)}")
|
print(f"Eindeutige Texte extrahiert: {len(texts)}")
|
||||||
|
|
||||||
@@ -440,8 +489,173 @@ def read_texts_from_json(filename: Path) -> list[str]:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def load_translations_from_json(filename: Path) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Liest Übersetzungen aus dem 'translations' Block einer JSON-Datei.
|
||||||
|
Erwartet eine Struktur mit "translations": [{"source": "...", "target": "..."}, ...]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: Pfad zur JSON-Datei
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary mit source -> target Mappings
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(filename, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
source = entry['source']
|
||||||
|
target = entry['target']
|
||||||
|
if source and target: # Ignoriere leere Einträge
|
||||||
|
translations[source] = target
|
||||||
|
|
||||||
|
print(f"Übersetzungen aus JSON-Datei geladen: {len(translations)}")
|
||||||
|
return translations
|
||||||
|
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"Fehler beim Parsen der JSON-Datei: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Lesen der JSON-Datei: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[str, str],
|
||||||
|
wildcard_patterns: list[str], regex_patterns: list[str]):
|
||||||
|
"""
|
||||||
|
Übersetzt alle TEXT, MTEXT Objekte und TEXT-D Attribute in Blöcken einer DXF-Datei.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_dxf: Pfad zur Quell-DXF
|
||||||
|
output_dxf: Pfad zur Ziel-DXF
|
||||||
|
translations: Dictionary mit source -> target Mappings
|
||||||
|
wildcard_patterns: Wildcard-Muster zum Filtern
|
||||||
|
regex_patterns: Regex-Muster zum Filtern
|
||||||
|
"""
|
||||||
|
# Attribute die ein Block haben muss, damit TEXT-D übersetzt wird
|
||||||
|
required_attributes = {'IO', 'ID', 'VERW', 'BEZEICHNUNG', 'KENNZEICHNUNG', 'TEXT-D'}
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc = ezdxf.readfile(input_dxf)
|
||||||
|
msp = doc.modelspace()
|
||||||
|
|
||||||
|
text_translated = 0
|
||||||
|
text_skipped = 0
|
||||||
|
text_ignored = 0
|
||||||
|
mtext_translated = 0
|
||||||
|
mtext_skipped = 0
|
||||||
|
mtext_ignored = 0
|
||||||
|
block_translated = 0
|
||||||
|
block_skipped = 0
|
||||||
|
block_ignored = 0
|
||||||
|
|
||||||
|
# Übersetze TEXT Objekte
|
||||||
|
for entity in msp.query('TEXT'):
|
||||||
|
if entity.dxf.text:
|
||||||
|
original_text = entity.dxf.text.strip()
|
||||||
|
|
||||||
|
# Prüfe ob Text ignoriert werden soll
|
||||||
|
if should_ignore_text(original_text, wildcard_patterns, regex_patterns):
|
||||||
|
text_ignored += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Suche Übersetzung
|
||||||
|
if original_text in translations:
|
||||||
|
entity.dxf.text = translations[original_text]
|
||||||
|
text_translated += 1
|
||||||
|
else:
|
||||||
|
text_skipped += 1
|
||||||
|
|
||||||
|
# Übersetze MTEXT Objekte
|
||||||
|
for entity in msp.query('MTEXT'):
|
||||||
|
if entity.text:
|
||||||
|
original_text = entity.text.strip()
|
||||||
|
|
||||||
|
# Prüfe ob Text ignoriert werden soll
|
||||||
|
if should_ignore_text(original_text, wildcard_patterns, regex_patterns):
|
||||||
|
mtext_ignored += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Suche Übersetzung
|
||||||
|
if original_text in translations:
|
||||||
|
entity.text = translations[original_text]
|
||||||
|
mtext_translated += 1
|
||||||
|
else:
|
||||||
|
mtext_skipped += 1
|
||||||
|
|
||||||
|
# Übersetze TEXT-D in Blöcken
|
||||||
|
for entity in msp.query('INSERT'):
|
||||||
|
if entity.has_attrib:
|
||||||
|
# Sammle alle vorhandenen Attribute des Blocks
|
||||||
|
block_attributes = set()
|
||||||
|
text_d_attrib = None
|
||||||
|
|
||||||
|
for attrib in entity.attribs:
|
||||||
|
block_attributes.add(attrib.dxf.tag)
|
||||||
|
if attrib.dxf.tag == 'TEXT-D':
|
||||||
|
text_d_attrib = attrib
|
||||||
|
|
||||||
|
# Prüfe ob Block alle erforderlichen Attribute hat
|
||||||
|
if required_attributes.issubset(block_attributes) and text_d_attrib:
|
||||||
|
original_text = text_d_attrib.dxf.text.strip() if text_d_attrib.dxf.text else None
|
||||||
|
|
||||||
|
if original_text:
|
||||||
|
# Prüfe ob Text ignoriert werden soll
|
||||||
|
if should_ignore_text(original_text, wildcard_patterns, regex_patterns):
|
||||||
|
block_ignored += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Suche Übersetzung
|
||||||
|
if original_text in translations:
|
||||||
|
text_d_attrib.dxf.text = translations[original_text]
|
||||||
|
block_translated += 1
|
||||||
|
else:
|
||||||
|
block_skipped += 1
|
||||||
|
|
||||||
|
# Speichere neue DXF
|
||||||
|
doc.saveas(output_dxf)
|
||||||
|
|
||||||
|
translated_count = text_translated + mtext_translated + block_translated
|
||||||
|
skipped_count = text_skipped + mtext_skipped + block_skipped
|
||||||
|
ignored_count = text_ignored + mtext_ignored + block_ignored
|
||||||
|
|
||||||
|
print(f"\nDXF-Übersetzung abgeschlossen:")
|
||||||
|
print(f" TEXT übersetzt: {text_translated}, übersprungen: {text_skipped}, ignoriert: {text_ignored}")
|
||||||
|
print(f" MTEXT übersetzt: {mtext_translated}, übersprungen: {mtext_skipped}, ignoriert: {mtext_ignored}")
|
||||||
|
print(f" TEXT-D (Blöcke) übersetzt: {block_translated}, übersprungen: {block_skipped}, ignoriert: {block_ignored}")
|
||||||
|
print(f" Gesamt: {translated_count} übersetzt, {skipped_count} übersprungen, {ignored_count} ignoriert")
|
||||||
|
print(f" Ausgabe-Datei: {output_dxf}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Übersetzen der DXF-Datei: {e}")
|
||||||
|
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):
|
translation_dicts: tuple[dict[str, str], 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.
|
Optional: Schreibt Übersetzungen in die zweite Spalte.
|
||||||
@@ -449,7 +663,7 @@ def write_texts_to_excel(texts: list[str], output_path: Path,
|
|||||||
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
|
translation_dicts: Optional: Tuple mit (Multi, Trigramme, Bigramme, Single) für Übersetzungen
|
||||||
"""
|
"""
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
@@ -466,8 +680,8 @@ def write_texts_to_excel(texts: list[str], output_path: Path,
|
|||||||
|
|
||||||
# Optional: Übersetzung in zweite Spalte
|
# Optional: Übersetzung in zweite Spalte
|
||||||
if translation_dicts:
|
if translation_dicts:
|
||||||
trigramme, bigramme, single = translation_dicts
|
multi, trigramme, bigramme, single = translation_dicts
|
||||||
translated = translate_text(text, trigramme, bigramme, single)
|
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||||
if translated: # Nur wenn Übersetzung gefunden wurde
|
if translated: # Nur wenn Übersetzung gefunden wurde
|
||||||
ws[f'B{idx}'] = translated
|
ws[f'B{idx}'] = translated
|
||||||
# Sonst bleibt die Zelle leer
|
# Sonst bleibt die Zelle leer
|
||||||
@@ -488,7 +702,7 @@ 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,
|
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):
|
translation_dicts: tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]] = None):
|
||||||
"""
|
"""
|
||||||
Schreibt die Texte in eine JSON-Datei mit drei Blöcken.
|
Schreibt die Texte in eine JSON-Datei mit drei Blöcken.
|
||||||
|
|
||||||
@@ -501,19 +715,19 @@ def write_texts_to_json(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
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-JSON-Datei
|
output_path: Pfad zur Ausgabe-JSON-Datei
|
||||||
translation_dicts: Optional: Tuple mit (Trigramme, Bigramme, Single) für Übersetzungen
|
translation_dicts: Optional: Tuple mit (Multi, Trigramme, Bigramme, Single) für Übersetzungen
|
||||||
"""
|
"""
|
||||||
output_data = {}
|
output_data = {}
|
||||||
|
|
||||||
# Block 1: Übersetzte Texte (als Liste von Dicts mit source/target)
|
# 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)
|
# Block 2: Nicht übersetzte Texte (als Liste von Dicts mit source und leerem target)
|
||||||
if translation_dicts:
|
if translation_dicts:
|
||||||
trigramme, bigramme, single = translation_dicts
|
multi, trigramme, bigramme, single = translation_dicts
|
||||||
translations = []
|
translations = []
|
||||||
untranslated = []
|
untranslated = []
|
||||||
|
|
||||||
for text in texts:
|
for text in texts:
|
||||||
translated = translate_text(text, trigramme, bigramme, single)
|
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||||
if translated: # Übersetzung vorhanden
|
if translated: # Übersetzung vorhanden
|
||||||
translations.append({
|
translations.append({
|
||||||
"source": text,
|
"source": text,
|
||||||
@@ -552,7 +766,7 @@ def write_texts_to_json(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
|
|
||||||
|
|
||||||
def write_texts_to_text(texts: list[str], ignored_texts: list[str], output_path: Path,
|
def write_texts_to_text(texts: list[str], ignored_texts: list[str], output_path: Path,
|
||||||
translation_dicts: tuple[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):
|
||||||
"""
|
"""
|
||||||
Schreibt die Texte in eine Textdatei mit drei Abschnitten.
|
Schreibt die Texte in eine Textdatei mit drei Abschnitten.
|
||||||
|
|
||||||
@@ -576,18 +790,18 @@ def write_texts_to_text(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
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-Textdatei
|
||||||
translation_dicts: Optional: Tuple mit (Trigramme, Bigramme, Single) für Übersetzungen
|
translation_dicts: Optional: Tuple mit (Multi, Trigramme, Bigramme, Single) für Übersetzungen
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with open(output_path, 'w', encoding='utf-8') as f:
|
with open(output_path, 'w', encoding='utf-8') as f:
|
||||||
# Block 1: Übersetzte Texte
|
# Block 1: Übersetzte Texte
|
||||||
if translation_dicts:
|
if translation_dicts:
|
||||||
trigramme, bigramme, single = translation_dicts
|
multi, trigramme, bigramme, single = translation_dicts
|
||||||
translations = []
|
translations = []
|
||||||
untranslated = []
|
untranslated = []
|
||||||
|
|
||||||
for text in texts:
|
for text in texts:
|
||||||
translated = translate_text(text, trigramme, bigramme, single)
|
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||||
if translated:
|
if translated:
|
||||||
translations.append((text, translated))
|
translations.append((text, translated))
|
||||||
else:
|
else:
|
||||||
@@ -617,7 +831,7 @@ def write_texts_to_text(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
|
|
||||||
print(f"Text-Datei erfolgreich erstellt: {output_path}")
|
print(f"Text-Datei erfolgreich erstellt: {output_path}")
|
||||||
if translation_dicts:
|
if translation_dicts:
|
||||||
translations_count = sum(1 for text in texts if translate_text(text, trigramme, bigramme, single))
|
translations_count = sum(1 for text in texts if translate_text(text, multi, trigramme, bigramme, single))
|
||||||
untranslated_count = len(texts) - translations_count
|
untranslated_count = len(texts) - translations_count
|
||||||
print(f" Übersetzungen: {translations_count}")
|
print(f" Übersetzungen: {translations_count}")
|
||||||
print(f" Nicht übersetzte Texte: {untranslated_count}")
|
print(f" Nicht übersetzte Texte: {untranslated_count}")
|
||||||
@@ -632,11 +846,11 @@ def write_texts_to_text(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Extrahiert TEXT/MTEXT aus DXF, filtert Texte aus TXT, oder verarbeitet untranslated Block aus JSON. Optional mit Übersetzungsfunktion.',
|
description='Extrahiert TEXT/MTEXT aus DXF, filtert Texte aus TXT, verarbeitet JSON, oder übersetzt DXF direkt. Optional mit Übersetzungsfunktion.',
|
||||||
prog='translate'
|
prog='translate'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mutually exclusive group: entweder DXF-Extraktion, TXT-Filterung oder JSON-Reprocessing
|
# Mutually exclusive group: entweder DXF-Extraktion, TXT-Filterung, JSON-Reprocessing oder DXF-zu-DXF
|
||||||
input_group = parser.add_mutually_exclusive_group(required=True)
|
input_group = parser.add_mutually_exclusive_group(required=True)
|
||||||
input_group.add_argument(
|
input_group.add_argument(
|
||||||
'-e', '--extract',
|
'-e', '--extract',
|
||||||
@@ -655,6 +869,12 @@ if __name__ == '__main__':
|
|||||||
metavar='FILE.json',
|
metavar='FILE.json',
|
||||||
help='Liest untranslated Block aus JSON-Datei und übersetzt erneut (benötigt --translate)'
|
help='Liest untranslated Block aus JSON-Datei und übersetzt erneut (benötigt --translate)'
|
||||||
)
|
)
|
||||||
|
input_group.add_argument(
|
||||||
|
'--todxf',
|
||||||
|
action='store',
|
||||||
|
metavar='OUTPUT.dxf',
|
||||||
|
help='Übersetzt TEXT/MTEXT in DXF und schreibt neue DXF-Datei (benötigt --filename)'
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-f', '--filename',
|
'-f', '--filename',
|
||||||
@@ -686,6 +906,12 @@ if __name__ == '__main__':
|
|||||||
metavar='LANG',
|
metavar='LANG',
|
||||||
help='Übersetzt Texte mit Config aus translation/<LANG>.cfg (z.B. CSK, EN, FR)'
|
help='Übersetzt Texte mit Config aus translation/<LANG>.cfg (z.B. CSK, EN, FR)'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--translation-json',
|
||||||
|
action='store',
|
||||||
|
metavar='FILE.json',
|
||||||
|
help='JSON-Datei mit Übersetzungen für --todxf (Standard: <filename>_texts.json)'
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -693,14 +919,22 @@ if __name__ == '__main__':
|
|||||||
if args.extract and not args.filename:
|
if args.extract and not args.filename:
|
||||||
parser.error("--extract benötigt --filename")
|
parser.error("--extract benötigt --filename")
|
||||||
|
|
||||||
# Validierung: --filename nur mit --extract
|
# Validierung: --filename nur mit --extract oder --todxf
|
||||||
if args.filename and not args.extract:
|
if args.filename and not (args.extract or args.todxf):
|
||||||
parser.error("--filename kann nur mit --extract verwendet werden")
|
parser.error("--filename kann nur mit --extract oder --todxf verwendet werden")
|
||||||
|
|
||||||
# Validierung: --fromjson benötigt --translate
|
# Validierung: --fromjson benötigt --translate
|
||||||
if args.fromjson and not args.translate:
|
if args.fromjson and not args.translate:
|
||||||
parser.error("--fromjson benötigt --translate (Übersetzung ist erforderlich)")
|
parser.error("--fromjson benötigt --translate (Übersetzung ist erforderlich)")
|
||||||
|
|
||||||
|
# Validierung: --todxf benötigt --filename
|
||||||
|
if args.todxf and not args.filename:
|
||||||
|
parser.error("--todxf benötigt --filename (Quell-DXF muss angegeben werden)")
|
||||||
|
|
||||||
|
# Validierung: --translation-json nur mit --todxf
|
||||||
|
if args.translation_json and not args.todxf:
|
||||||
|
parser.error("--translation-json kann nur mit --todxf verwendet werden")
|
||||||
|
|
||||||
# Prüfe Umgebungsvariablen
|
# Prüfe Umgebungsvariablen
|
||||||
work_dir = check_environment_var('PROJECT_WORK')
|
work_dir = check_environment_var('PROJECT_WORK')
|
||||||
cfg_dir = check_environment_var('PROJECT_CFG')
|
cfg_dir = check_environment_var('PROJECT_CFG')
|
||||||
@@ -717,6 +951,64 @@ if __name__ == '__main__':
|
|||||||
if args.debug:
|
if args.debug:
|
||||||
print("DEBUG-Modus aktiviert")
|
print("DEBUG-Modus aktiviert")
|
||||||
|
|
||||||
|
# Spezieller Workflow: DXF-zu-DXF Übersetzung
|
||||||
|
if args.todxf:
|
||||||
|
print("=== DXF-zu-DXF Übersetzung ===\n")
|
||||||
|
|
||||||
|
# Finde Quell-DXF
|
||||||
|
input_filename = args.filename
|
||||||
|
if not input_filename.lower().endswith(('.dxf', '.dwg')):
|
||||||
|
print("Mit --todxf nur .dxf oder .dwg Dateien als Quelle erlaubt")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
source_dxf = work_dir / input_filename
|
||||||
|
if not source_dxf.exists():
|
||||||
|
source_dxf = Path(input_filename)
|
||||||
|
if not source_dxf.exists():
|
||||||
|
print(f"Quell-DXF nicht gefunden: {input_filename}")
|
||||||
|
print(f" Geprüft in Work-Ordner: {work_dir / input_filename}")
|
||||||
|
print(f" Geprüft als vollständiger Pfad: {source_dxf}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Quell-DXF: {source_dxf}")
|
||||||
|
|
||||||
|
# Bestimme JSON-Datei mit Übersetzungen
|
||||||
|
if args.translation_json:
|
||||||
|
translation_json = work_dir / args.translation_json
|
||||||
|
if not translation_json.exists():
|
||||||
|
translation_json = Path(args.translation_json)
|
||||||
|
if not translation_json.exists():
|
||||||
|
print(f"Übersetzungs-JSON nicht gefunden: {args.translation_json}")
|
||||||
|
print(f" Geprüft in Work-Ordner: {work_dir / args.translation_json}")
|
||||||
|
print(f" Geprüft als vollständiger Pfad: {translation_json}")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
# Standard: <filename>_texts.json im Work-Ordner
|
||||||
|
translation_json = work_dir / (Path(input_filename).stem + "_texts.json")
|
||||||
|
if not translation_json.exists():
|
||||||
|
print(f"Standard-Übersetzungs-JSON nicht gefunden: {translation_json}")
|
||||||
|
print(f"Bitte erstellen Sie die Datei oder geben Sie eine alternative mit --translation-json an")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Übersetzungs-JSON: {translation_json}")
|
||||||
|
|
||||||
|
# Lade Übersetzungen
|
||||||
|
translations = load_translations_from_json(translation_json)
|
||||||
|
|
||||||
|
# Bestimme Ausgabe-DXF
|
||||||
|
output_dxf_name = args.todxf
|
||||||
|
if not output_dxf_name.lower().endswith(('.dxf', '.dwg')):
|
||||||
|
output_dxf_name += '.dxf'
|
||||||
|
output_dxf = work_dir / output_dxf_name
|
||||||
|
|
||||||
|
print(f"Ziel-DXF: {output_dxf}")
|
||||||
|
|
||||||
|
# Übersetze DXF
|
||||||
|
translate_dxf_texts(source_dxf, output_dxf, translations, wildcard_patterns, regex_patterns)
|
||||||
|
|
||||||
|
print("\nVerarbeitung erfolgreich abgeschlossen.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
# Bestimme Input-Modus und Datei
|
# Bestimme Input-Modus und Datei
|
||||||
if args.extract:
|
if args.extract:
|
||||||
# DXF/DWG-Modus
|
# DXF/DWG-Modus
|
||||||
|
|||||||
@@ -97,8 +97,11 @@ with TEF=with TEF
|
|||||||
# ## deutsch
|
# ## deutsch
|
||||||
Abhänger=Závěs
|
Abhänger=Závěs
|
||||||
BLOCK=BLOK
|
BLOCK=BLOK
|
||||||
|
Betriebsbereit=Provozuschopný
|
||||||
|
Betriebshalt=Zastavení provozu
|
||||||
Belastung=Zatížení
|
Belastung=Zatížení
|
||||||
Brandschutztor=protipožární vrata
|
Brandschutztor=protipožární vrata
|
||||||
|
Reset=Obnovení
|
||||||
Säule=Sloup
|
Säule=Sloup
|
||||||
Schnitt=Řez
|
Schnitt=Řez
|
||||||
Unterverteiler=Rozvaděč
|
Unterverteiler=Rozvaděč
|
||||||
@@ -178,4 +181,16 @@ Weight=Hmotnost
|
|||||||
with=s
|
with=s
|
||||||
|
|
||||||
|
|
||||||
|
[multi]
|
||||||
|
LM Störung=Porucha LM
|
||||||
|
Not-Halt Kanal=Kanál nouzového zastavení
|
||||||
|
DT Anlage Aus=DT zařízení vypnuto
|
||||||
|
LDT Anlage Ein=LDT zařízení zapnuto
|
||||||
|
LM Brandfall=Požár LM
|
||||||
|
LM Druckluft fehlt=LM: chybí stlačený vzduch
|
||||||
|
LM Lampentest=Test lampy LM
|
||||||
|
LM Motorschutz hat ausgelöst=LM: ochrana motoru se spustila
|
||||||
|
LM Sicherung hat ausgelöst=LM: pojistka byla vypla
|
||||||
|
LDT Start nach Störung=LDT: spuštění po poruše
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user