Layer Funktion eingebaut. Block Attribute werden einmal vor den INSERTS reingeschrieben, damit alle dieses verwenden können

This commit is contained in:
2025-12-04 15:08:10 +01:00
parent 8af0d35f25
commit a6f813dd25
+181 -21
View File
@@ -111,6 +111,11 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
"""
Liest die Zuordnung von Sprachcodes zu Symbol-Attributnamen aus der translator.cfg Datei.
Verwendet den Abschnitt [symbol_attribute], z.B.:
DE = TEXT-D
EN = TEXT-E
CS = TEXT-CS
Args:
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
@@ -124,9 +129,7 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
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')
@@ -134,12 +137,12 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
print(f"Fehler beim Lesen der Konfigurationsdatei: {e}")
sys.exit(1)
symbol_mapping = {}
symbol_mapping: dict[str, str] = {}
# Lade Symbol-Attribut-Zuordnung
if config.has_section('symbolattribute'):
for key in config['symbolattribute']:
attr_name = config['symbolattribute'][key].strip()
if config.has_section('symbol_attribute'):
for key in config['symbol_attribute']:
attr_name = config['symbol_attribute'][key].strip()
if attr_name and not attr_name.startswith('#'):
symbol_mapping[key] = attr_name
@@ -150,6 +153,51 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
return symbol_mapping
def load_symbol_layer_mapping(cfg_path: Path) -> dict[str, str]:
"""
Liest die Zuordnung von Sprachcodes zu Symbol-Layern aus der translator.cfg Datei.
Verwendet den Abschnitt [symbol_layer], z.B.:
DE = 0-0_TEXT-D
EN = 0-0_TEXT-E
CS = 0-0_TEXT-CS
Args:
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
Returns:
Dictionary mit Sprachcode -> Layername Mapping
"""
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)
config = RawConfigParser()
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)
layer_mapping: dict[str, str] = {}
if config.has_section('symbol_layer'):
for key in config['symbol_layer']:
layer_name = config['symbol_layer'][key].strip()
if layer_name and not layer_name.startswith('#'):
layer_mapping[key] = layer_name
print(f"\nGeladene Symbol-Layer-Zuordnungen: {len(layer_mapping)}")
for lang, layer in layer_mapping.items():
print(f" {lang} -> {layer}")
return layer_mapping
def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
"""
Liest die ignore_pattern aus der translator.cfg Datei.
@@ -587,20 +635,98 @@ def load_translations_from_json(filename: Path) -> dict[str, str]:
sys.exit(1)
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]:
def ensure_block_attdef_and_layer(doc, block_name: str,
text_source_attr: str,
text_target_attr: str,
target_layer: str | None = None) -> None:
"""
Stellt sicher, dass im Block-Definitionseintrag ein ATTDEF für das Ziel-Attribut
existiert und der passende Layer vorhanden ist.
- Wenn der Layer aus translator.cfg ([symbol_layer]) noch nicht existiert, wird er angelegt.
- Wenn das ATTDEF für text_target_attr noch nicht existiert, wird es auf Basis des
ATTDEF von text_source_attr erzeugt (Position, Höhe, Stil, Rotation werden übernommen).
"""
if doc is None or not block_name:
return
try:
block = doc.blocks[block_name]
except KeyError:
# Kein Block mit diesem Namen vorhanden (z.B. anonyme Blöcke) -> nichts zu tun
return
# Layer sicherstellen
if target_layer:
if target_layer not in doc.layers:
doc.layers.new(name=target_layer)
source_def = None
target_def = None
for attdef in block.attdefs():
tag = attdef.dxf.tag
if tag == text_target_attr:
target_def = attdef
elif tag == text_source_attr:
source_def = attdef
# Ziel-ATTDEF existiert bereits -> ggf. nur Layer korrigieren
if target_def is not None:
if target_layer:
target_def.dxf.layer = target_layer
return
# Neues ATTDEF anlegen, möglichst anhand der Quell-Definition
insert = (0.0, 0.0)
height = 2.5
layer_name = target_layer or "0"
if source_def is not None:
insert = source_def.dxf.insert
if source_def.dxf.hasattr('height'):
height = source_def.dxf.height
if source_def.dxf.hasattr('layer') and not target_layer:
layer_name = source_def.dxf.layer
# `add_attdef` unterstützt keinen `layer`-Parameter direkt, daher Layer danach setzen
new_def = block.add_attdef(
tag=text_target_attr,
insert=insert,
height=height,
)
new_def.dxf.layer = layer_name
# Weitere Eigenschaften (Rotation, Stil) vom Quell-ATTDEF übernehmen
if source_def is not None:
if source_def.dxf.hasattr('rotation'):
new_def.dxf.rotation = source_def.dxf.rotation
if source_def.dxf.hasattr('style'):
new_def.dxf.style = source_def.dxf.style
def translate_block_attribute(entity,
doc,
translations: dict[str, str],
wildcard_patterns: list[str],
regex_patterns: list[str],
required_attributes: set[str],
text_source_attr: str,
text_target_attr: str,
target_layer: str | None = None) -> tuple[int, int, int]:
"""
Übersetzt Text-Attribute eines einzelnen Block-Inserts (INSERT entity).
Args:
entity: INSERT entity aus der DXF-Datei
doc: ezdxf-Dokument, um Blockdefinitionen und Layer zu ändern
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")
target_layer: Ziel-Layername für das Ziel-Attribut (aus [symbol_layer])
Returns:
Tuple mit (translated_count, skipped_count, ignored_count) für diesen Block
@@ -641,13 +767,18 @@ def translate_block_attribute(entity, translations: dict[str, str],
if text_target_attrib:
# Ziel-Attribut existiert bereits, aktualisiere es
text_target_attrib.dxf.text = translations[original_text]
# Layer ggf. anpassen
if target_layer:
text_target_attrib.dxf.layer = target_layer
else:
# Vor dem Anlegen sicherstellen, dass im Block ein passender ATTDEF existiert
ensure_block_attdef_and_layer(doc, entity.dxf.name, text_source_attr, text_target_attr, target_layer)
# 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
insert=text_source_attrib.dxf.insert,
)
# Kopiere weitere Eigenschaften
if text_source_attrib.dxf.hasattr('height'):
@@ -658,15 +789,23 @@ def translate_block_attribute(entity, translations: dict[str, str],
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'):
# Layer explizit auf Ziel-Layer setzen, falls konfiguriert, sonst wie Quell-Attribut
if target_layer:
new_attrib.dxf.layer = target_layer
elif 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'):
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',
target_layer: str | None = None):
"""
Übersetzt alle TEXT, MTEXT Objekte und Text-Attribute in Blöcken einer DXF-Datei.
@@ -738,8 +877,15 @@ def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[st
# Übersetze Text-Attribute in Blöcken
for entity in msp.query('INSERT'):
translated, skipped, ignored = translate_block_attribute(
entity, translations, wildcard_patterns, regex_patterns,
required_attributes, text_source_attr, text_target_attr
entity,
doc,
translations,
wildcard_patterns,
regex_patterns,
required_attributes,
text_source_attr,
text_target_attr,
target_layer,
)
block_translated += translated
block_skipped += skipped
@@ -1060,17 +1206,23 @@ if __name__ == '__main__':
# Lade Ignore-Muster aus Konfigurationsdatei
wildcard_patterns, regex_patterns = load_ignore_patterns(cfg_dir)
# Lade Symbol-Attribut-Mapping
# Lade Symbol-Attribut- und Layer-Mapping
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'
# Bestimme Ziel-Layer für Blockattribute (nur relevant bei --todxf)
target_layer_name = symbol_layer_mapping.get(args.translate) if args.translate 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}")
# Optional: Lade Übersetzungs-Config
translation_dicts = None
@@ -1133,9 +1285,17 @@ if __name__ == '__main__':
print(f"Ziel-DXF: {output_dxf}")
# Übersetze DXF
translate_dxf_texts(source_dxf, output_dxf, translations, wildcard_patterns, regex_patterns,
source_attr_name, target_attr_name)
# Übersetze DXF (inkl. ggf. neuer TEXT-Attribute und Layer)
translate_dxf_texts(
source_dxf,
output_dxf,
translations,
wildcard_patterns,
regex_patterns,
source_attr_name,
target_attr_name,
target_layer_name,
)
print("\nVerarbeitung erfolgreich abgeschlossen.")
sys.exit(0)