Layer Funktion eingebaut. Block Attribute werden einmal vor den INSERTS reingeschrieben, damit alle dieses verwenden können
This commit is contained in:
+181
-21
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user