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.
|
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:
|
Args:
|
||||||
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
|
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}")
|
print(f"Bitte erstellen Sie die Datei 'translator.cfg' im Verzeichnis: {cfg_path}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# RawConfigParser verhindert dass Backslashes in Regex-Mustern escaped werden
|
|
||||||
config = RawConfigParser()
|
config = RawConfigParser()
|
||||||
# Überschreibe optionxform um Groß-/Kleinschreibung zu erhalten
|
|
||||||
config.optionxform = str
|
config.optionxform = str
|
||||||
try:
|
try:
|
||||||
config.read(config_file, encoding='utf-8')
|
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}")
|
print(f"Fehler beim Lesen der Konfigurationsdatei: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
symbol_mapping = {}
|
symbol_mapping: dict[str, str] = {}
|
||||||
|
|
||||||
# Lade Symbol-Attribut-Zuordnung
|
# Lade Symbol-Attribut-Zuordnung
|
||||||
if config.has_section('symbolattribute'):
|
if config.has_section('symbol_attribute'):
|
||||||
for key in config['symbolattribute']:
|
for key in config['symbol_attribute']:
|
||||||
attr_name = config['symbolattribute'][key].strip()
|
attr_name = config['symbol_attribute'][key].strip()
|
||||||
if attr_name and not attr_name.startswith('#'):
|
if attr_name and not attr_name.startswith('#'):
|
||||||
symbol_mapping[key] = attr_name
|
symbol_mapping[key] = attr_name
|
||||||
|
|
||||||
@@ -150,6 +153,51 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
|
|||||||
return symbol_mapping
|
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]]:
|
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.
|
||||||
@@ -587,20 +635,98 @@ def load_translations_from_json(filename: Path) -> dict[str, str]:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def translate_block_attribute(entity, translations: dict[str, str],
|
def ensure_block_attdef_and_layer(doc, block_name: str,
|
||||||
wildcard_patterns: list[str], regex_patterns: list[str],
|
text_source_attr: str,
|
||||||
required_attributes: set[str], text_source_attr: str, text_target_attr: str) -> tuple[int, int, int]:
|
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).
|
Übersetzt Text-Attribute eines einzelnen Block-Inserts (INSERT entity).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entity: INSERT entity aus der DXF-Datei
|
entity: INSERT entity aus der DXF-Datei
|
||||||
|
doc: ezdxf-Dokument, um Blockdefinitionen und Layer zu ändern
|
||||||
translations: Dictionary mit source -> target Mappings
|
translations: Dictionary mit source -> target Mappings
|
||||||
wildcard_patterns: Wildcard-Muster zum Filtern
|
wildcard_patterns: Wildcard-Muster zum Filtern
|
||||||
regex_patterns: Regex-Muster zum Filtern
|
regex_patterns: Regex-Muster zum Filtern
|
||||||
required_attributes: Set mit erforderlichen Attributnamen für den Block
|
required_attributes: Set mit erforderlichen Attributnamen für den Block
|
||||||
text_source_attr: Quell-Attributname (z.B. "TEXT-D", "TEXT-EN")
|
text_source_attr: Quell-Attributname (z.B. "TEXT-D", "TEXT-EN")
|
||||||
text_target_attr: Ziel-Attributname (z.B. "TEXT-EN", "TEXT-CS")
|
text_target_attr: Ziel-Attributname (z.B. "TEXT-EN", "TEXT-CS")
|
||||||
|
target_layer: Ziel-Layername für das Ziel-Attribut (aus [symbol_layer])
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple mit (translated_count, skipped_count, ignored_count) für diesen Block
|
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:
|
if text_target_attrib:
|
||||||
# Ziel-Attribut existiert bereits, aktualisiere es
|
# Ziel-Attribut existiert bereits, aktualisiere es
|
||||||
text_target_attrib.dxf.text = translations[original_text]
|
text_target_attrib.dxf.text = translations[original_text]
|
||||||
|
# Layer ggf. anpassen
|
||||||
|
if target_layer:
|
||||||
|
text_target_attrib.dxf.layer = target_layer
|
||||||
else:
|
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
|
# Ziel-Attribut existiert nicht, erstelle es basierend auf Quell-Attribut
|
||||||
# Kopiere alle Eigenschaften vom Quell-Attribut
|
|
||||||
new_attrib = entity.add_attrib(
|
new_attrib = entity.add_attrib(
|
||||||
tag=text_target_attr,
|
tag=text_target_attr,
|
||||||
text=translations[original_text],
|
text=translations[original_text],
|
||||||
insert=text_source_attrib.dxf.insert
|
insert=text_source_attrib.dxf.insert,
|
||||||
)
|
)
|
||||||
# Kopiere weitere Eigenschaften
|
# Kopiere weitere Eigenschaften
|
||||||
if text_source_attrib.dxf.hasattr('height'):
|
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
|
new_attrib.dxf.rotation = text_source_attrib.dxf.rotation
|
||||||
if text_source_attrib.dxf.hasattr('width'):
|
if text_source_attrib.dxf.hasattr('width'):
|
||||||
new_attrib.dxf.width = text_source_attrib.dxf.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
|
new_attrib.dxf.layer = text_source_attrib.dxf.layer
|
||||||
|
|
||||||
return 1, 0, 0
|
return 1, 0, 0
|
||||||
|
|
||||||
|
|
||||||
def translate_dxf_texts(input_dxf: Path, output_dxf: Path, translations: dict[str, str],
|
def translate_dxf_texts(input_dxf: Path,
|
||||||
wildcard_patterns: list[str], regex_patterns: list[str],
|
output_dxf: Path,
|
||||||
text_source_attr: str = 'TEXT-D', text_target_attr: str = 'TEXT-CS'):
|
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.
|
Ü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
|
# Übersetze Text-Attribute in Blöcken
|
||||||
for entity in msp.query('INSERT'):
|
for entity in msp.query('INSERT'):
|
||||||
translated, skipped, ignored = translate_block_attribute(
|
translated, skipped, ignored = translate_block_attribute(
|
||||||
entity, translations, wildcard_patterns, regex_patterns,
|
entity,
|
||||||
required_attributes, text_source_attr, text_target_attr
|
doc,
|
||||||
|
translations,
|
||||||
|
wildcard_patterns,
|
||||||
|
regex_patterns,
|
||||||
|
required_attributes,
|
||||||
|
text_source_attr,
|
||||||
|
text_target_attr,
|
||||||
|
target_layer,
|
||||||
)
|
)
|
||||||
block_translated += translated
|
block_translated += translated
|
||||||
block_skipped += skipped
|
block_skipped += skipped
|
||||||
@@ -1060,17 +1206,23 @@ 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)
|
||||||
|
|
||||||
# Lade Symbol-Attribut-Mapping
|
# Lade Symbol-Attribut- und Layer-Mapping
|
||||||
symbol_attr_mapping = load_symbol_attribute_mapping(cfg_dir)
|
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
|
# Bestimme Quell- und Ziel-Attributnamen basierend auf Sprachcodes
|
||||||
source_attr_name = symbol_attr_mapping.get(args.lang_source, 'TEXT-D')
|
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'
|
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"\nVerwendete Attribut-Namen:")
|
||||||
print(f" Quell-Attribut (--lang_source {args.lang_source}): {source_attr_name}")
|
print(f" Quell-Attribut (--lang_source {args.lang_source}): {source_attr_name}")
|
||||||
if args.translate:
|
if args.translate:
|
||||||
print(f" Ziel-Attribut (--translate {args.translate}): {target_attr_name}")
|
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
|
# Optional: Lade Übersetzungs-Config
|
||||||
translation_dicts = None
|
translation_dicts = None
|
||||||
@@ -1133,9 +1285,17 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
print(f"Ziel-DXF: {output_dxf}")
|
print(f"Ziel-DXF: {output_dxf}")
|
||||||
|
|
||||||
# Übersetze DXF
|
# Übersetze DXF (inkl. ggf. neuer TEXT-Attribute und Layer)
|
||||||
translate_dxf_texts(source_dxf, output_dxf, translations, wildcard_patterns, regex_patterns,
|
translate_dxf_texts(
|
||||||
source_attr_name, target_attr_name)
|
source_dxf,
|
||||||
|
output_dxf,
|
||||||
|
translations,
|
||||||
|
wildcard_patterns,
|
||||||
|
regex_patterns,
|
||||||
|
source_attr_name,
|
||||||
|
target_attr_name,
|
||||||
|
target_layer_name,
|
||||||
|
)
|
||||||
|
|
||||||
print("\nVerarbeitung erfolgreich abgeschlossen.")
|
print("\nVerarbeitung erfolgreich abgeschlossen.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user