refactoring von translate.py. Config lesen in eine Methode gepackt. Multilang-json Struktur in eigene Methode
This commit is contained in:
+268
-218
@@ -380,20 +380,16 @@ def load_transfer_terms(translation_lang: str, translation_dir: Path) -> set[str
|
|||||||
return transfer
|
return transfer
|
||||||
|
|
||||||
|
|
||||||
def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
|
def _load_translator_config(cfg_path: Path) -> RawConfigParser:
|
||||||
"""
|
"""
|
||||||
Liest die Zuordnung von Sprachcodes zu Symbol-Attributnamen aus der translator.cfg Datei.
|
Lädt translator.cfg aus cfg_path und gibt einen RawConfigParser zurück.
|
||||||
|
Bricht mit Fehlermeldung ab wenn die Datei nicht existiert oder nicht gelesen werden kann.
|
||||||
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)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dictionary mit Sprachcode -> Attributname Mapping (z.B. "DE" -> "TEXT-D", "EN" -> "TEXT-EN")
|
Gelesener RawConfigParser (case-sensitive Keys)
|
||||||
"""
|
"""
|
||||||
config_file = cfg_path / "translator.cfg"
|
config_file = cfg_path / "translator.cfg"
|
||||||
|
|
||||||
@@ -410,6 +406,26 @@ 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)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary mit Sprachcode -> Attributname Mapping (z.B. "DE" -> "TEXT-D", "EN" -> "TEXT-EN")
|
||||||
|
"""
|
||||||
|
config = _load_translator_config(cfg_path)
|
||||||
|
|
||||||
symbol_mapping: dict[str, str] = {}
|
symbol_mapping: dict[str, str] = {}
|
||||||
|
|
||||||
# Lade Symbol-Attribut-Zuordnung
|
# Lade Symbol-Attribut-Zuordnung
|
||||||
@@ -441,20 +457,7 @@ def load_symbol_layer_mapping(cfg_path: Path) -> dict[str, str]:
|
|||||||
Returns:
|
Returns:
|
||||||
Dictionary mit Sprachcode -> Layername Mapping
|
Dictionary mit Sprachcode -> Layername Mapping
|
||||||
"""
|
"""
|
||||||
config_file = cfg_path / "translator.cfg"
|
config = _load_translator_config(cfg_path)
|
||||||
|
|
||||||
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] = {}
|
layer_mapping: dict[str, str] = {}
|
||||||
|
|
||||||
@@ -482,22 +485,8 @@ def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
|
|||||||
Returns:
|
Returns:
|
||||||
Tuple mit (Wildcard-Mustern, Regex-Mustern)
|
Tuple mit (Wildcard-Mustern, Regex-Mustern)
|
||||||
"""
|
"""
|
||||||
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
|
# RawConfigParser verhindert dass Backslashes in Regex-Mustern escaped werden
|
||||||
config = RawConfigParser()
|
config = _load_translator_config(cfg_path)
|
||||||
# Ü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)
|
|
||||||
|
|
||||||
wildcard_patterns = []
|
wildcard_patterns = []
|
||||||
regex_patterns = []
|
regex_patterns = []
|
||||||
@@ -703,12 +692,6 @@ def extract_text_from_dxf(filename: Path, text_attr_name: str = 'TEXT-D') -> lis
|
|||||||
# Prüfe ob Block alle erforderlichen Attribute hat
|
# Prüfe ob Block alle erforderlichen Attribute hat
|
||||||
if required_attributes.issubset(block_attributes) and text_d_value:
|
if required_attributes.issubset(block_attributes) and text_d_value:
|
||||||
block_count += 1
|
block_count += 1
|
||||||
|
|
||||||
# Ignoriere leere Texte
|
|
||||||
if not text_d_value:
|
|
||||||
empty_count += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
texts_set.add(text_d_value)
|
texts_set.add(text_d_value)
|
||||||
|
|
||||||
# Konvertiere Set zu sortierter Liste
|
# Konvertiere Set zu sortierter Liste
|
||||||
@@ -1216,6 +1199,50 @@ def translate_block_attribute(entity,
|
|||||||
return 1, 0, 0, 0
|
return 1, 0, 0, 0
|
||||||
|
|
||||||
|
|
||||||
|
def _translate_text_entities(msp, entity_type: str,
|
||||||
|
translations: dict[str, str],
|
||||||
|
wildcard_patterns: list[str],
|
||||||
|
regex_patterns: list[str]) -> tuple[int, int, int]:
|
||||||
|
"""
|
||||||
|
Übersetzt alle TEXT oder MTEXT Entitäten im Modelraum in-place.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msp: ezdxf Modelspace-Objekt
|
||||||
|
entity_type: "TEXT" oder "MTEXT"
|
||||||
|
translations: Dictionary mit source -> target Mappings
|
||||||
|
wildcard_patterns: Wildcard-Muster zum Filtern
|
||||||
|
regex_patterns: Regex-Muster zum Filtern
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple (translated, skipped, ignored)
|
||||||
|
"""
|
||||||
|
translated = 0
|
||||||
|
skipped = 0
|
||||||
|
ignored = 0
|
||||||
|
|
||||||
|
for entity in msp.query(entity_type):
|
||||||
|
raw_text = entity.dxf.text if entity_type == 'TEXT' else entity.text
|
||||||
|
if not raw_text:
|
||||||
|
continue
|
||||||
|
|
||||||
|
original_text = raw_text.strip()
|
||||||
|
|
||||||
|
if should_ignore_text(original_text, wildcard_patterns, regex_patterns):
|
||||||
|
ignored += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if original_text in translations:
|
||||||
|
if entity_type == 'TEXT':
|
||||||
|
entity.dxf.text = translations[original_text]
|
||||||
|
else:
|
||||||
|
entity.text = translations[original_text]
|
||||||
|
translated += 1
|
||||||
|
else:
|
||||||
|
skipped += 1
|
||||||
|
|
||||||
|
return translated, skipped, ignored
|
||||||
|
|
||||||
|
|
||||||
def translate_dxf_texts(input_dxf: Path,
|
def translate_dxf_texts(input_dxf: Path,
|
||||||
output_dxf: Path,
|
output_dxf: Path,
|
||||||
translations: dict[str, str],
|
translations: dict[str, str],
|
||||||
@@ -1251,51 +1278,16 @@ def translate_dxf_texts(input_dxf: Path,
|
|||||||
doc = ezdxf.readfile(input_dxf)
|
doc = ezdxf.readfile(input_dxf)
|
||||||
msp = doc.modelspace()
|
msp = doc.modelspace()
|
||||||
|
|
||||||
text_translated = 0
|
text_translated, text_skipped, text_ignored = _translate_text_entities(
|
||||||
text_skipped = 0
|
msp, 'TEXT', translations, wildcard_patterns, regex_patterns)
|
||||||
text_ignored = 0
|
mtext_translated, mtext_skipped, mtext_ignored = _translate_text_entities(
|
||||||
mtext_translated = 0
|
msp, 'MTEXT', translations, wildcard_patterns, regex_patterns)
|
||||||
mtext_skipped = 0
|
|
||||||
mtext_ignored = 0
|
|
||||||
block_translated = 0
|
block_translated = 0
|
||||||
block_skipped = 0
|
block_skipped = 0
|
||||||
block_ignored = 0
|
block_ignored = 0
|
||||||
block_transferred = 0
|
block_transferred = 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-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, transferred = translate_block_attribute(
|
translated, skipped, ignored, transferred = translate_block_attribute(
|
||||||
@@ -1382,6 +1374,78 @@ def write_texts_to_excel(texts: list[str], output_path: Path,
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def _load_existing_lang_blocks(output_path: Path, translation_languages: list[str]) -> dict:
|
||||||
|
"""
|
||||||
|
Lädt vorhandene Sprachblöcke aus einer bestehenden JSON-Datei für Merge-Unterstützung.
|
||||||
|
Gibt ein leeres Dict zurück wenn die Datei nicht existiert oder nicht gelesen werden kann.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output_path: Pfad zur bestehenden JSON-Datei
|
||||||
|
translation_languages: Sprachen die neu generiert werden (werden aus dem Merge ausgeschlossen)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict mit bestehenden Sprachblöcken die NICHT neu generiert werden
|
||||||
|
"""
|
||||||
|
if not output_path.exists():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(output_path, 'r', encoding='utf-8') as f:
|
||||||
|
existing = json.load(f)
|
||||||
|
if not isinstance(existing, dict):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
existing_lang_blocks = {
|
||||||
|
key: value for key, value in existing.items()
|
||||||
|
if key.startswith('[') and key.endswith(']') and len(key) > 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if existing_lang_blocks:
|
||||||
|
preserved = [k for k in existing_lang_blocks
|
||||||
|
if k not in {f"[{lang}]" for lang in translation_languages}]
|
||||||
|
if preserved:
|
||||||
|
print(f" Bestehende Sprachblöcke übernommen: {', '.join(preserved)}")
|
||||||
|
|
||||||
|
new_lang_keys = {f"[{lang}]" for lang in translation_languages}
|
||||||
|
return {key: value for key, value in existing_lang_blocks.items()
|
||||||
|
if key not in new_lang_keys}
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return {} # Fehler beim Laden → einfach neu schreiben
|
||||||
|
|
||||||
|
|
||||||
|
def _build_lang_block(
|
||||||
|
texts: list[str],
|
||||||
|
multi: dict[str, str],
|
||||||
|
trigramme: dict[str, str],
|
||||||
|
bigramme: dict[str, str],
|
||||||
|
single: dict[str, str]) -> dict:
|
||||||
|
"""
|
||||||
|
Übersetzt alle Texte für eine Sprache und baut den Sprach-Block für die JSON-Ausgabe.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
texts: Liste der zu übersetzenden Texte
|
||||||
|
multi: Multi-Phrasen-Dict
|
||||||
|
trigramme: Trigramme-Dict
|
||||||
|
bigramme: Bigramme-Dict
|
||||||
|
single: Einzelwörter-Dict
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict mit {"translations": [...], "untranslated": [...]}
|
||||||
|
"""
|
||||||
|
translations = []
|
||||||
|
untranslated = []
|
||||||
|
|
||||||
|
for text in texts:
|
||||||
|
translated = translate_text(text, multi, trigramme, bigramme, single)
|
||||||
|
if translated:
|
||||||
|
translations.append({"source": text, "target": translated})
|
||||||
|
else:
|
||||||
|
untranslated.append({"source": text, "target": ""})
|
||||||
|
|
||||||
|
return {"translations": translations, "untranslated": untranslated}
|
||||||
|
|
||||||
|
|
||||||
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], dict[str, str]] = None,
|
translation_dicts: tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]] = None,
|
||||||
translation_dicts_all: dict[str, tuple] = None,
|
translation_dicts_all: dict[str, tuple] = None,
|
||||||
@@ -1421,49 +1485,14 @@ def write_texts_to_json(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
if translation_dicts_all and translation_languages:
|
if translation_dicts_all and translation_languages:
|
||||||
|
|
||||||
# Lade bestehende Sprachblöcke aus vorhandener Datei (Merge-Unterstützung)
|
# Lade bestehende Sprachblöcke aus vorhandener Datei (Merge-Unterstützung)
|
||||||
existing_lang_blocks = {}
|
output_data.update(_load_existing_lang_blocks(output_path, translation_languages))
|
||||||
if output_path.exists():
|
|
||||||
try:
|
|
||||||
with open(output_path, 'r', encoding='utf-8') as f:
|
|
||||||
existing = json.load(f)
|
|
||||||
if isinstance(existing, dict):
|
|
||||||
for key, value in existing.items():
|
|
||||||
if key.startswith('[') and key.endswith(']') and len(key) > 2:
|
|
||||||
existing_lang_blocks[key] = value
|
|
||||||
if existing_lang_blocks:
|
|
||||||
preserved = [k for k in existing_lang_blocks
|
|
||||||
if k not in {f"[{lang}]" for lang in translation_languages}]
|
|
||||||
if preserved:
|
|
||||||
print(f" Bestehende Sprachblöcke übernommen: {', '.join(preserved)}")
|
|
||||||
except Exception:
|
|
||||||
pass # Fehler beim Laden → einfach neu schreiben
|
|
||||||
|
|
||||||
# Übernehme Sprachblöcke, die NICHT neu generiert werden
|
|
||||||
new_lang_keys = {f"[{lang}]" for lang in translation_languages}
|
|
||||||
for key, value in existing_lang_blocks.items():
|
|
||||||
if key not in new_lang_keys:
|
|
||||||
output_data[key] = value
|
|
||||||
|
|
||||||
# Generiere neue/aktualisierte Sprachblöcke
|
# Generiere neue/aktualisierte Sprachblöcke
|
||||||
for lang in translation_languages:
|
for lang in translation_languages:
|
||||||
if lang not in translation_dicts_all:
|
if lang not in translation_dicts_all:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
||||||
translations = []
|
output_data[f"[{lang}]"] = _build_lang_block(texts, multi, trigramme, bigramme, single)
|
||||||
untranslated = []
|
|
||||||
|
|
||||||
for text in texts:
|
|
||||||
translated = translate_text(text, multi, trigramme, bigramme, single)
|
|
||||||
if translated:
|
|
||||||
translations.append({"source": text, "target": translated})
|
|
||||||
else:
|
|
||||||
untranslated.append({"source": text, "target": ""})
|
|
||||||
|
|
||||||
output_data[f"[{lang}]"] = {
|
|
||||||
"translations": translations,
|
|
||||||
"untranslated": untranslated
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ignorierte Texte am Ende (ohne Sprachzuordnung)
|
# Ignorierte Texte am Ende (ohne Sprachzuordnung)
|
||||||
output_data["ignored"] = ignored_texts
|
output_data["ignored"] = ignored_texts
|
||||||
@@ -1472,18 +1501,9 @@ def write_texts_to_json(texts: list[str], ignored_texts: list[str], output_path:
|
|||||||
else:
|
else:
|
||||||
if translation_dicts:
|
if translation_dicts:
|
||||||
multi, trigramme, bigramme, single = translation_dicts
|
multi, trigramme, bigramme, single = translation_dicts
|
||||||
translations = []
|
lang_block = _build_lang_block(texts, multi, trigramme, bigramme, single)
|
||||||
untranslated = []
|
output_data["translations"] = lang_block["translations"]
|
||||||
|
output_data["untranslated"] = lang_block["untranslated"]
|
||||||
for text in texts:
|
|
||||||
translated = translate_text(text, multi, trigramme, bigramme, single)
|
|
||||||
if translated:
|
|
||||||
translations.append({"source": text, "target": translated})
|
|
||||||
else:
|
|
||||||
untranslated.append({"source": text, "target": ""})
|
|
||||||
|
|
||||||
output_data["translations"] = translations
|
|
||||||
output_data["untranslated"] = untranslated
|
|
||||||
else:
|
else:
|
||||||
# Ohne Übersetzungs-Config: alle akzeptierten Texte sind nicht übersetzt
|
# Ohne Übersetzungs-Config: alle akzeptierten Texte sind nicht übersetzt
|
||||||
output_data["translations"] = []
|
output_data["translations"] = []
|
||||||
@@ -1586,7 +1606,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, multi, trigramme, bigramme, single))
|
translations_count = len(translations)
|
||||||
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}")
|
||||||
@@ -1731,6 +1751,119 @@ def _retranslate_language_block(
|
|||||||
return updated, unchanged, newly
|
return updated, unchanged, newly
|
||||||
|
|
||||||
|
|
||||||
|
def _retranslate_legacy(data: dict,
|
||||||
|
translation_languages: list[str],
|
||||||
|
translation_dicts_all: dict[str, tuple]) -> dict:
|
||||||
|
"""
|
||||||
|
Verarbeitet eine Legacy-Flat-JSON-Struktur und konvertiert sie ins Multilang-Format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: Geladene JSON-Daten (flache Struktur mit 'translations'/'untranslated')
|
||||||
|
translation_languages: Sprachen in der Reihenfolge der Verarbeitung
|
||||||
|
translation_dicts_all: Dict mit {LANG: (multi, trigramme, bigramme, single), ...}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Konvertierte Daten im Multilang-Format
|
||||||
|
"""
|
||||||
|
if 'translations' not in data or not isinstance(data['translations'], list):
|
||||||
|
print(f"FEHLER: JSON-Datei enthält keinen gültigen 'translations' Block")
|
||||||
|
sys.exit(1)
|
||||||
|
if not translation_languages or translation_languages[0] not in translation_dicts_all:
|
||||||
|
print(f"FEHLER: Keine Übersetzungs-Config für Re-Übersetzung verfügbar")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if 'untranslated' not in data:
|
||||||
|
data['untranslated'] = []
|
||||||
|
|
||||||
|
lang = translation_languages[0]
|
||||||
|
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
||||||
|
|
||||||
|
updated, unchanged, newly = _retranslate_language_block(
|
||||||
|
data['translations'], data['untranslated'],
|
||||||
|
multi, trigramme, bigramme, single,
|
||||||
|
f"[{lang}]"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\nRe-Übersetzung abgeschlossen (alte Struktur → wird zu multilang konvertiert, Sprache: {lang}):")
|
||||||
|
print(f" Aktualisiert (translations): {updated}")
|
||||||
|
print(f" Unverändert: {unchanged}")
|
||||||
|
if newly:
|
||||||
|
print(f" Neu aus 'untranslated' übersetzt/verschoben: {newly}")
|
||||||
|
|
||||||
|
# Legacy → Multilang konvertieren: flache Struktur in [LANG]-Block einpacken
|
||||||
|
return {
|
||||||
|
f"[{lang}]": {
|
||||||
|
"translations": data['translations'],
|
||||||
|
"untranslated": data['untranslated'],
|
||||||
|
},
|
||||||
|
"ignored": data.get('ignored', []),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _retranslate_multilang(data: dict,
|
||||||
|
existing_languages: list[str],
|
||||||
|
translation_languages: list[str],
|
||||||
|
translation_dicts_all: dict[str, tuple]) -> None:
|
||||||
|
"""
|
||||||
|
Verarbeitet eine Multilang-JSON-Struktur in-place.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: Geladene JSON-Daten (hierarchische Multilang-Struktur, wird in-place verändert)
|
||||||
|
existing_languages: Sprachen die bereits in der Datei vorhanden sind
|
||||||
|
translation_languages: Sprachen in der Reihenfolge der Verarbeitung
|
||||||
|
translation_dicts_all: Dict mit {LANG: (multi, trigramme, bigramme, single), ...}
|
||||||
|
"""
|
||||||
|
print(f"Erkannte mehrsprachige Struktur mit Sprachen: {', '.join(existing_languages)}")
|
||||||
|
|
||||||
|
total_updated = 0
|
||||||
|
total_unchanged = 0
|
||||||
|
total_newly = 0
|
||||||
|
new_block_count = 0
|
||||||
|
|
||||||
|
for lang in translation_languages:
|
||||||
|
lang_key = f"[{lang}]"
|
||||||
|
if lang_key not in data:
|
||||||
|
print(f" Erstelle neuen Sprach-Block: [{lang}]")
|
||||||
|
data[lang_key] = {"translations": [], "untranslated": []}
|
||||||
|
new_block_count += 1
|
||||||
|
|
||||||
|
lang_data = data[lang_key]
|
||||||
|
if not isinstance(lang_data, dict):
|
||||||
|
print(f"WARNUNG: [{lang}] Block ist kein Object, überspringe")
|
||||||
|
continue
|
||||||
|
if 'translations' not in lang_data:
|
||||||
|
lang_data['translations'] = []
|
||||||
|
if 'untranslated' not in lang_data:
|
||||||
|
lang_data['untranslated'] = []
|
||||||
|
if not isinstance(lang_data['translations'], list):
|
||||||
|
print(f"WARNUNG: [{lang}][translations] ist kein Array, überspringe")
|
||||||
|
continue
|
||||||
|
if lang not in translation_dicts_all:
|
||||||
|
print(f"WARNUNG: Keine Übersetzungs-Config für [{lang}] verfügbar, überspringe")
|
||||||
|
continue
|
||||||
|
|
||||||
|
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
||||||
|
updated, unchanged, newly = _retranslate_language_block(
|
||||||
|
lang_data['translations'], lang_data['untranslated'],
|
||||||
|
multi, trigramme, bigramme, single,
|
||||||
|
f"[{lang}]"
|
||||||
|
)
|
||||||
|
total_updated += updated + newly
|
||||||
|
total_unchanged += unchanged
|
||||||
|
total_newly += newly
|
||||||
|
|
||||||
|
print(f" [{lang}] Aktualisiert: {updated}, Unverändert: {unchanged}", end="")
|
||||||
|
if newly:
|
||||||
|
print(f", Neu aus 'untranslated': {newly}", end="")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print(f"\nRe-Übersetzung abgeschlossen (mehrsprachige Struktur):")
|
||||||
|
print(f" Gesamt aktualisiert: {total_updated}")
|
||||||
|
print(f" Gesamt unverändert: {total_unchanged}")
|
||||||
|
if new_block_count:
|
||||||
|
print(f" Neue Sprach-Blöcke erstellt: {new_block_count}")
|
||||||
|
|
||||||
|
|
||||||
def retranslate_json_file(json_path: Path,
|
def retranslate_json_file(json_path: Path,
|
||||||
translation_dicts_all: dict[str, tuple],
|
translation_dicts_all: dict[str, tuple],
|
||||||
translation_languages: list[str]):
|
translation_languages: list[str]):
|
||||||
@@ -1759,93 +1892,10 @@ def retranslate_json_file(json_path: Path,
|
|||||||
|
|
||||||
structure_type, existing_languages = detect_json_structure(data)
|
structure_type, existing_languages = detect_json_structure(data)
|
||||||
|
|
||||||
total_updated = 0
|
|
||||||
total_unchanged = 0
|
|
||||||
total_newly = 0
|
|
||||||
new_block_count = 0
|
|
||||||
|
|
||||||
if structure_type == "legacy":
|
if structure_type == "legacy":
|
||||||
if 'translations' not in data or not isinstance(data['translations'], list):
|
data = _retranslate_legacy(data, translation_languages, translation_dicts_all)
|
||||||
print(f"FEHLER: JSON-Datei enthält keinen gültigen 'translations' Block")
|
|
||||||
sys.exit(1)
|
|
||||||
if not translation_languages or translation_languages[0] not in translation_dicts_all:
|
|
||||||
print(f"FEHLER: Keine Übersetzungs-Config für Re-Übersetzung verfügbar")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if 'untranslated' not in data:
|
|
||||||
data['untranslated'] = []
|
|
||||||
|
|
||||||
lang = translation_languages[0]
|
|
||||||
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
|
||||||
|
|
||||||
updated, unchanged, newly = _retranslate_language_block(
|
|
||||||
data['translations'], data['untranslated'],
|
|
||||||
multi, trigramme, bigramme, single,
|
|
||||||
f"[{lang}]"
|
|
||||||
)
|
|
||||||
total_updated, total_unchanged, total_newly = updated, unchanged, newly
|
|
||||||
|
|
||||||
print(f"\nRe-Übersetzung abgeschlossen (alte Struktur → wird zu multilang konvertiert, Sprache: {lang}):")
|
|
||||||
print(f" Aktualisiert (translations): {updated}")
|
|
||||||
print(f" Unverändert: {unchanged}")
|
|
||||||
if newly:
|
|
||||||
print(f" Neu aus 'untranslated' übersetzt/verschoben: {newly}")
|
|
||||||
|
|
||||||
# Legacy → Multilang konvertieren: flache Struktur in [LANG]-Block einpacken
|
|
||||||
data = {
|
|
||||||
f"[{lang}]": {
|
|
||||||
"translations": data['translations'],
|
|
||||||
"untranslated": data['untranslated'],
|
|
||||||
},
|
|
||||||
"ignored": data.get('ignored', []),
|
|
||||||
}
|
|
||||||
|
|
||||||
elif structure_type == "multilang":
|
elif structure_type == "multilang":
|
||||||
print(f"Erkannte mehrsprachige Struktur mit Sprachen: {', '.join(existing_languages)}")
|
_retranslate_multilang(data, existing_languages, translation_languages, translation_dicts_all)
|
||||||
|
|
||||||
for lang in translation_languages:
|
|
||||||
lang_key = f"[{lang}]"
|
|
||||||
if lang_key not in data:
|
|
||||||
print(f" Erstelle neuen Sprach-Block: [{lang}]")
|
|
||||||
data[lang_key] = {"translations": [], "untranslated": []}
|
|
||||||
new_block_count += 1
|
|
||||||
|
|
||||||
lang_data = data[lang_key]
|
|
||||||
if not isinstance(lang_data, dict):
|
|
||||||
print(f"WARNUNG: [{lang}] Block ist kein Object, überspringe")
|
|
||||||
continue
|
|
||||||
if 'translations' not in lang_data:
|
|
||||||
lang_data['translations'] = []
|
|
||||||
if 'untranslated' not in lang_data:
|
|
||||||
lang_data['untranslated'] = []
|
|
||||||
if not isinstance(lang_data['translations'], list):
|
|
||||||
print(f"WARNUNG: [{lang}][translations] ist kein Array, überspringe")
|
|
||||||
continue
|
|
||||||
if lang not in translation_dicts_all:
|
|
||||||
print(f"WARNUNG: Keine Übersetzungs-Config für [{lang}] verfügbar, überspringe")
|
|
||||||
continue
|
|
||||||
|
|
||||||
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
|
||||||
updated, unchanged, newly = _retranslate_language_block(
|
|
||||||
lang_data['translations'], lang_data['untranslated'],
|
|
||||||
multi, trigramme, bigramme, single,
|
|
||||||
f"[{lang}]"
|
|
||||||
)
|
|
||||||
total_updated += updated + newly
|
|
||||||
total_unchanged += unchanged
|
|
||||||
total_newly += newly
|
|
||||||
|
|
||||||
print(f" [{lang}] Aktualisiert: {updated}, Unverändert: {unchanged}", end="")
|
|
||||||
if newly:
|
|
||||||
print(f", Neu aus 'untranslated': {newly}", end="")
|
|
||||||
print()
|
|
||||||
|
|
||||||
print(f"\nRe-Übersetzung abgeschlossen (mehrsprachige Struktur):")
|
|
||||||
print(f" Gesamt aktualisiert: {total_updated}")
|
|
||||||
print(f" Gesamt unverändert: {total_unchanged}")
|
|
||||||
if new_block_count:
|
|
||||||
print(f" Neue Sprach-Blöcke erstellt: {new_block_count}")
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f"FEHLER: JSON-Datei hat unbekannte Struktur")
|
print(f"FEHLER: JSON-Datei hat unbekannte Struktur")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user