eigene Routine für die Ergänzung der Blockattribute für TEXT-CS geschrieben. Der Layer der Symbole für die jeweilige Zielsprache ins in translate.cfg einstellbar
This commit is contained in:
@@ -72,3 +72,14 @@ ip_adress = ^.*;(\d{1,3}\.){3}\d{1,3}$
|
||||
tunnel = ^\\fArial.*TUNNEL\d+-\d{4}$
|
||||
|
||||
kw_A = ^\d+\s*KW\s*-\s*\d+\s*A$
|
||||
|
||||
|
||||
[symbolattribute]
|
||||
# Zuordnung von Sprachcodes zu Block-Attributnamen für Texte
|
||||
# Format: SPRACHCODE = TEXT-ATTRIBUTNAME
|
||||
# Diese Zuordnung wird verwendet um die richtigen Attribute aus DXF-Blöcken zu lesen/schreiben
|
||||
DE = TEXT-D
|
||||
EN = TEXT-EN
|
||||
CS = TEXT-CS
|
||||
FR = TEXT-FR
|
||||
PL = TEXT-PL
|
||||
|
||||
+175
-44
@@ -36,10 +36,10 @@ def check_environment_var(env_str: str) -> Path:
|
||||
|
||||
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. CS.cfg, EN.cfg, FR.cfg).
|
||||
|
||||
Args:
|
||||
translation_lang: Sprach-Code (z.B. "CSK", "EN", "FR")
|
||||
translation_lang: Sprach-Code (z.B. "CS", "EN", "FR")
|
||||
translation_dir: Verzeichnis mit Übersetzungs-Configs (aus PROJECT_TRANSLATION)
|
||||
|
||||
Returns:
|
||||
@@ -107,6 +107,49 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
||||
return multi, trigramme, bigramme, single
|
||||
|
||||
|
||||
def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
|
||||
"""
|
||||
Liest die Zuordnung von Sprachcodes zu Symbol-Attributnamen aus der translator.cfg Datei.
|
||||
|
||||
Args:
|
||||
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
|
||||
|
||||
Returns:
|
||||
Dictionary mit Sprachcode -> Attributname Mapping (z.B. "DE" -> "TEXT-D", "EN" -> "TEXT-EN")
|
||||
"""
|
||||
config_file = cfg_path / "translator.cfg"
|
||||
|
||||
if not config_file.exists():
|
||||
print(f"FEHLER: Konfigurationsdatei nicht gefunden: {config_file}")
|
||||
print(f"Bitte erstellen Sie die Datei 'translator.cfg' im Verzeichnis: {cfg_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# RawConfigParser verhindert dass Backslashes in Regex-Mustern escaped werden
|
||||
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 Konfigurationsdatei: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
symbol_mapping = {}
|
||||
|
||||
# Lade Symbol-Attribut-Zuordnung
|
||||
if config.has_section('symbolattribute'):
|
||||
for key in config['symbolattribute']:
|
||||
attr_name = config['symbolattribute'][key].strip()
|
||||
if attr_name and not attr_name.startswith('#'):
|
||||
symbol_mapping[key] = attr_name
|
||||
|
||||
print(f"\nGeladene Symbol-Attribut-Zuordnungen: {len(symbol_mapping)}")
|
||||
for lang, attr in symbol_mapping.items():
|
||||
print(f" {lang} -> {attr}")
|
||||
|
||||
return symbol_mapping
|
||||
|
||||
|
||||
def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
|
||||
"""
|
||||
Liest die ignore_pattern aus der translator.cfg Datei.
|
||||
@@ -272,14 +315,15 @@ def should_ignore_text(text: str, wildcard_patterns: list[str], regex_patterns:
|
||||
return False
|
||||
|
||||
|
||||
def extract_text_from_dxf(filename: Path) -> list[str]:
|
||||
def extract_text_from_dxf(filename: Path, text_attr_name: str = 'TEXT-D') -> list[str]:
|
||||
"""
|
||||
Extrahiert alle TEXT und MTEXT Objekte sowie TEXT-D Attribute aus Blöcken einer DXF Datei.
|
||||
Extrahiert alle TEXT und MTEXT Objekte sowie TEXT-{attr} Attribute aus Blöcken einer DXF Datei.
|
||||
Verwendet ein Set, um Duplikate zu vermeiden.
|
||||
Filtert leere Texte heraus.
|
||||
|
||||
Args:
|
||||
filename: Pfad zur DXF Datei
|
||||
text_attr_name: Name des Text-Attributs in Blöcken (z.B. "TEXT-D", "TEXT-EN", "TEXT-CS"). Standard: "TEXT-D"
|
||||
|
||||
Returns:
|
||||
Alphabetisch sortierte Liste aller gefundenen Texte (ohne Duplikate, ohne leere Texte)
|
||||
@@ -290,8 +334,8 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
||||
block_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'}
|
||||
# Attribute die ein Block haben muss, damit das Text-Attribut extrahiert wird
|
||||
required_attributes = {'IO', 'ID', 'VERW', 'BEZEICHNUNG', 'KENNZEICHNUNG', text_attr_name}
|
||||
|
||||
try:
|
||||
doc = ezdxf.readfile(filename)
|
||||
@@ -332,7 +376,7 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
||||
|
||||
for attrib in entity.attribs:
|
||||
block_attributes.add(attrib.dxf.tag)
|
||||
if attrib.dxf.tag == 'TEXT-D':
|
||||
if attrib.dxf.tag == text_attr_name:
|
||||
text_d_value = attrib.dxf.text.strip() if attrib.dxf.text else None
|
||||
|
||||
# Prüfe ob Block alle erforderlichen Attribute hat
|
||||
@@ -351,7 +395,7 @@ def extract_text_from_dxf(filename: Path) -> list[str]:
|
||||
|
||||
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"Anzahl gefundener {text_attr_name} in Blöcken: {block_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)}")
|
||||
@@ -543,10 +587,93 @@ def load_translations_from_json(filename: Path) -> dict[str, str]:
|
||||
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]):
|
||||
def translate_block_attribute(entity, translations: dict[str, str],
|
||||
wildcard_patterns: list[str], regex_patterns: list[str],
|
||||
required_attributes: set[str], text_source_attr: str, text_target_attr: str) -> tuple[int, int, int]:
|
||||
"""
|
||||
Übersetzt alle TEXT, MTEXT Objekte und TEXT-D Attribute in Blöcken einer DXF-Datei.
|
||||
Übersetzt Text-Attribute eines einzelnen Block-Inserts (INSERT entity).
|
||||
|
||||
Args:
|
||||
entity: INSERT entity aus der DXF-Datei
|
||||
translations: Dictionary mit source -> target Mappings
|
||||
wildcard_patterns: Wildcard-Muster zum Filtern
|
||||
regex_patterns: Regex-Muster zum Filtern
|
||||
required_attributes: Set mit erforderlichen Attributnamen für den Block
|
||||
text_source_attr: Quell-Attributname (z.B. "TEXT-D", "TEXT-EN")
|
||||
text_target_attr: Ziel-Attributname (z.B. "TEXT-EN", "TEXT-CS")
|
||||
|
||||
Returns:
|
||||
Tuple mit (translated_count, skipped_count, ignored_count) für diesen Block
|
||||
"""
|
||||
if not entity.has_attrib:
|
||||
return 0, 0, 0
|
||||
|
||||
# Sammle alle vorhandenen Attribute des Blocks
|
||||
block_attributes = {}
|
||||
text_source_attrib = None
|
||||
text_target_attrib = None
|
||||
|
||||
for attrib in entity.attribs:
|
||||
block_attributes[attrib.dxf.tag] = attrib
|
||||
if attrib.dxf.tag == text_source_attr:
|
||||
text_source_attrib = attrib
|
||||
elif attrib.dxf.tag == text_target_attr:
|
||||
text_target_attrib = attrib
|
||||
|
||||
# Prüfe ob Block alle erforderlichen Attribute hat
|
||||
if not (required_attributes.issubset(block_attributes.keys()) and text_source_attrib):
|
||||
return 0, 0, 0
|
||||
|
||||
original_text = text_source_attrib.dxf.text.strip() if text_source_attrib.dxf.text else None
|
||||
|
||||
if not original_text:
|
||||
return 0, 0, 0
|
||||
|
||||
# Prüfe ob Text ignoriert werden soll
|
||||
if should_ignore_text(original_text, wildcard_patterns, regex_patterns):
|
||||
return 0, 0, 1
|
||||
|
||||
# Suche Übersetzung
|
||||
if original_text not in translations:
|
||||
return 0, 1, 0
|
||||
|
||||
# Schreibe Übersetzung in Ziel-Attribut
|
||||
if text_target_attrib:
|
||||
# Ziel-Attribut existiert bereits, aktualisiere es
|
||||
text_target_attrib.dxf.text = translations[original_text]
|
||||
else:
|
||||
# Ziel-Attribut existiert nicht, erstelle es basierend auf Quell-Attribut
|
||||
# Kopiere alle Eigenschaften vom Quell-Attribut
|
||||
new_attrib = entity.add_attrib(
|
||||
tag=text_target_attr,
|
||||
text=translations[original_text],
|
||||
insert=text_source_attrib.dxf.insert
|
||||
)
|
||||
# Kopiere weitere Eigenschaften
|
||||
if text_source_attrib.dxf.hasattr('height'):
|
||||
new_attrib.dxf.height = text_source_attrib.dxf.height
|
||||
if text_source_attrib.dxf.hasattr('style'):
|
||||
new_attrib.dxf.style = text_source_attrib.dxf.style
|
||||
if text_source_attrib.dxf.hasattr('rotation'):
|
||||
new_attrib.dxf.rotation = text_source_attrib.dxf.rotation
|
||||
if text_source_attrib.dxf.hasattr('width'):
|
||||
new_attrib.dxf.width = text_source_attrib.dxf.width
|
||||
if text_source_attrib.dxf.hasattr('layer'):
|
||||
new_attrib.dxf.layer = text_source_attrib.dxf.layer
|
||||
|
||||
return 1, 0, 0
|
||||
|
||||
|
||||
def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[str, str],
|
||||
wildcard_patterns: list[str], regex_patterns: list[str],
|
||||
text_source_attr: str = 'TEXT-D', text_target_attr: str = 'TEXT-CS'):
|
||||
"""
|
||||
Übersetzt alle TEXT, MTEXT Objekte und Text-Attribute in Blöcken einer DXF-Datei.
|
||||
|
||||
Für Block-Attribute:
|
||||
- Liest die Übersetzung aus dem Quell-Attribut (z.B. TEXT-D)
|
||||
- Schreibt die Übersetzung in das Ziel-Attribut (z.B. TEXT-EN, TEXT-CS) (erstellt das Attribut falls nicht vorhanden)
|
||||
- Das Quell-Attribut bleibt unverändert (Original wird bewahrt)
|
||||
|
||||
Args:
|
||||
input_dxf: Pfad zur Quell-DXF
|
||||
@@ -554,9 +681,11 @@ def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[st
|
||||
translations: Dictionary mit source -> target Mappings
|
||||
wildcard_patterns: Wildcard-Muster zum Filtern
|
||||
regex_patterns: Regex-Muster zum Filtern
|
||||
text_source_attr: Quell-Attributname für Texte in Blöcken (z.B. "TEXT-D", "TEXT-EN"). Standard: "TEXT-D"
|
||||
text_target_attr: Ziel-Attributname für Übersetzungen in Blöcken (z.B. "TEXT-EN", "TEXT-CS"). Standard: "TEXT-CS"
|
||||
"""
|
||||
# Attribute die ein Block haben muss, damit TEXT-D übersetzt wird
|
||||
required_attributes = {'IO', 'ID', 'VERW', 'BEZEICHNUNG', 'KENNZEICHNUNG', 'TEXT-D'}
|
||||
# Attribute die ein Block haben muss, damit das Text-Attribut übersetzt wird
|
||||
required_attributes = {'IO', 'ID', 'VERW', 'BEZEICHNUNG', 'KENNZEICHNUNG', text_source_attr}
|
||||
|
||||
try:
|
||||
doc = ezdxf.readfile(input_dxf)
|
||||
@@ -606,34 +735,15 @@ def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[st
|
||||
else:
|
||||
mtext_skipped += 1
|
||||
|
||||
# Übersetze TEXT-D in Blöcken
|
||||
# Übersetze Text-Attribute 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
|
||||
translated, skipped, ignored = translate_block_attribute(
|
||||
entity, translations, wildcard_patterns, regex_patterns,
|
||||
required_attributes, text_source_attr, text_target_attr
|
||||
)
|
||||
block_translated += translated
|
||||
block_skipped += skipped
|
||||
block_ignored += ignored
|
||||
|
||||
# Speichere neue DXF
|
||||
doc.saveas(output_dxf)
|
||||
@@ -645,8 +755,9 @@ def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[st
|
||||
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" {text_target_attr} (Blöcke) erstellt/aktualisiert: {block_translated}, übersprungen: {block_skipped}, ignoriert: {block_ignored}")
|
||||
print(f" Gesamt: {translated_count} übersetzt, {skipped_count} übersprungen, {ignored_count} ignoriert")
|
||||
print(f" Hinweis: Übersetzungen in Blöcken wurden in {text_target_attr} geschrieben, TEXT-D bleibt unverändert")
|
||||
print(f" Ausgabe-Datei: {output_dxf}")
|
||||
|
||||
except Exception as e:
|
||||
@@ -904,7 +1015,14 @@ if __name__ == '__main__':
|
||||
'--translate',
|
||||
action='store',
|
||||
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. CS, EN, FR)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--lang_source',
|
||||
action='store',
|
||||
default='DE',
|
||||
metavar='LANG',
|
||||
help='Quellsprache für Attribut in Blöcken (z.B. DE->TEXT-D, EN->TEXT-EN, CS->TEXT-CS). Standard: DE'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--translation-json',
|
||||
@@ -942,6 +1060,18 @@ if __name__ == '__main__':
|
||||
# Lade Ignore-Muster aus Konfigurationsdatei
|
||||
wildcard_patterns, regex_patterns = load_ignore_patterns(cfg_dir)
|
||||
|
||||
# Lade Symbol-Attribut-Mapping
|
||||
symbol_attr_mapping = load_symbol_attribute_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'
|
||||
|
||||
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}")
|
||||
|
||||
# Optional: Lade Übersetzungs-Config
|
||||
translation_dicts = None
|
||||
if args.translate:
|
||||
@@ -1004,7 +1134,8 @@ if __name__ == '__main__':
|
||||
print(f"Ziel-DXF: {output_dxf}")
|
||||
|
||||
# Übersetze DXF
|
||||
translate_dxf_texts(source_dxf, output_dxf, translations, wildcard_patterns, regex_patterns)
|
||||
translate_dxf_texts(source_dxf, output_dxf, translations, wildcard_patterns, regex_patterns,
|
||||
source_attr_name, target_attr_name)
|
||||
|
||||
print("\nVerarbeitung erfolgreich abgeschlossen.")
|
||||
sys.exit(0)
|
||||
@@ -1031,7 +1162,7 @@ if __name__ == '__main__':
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Lese DXF Datei: {filename}")
|
||||
all_texts = extract_text_from_dxf(filename)
|
||||
all_texts = extract_text_from_dxf(filename, source_attr_name)
|
||||
|
||||
elif args.fromtxt:
|
||||
# TXT-Modus
|
||||
|
||||
Reference in New Issue
Block a user