Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| be1864c4d8 | |||
| 6b7eaa43df | |||
| a916151e63 | |||
| e29a5d1534 |
+2
-19
@@ -28,7 +28,6 @@ mkdir "%TARGET_DIR%"
|
|||||||
|
|
||||||
REM Prüfe Dateityp und wähle entsprechenden Workflow
|
REM Prüfe Dateityp und wähle entsprechenden Workflow
|
||||||
if /I "%EXT%"==".json" goto retranslate_json
|
if /I "%EXT%"==".json" goto retranslate_json
|
||||||
if /I "%EXT%"==".txt" goto retranslate_txt
|
|
||||||
if /I "%EXT%"==".dxf" goto translate_dxf
|
if /I "%EXT%"==".dxf" goto translate_dxf
|
||||||
if /I "%EXT%"==".dwg" goto translate_dxf
|
if /I "%EXT%"==".dwg" goto translate_dxf
|
||||||
goto invalid_filetype
|
goto invalid_filetype
|
||||||
@@ -65,36 +64,20 @@ echo === JSON file updated: %INPUT_FILE% ===
|
|||||||
pause
|
pause
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|
||||||
:retranslate_txt
|
|
||||||
echo.
|
|
||||||
echo === Re-translating TXT file with current %LANG%.cfg ===
|
|
||||||
call translate.bat --retranslate-txt "%INPUT_FILE%" --translate %LANG%
|
|
||||||
if errorlevel 1 (
|
|
||||||
@echo == failed: re-translating TXT
|
|
||||||
pause
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
echo.
|
|
||||||
echo === TXT file updated: %INPUT_FILE% ===
|
|
||||||
pause
|
|
||||||
goto :eof
|
|
||||||
|
|
||||||
:invalid_filetype
|
:invalid_filetype
|
||||||
@echo FEHLER: Ungültiger Dateityp: %EXT%
|
@echo FEHLER: Ungültiger Dateityp: %EXT%
|
||||||
@echo Erlaubt sind: .dxf, .dwg, .json, .txt
|
@echo Erlaubt sind: .dxf, .dwg, .json
|
||||||
pause
|
pause
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|
||||||
:usage
|
:usage
|
||||||
@echo Usage: %0 ^<LANG^> ^<file.dxf^|file.json^|file.txt^>
|
@echo Usage: %0 ^<LANG^> ^<file.dxf^|file.json^>
|
||||||
@echo LANG: Zielsprache (CS, EN, FR, IT, ES)
|
@echo LANG: Zielsprache (CS, EN, FR, IT, ES)
|
||||||
@echo - .dxf/.dwg: Extrahiert und übersetzt Texte zur angegebenen Sprache
|
@echo - .dxf/.dwg: Extrahiert und übersetzt Texte zur angegebenen Sprache
|
||||||
@echo - .json: Re-übersetzt vorhandene Übersetzungen mit aktueller LANG.cfg
|
@echo - .json: Re-übersetzt vorhandene Übersetzungen mit aktueller LANG.cfg
|
||||||
@echo - .txt: Re-übersetzt TXT-Datei (translations/untranslated) mit aktueller LANG.cfg
|
|
||||||
@echo.
|
@echo.
|
||||||
@echo Beispiele:
|
@echo Beispiele:
|
||||||
@echo %0 CS myfile.dxf
|
@echo %0 CS myfile.dxf
|
||||||
@echo %0 EN translations.json
|
@echo %0 EN translations.json
|
||||||
@echo %0 CS translations_texts.txt
|
|
||||||
exit /B 1
|
exit /B 1
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ KR_code = KR-M*
|
|||||||
#h1875ff = ^\\H1.875x;.*$
|
#h1875ff = ^\\H1.875x;.*$
|
||||||
#millimeter = ^\d+\s*mm$
|
#millimeter = ^\d+\s*mm$
|
||||||
#m_numbers = ^M\d{3}$
|
#m_numbers = ^M\d{3}$
|
||||||
ET200_UC =\+UC\d{4}\\P.*3 x ET200 SP DI16 \d{3}\.\d - \d{3}\.\d
|
|
||||||
MTEXT_UZ =\\H1\.875x.*\+UZ\d{4}
|
|
||||||
|
|
||||||
# Koordinaten mit Pfeilen
|
# Koordinaten mit Pfeilen
|
||||||
coord_arrows = ^\+\d{1,3}(?:[.,]\d{3})\s*(?:<<<|>>>)\s*\+\d{1,3}(?:[.,]\d{3})$
|
coord_arrows = ^\+\d{1,3}(?:[.,]\d{3})\s*(?:<<<|>>>)\s*\+\d{1,3}(?:[.,]\d{3})$
|
||||||
@@ -107,7 +105,6 @@ EN = TEXT-E
|
|||||||
ES = TEXT-ES
|
ES = TEXT-ES
|
||||||
FR = TEXT-F
|
FR = TEXT-F
|
||||||
CS = TEXT-CS
|
CS = TEXT-CS
|
||||||
IT = TEXT-IT
|
|
||||||
|
|
||||||
[symbol_layer]
|
[symbol_layer]
|
||||||
DE = 0-0_TEXT-D
|
DE = 0-0_TEXT-D
|
||||||
@@ -115,4 +112,3 @@ EN = 0-0_TEXT-E
|
|||||||
ES = 0-0_TEXT-ES
|
ES = 0-0_TEXT-ES
|
||||||
FR = 0-0_TEXT-F
|
FR = 0-0_TEXT-F
|
||||||
CS = 0-0_TEXT-CS
|
CS = 0-0_TEXT-CS
|
||||||
IT = 0-0_TEXT-IT
|
|
||||||
+251
-504
@@ -32,10 +32,9 @@ SCHRITT 1 – Texte aus DXF extrahieren und Roh-JSON erzeugen
|
|||||||
Optional: zusätzliche Ausgabe als Excel oder Text (-t excel,json,text).
|
Optional: zusätzliche Ausgabe als Excel oder Text (-t excel,json,text).
|
||||||
|
|
||||||
───────────────────────────────────────────────────────────────────────────────
|
───────────────────────────────────────────────────────────────────────────────
|
||||||
SCHRITT 2a – JSON/TXT auto-übersetzen (Drop auf tr2dxf_CS.bat / tr2dxf_EN.bat)
|
SCHRITT 2a – JSON auto-übersetzen (Drop auf tr2dxf_CS.bat / tr2dxf_EN.bat)
|
||||||
───────────────────────────────────────────────────────────────────────────────
|
───────────────────────────────────────────────────────────────────────────────
|
||||||
--retranslate-json myfile_texts.json --translate CS[,EN,...]
|
--retranslate-json myfile_texts.json --translate CS[,EN,...]
|
||||||
--retranslate-txt myfile_texts.txt --translate CS
|
|
||||||
|
|
||||||
Liest eine bestehende JSON-Datei (Legacy-Flat oder Multilang), übersetzt
|
Liest eine bestehende JSON-Datei (Legacy-Flat oder Multilang), übersetzt
|
||||||
alle Texte aus 'untranslated' automatisch und verschiebt Treffer nach
|
alle Texte aus 'untranslated' automatisch und verschiebt Treffer nach
|
||||||
@@ -278,9 +277,8 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
|||||||
# Prüfe auf führende Leerzeichen vor dem Parsen (würden Zeilen zusammenziehen)
|
# Prüfe auf führende Leerzeichen vor dem Parsen (würden Zeilen zusammenziehen)
|
||||||
_check_leading_spaces(config_file, translation_lang)
|
_check_leading_spaces(config_file, translation_lang)
|
||||||
|
|
||||||
# RawConfigParser mit case-sensitive Keys und Unterstützung für Einträge ohne Wert
|
# RawConfigParser mit case-sensitive Keys
|
||||||
# (allow_no_value=True damit der [transfer]-Abschnitt mit einzelnen Begriffen ohne '=' gelesen werden kann)
|
config = RawConfigParser()
|
||||||
config = RawConfigParser(allow_no_value=True)
|
|
||||||
# Überschreibe optionxform um Groß-/Kleinschreibung zu erhalten
|
# Überschreibe optionxform um Groß-/Kleinschreibung zu erhalten
|
||||||
config.optionxform = str
|
config.optionxform = str
|
||||||
try:
|
try:
|
||||||
@@ -294,31 +292,37 @@ def load_translation_config(translation_lang: str, translation_dir: Path) -> tup
|
|||||||
bigramme = {}
|
bigramme = {}
|
||||||
single = {}
|
single = {}
|
||||||
|
|
||||||
def _load_section(section_name: str) -> dict[str, str]:
|
|
||||||
"""Lädt eine Übersetzungssektion und warnt bei Einträgen ohne '=' (value=None)."""
|
|
||||||
result = {}
|
|
||||||
if not config.has_section(section_name):
|
|
||||||
return result
|
|
||||||
for key in config[section_name]:
|
|
||||||
translation = config[section_name][key]
|
|
||||||
if translation is None:
|
|
||||||
print(f" WARNUNG [{translation_lang}] [{section_name}]: Eintrag ohne '=' ignoriert: '{key}'")
|
|
||||||
continue
|
|
||||||
if translation and not translation.startswith('#'):
|
|
||||||
result[key] = translation
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Lade Multi (4+ Wörter)
|
# Lade Multi (4+ Wörter)
|
||||||
multi = _load_section('multi')
|
if config.has_section('multi'):
|
||||||
|
for key in config['multi']:
|
||||||
|
original = key
|
||||||
|
translation = config['multi'][key]
|
||||||
|
if translation and not translation.startswith('#'):
|
||||||
|
multi[original] = translation
|
||||||
|
|
||||||
# Lade Trigramme
|
# Lade Trigramme
|
||||||
trigramme = _load_section('trigramme')
|
if config.has_section('trigramme'):
|
||||||
|
for key in config['trigramme']:
|
||||||
|
original = key
|
||||||
|
translation = config['trigramme'][key]
|
||||||
|
if translation and not translation.startswith('#'):
|
||||||
|
trigramme[original] = translation
|
||||||
|
|
||||||
# Lade Bigramme
|
# Lade Bigramme
|
||||||
bigramme = _load_section('bigramme')
|
if config.has_section('bigramme'):
|
||||||
|
for key in config['bigramme']:
|
||||||
|
original = key
|
||||||
|
translation = config['bigramme'][key]
|
||||||
|
if translation and not translation.startswith('#'):
|
||||||
|
bigramme[original] = translation
|
||||||
|
|
||||||
# Lade Single
|
# Lade Single
|
||||||
single = _load_section('single')
|
if config.has_section('single'):
|
||||||
|
for key in config['single']:
|
||||||
|
original = key
|
||||||
|
translation = config['single'][key]
|
||||||
|
if translation and not translation.startswith('#'):
|
||||||
|
single[original] = translation
|
||||||
|
|
||||||
# Prüfe Selbstübersetzungen in jedem Block und entferne sie mit Warnung
|
# Prüfe Selbstübersetzungen in jedem Block und entferne sie mit Warnung
|
||||||
multi = _filter_self_translations('multi', multi)
|
multi = _filter_self_translations('multi', multi)
|
||||||
@@ -381,35 +385,6 @@ def load_transfer_terms(translation_lang: str, translation_dir: Path) -> set[str
|
|||||||
return transfer
|
return transfer
|
||||||
|
|
||||||
|
|
||||||
def _load_translator_config(cfg_path: Path) -> RawConfigParser:
|
|
||||||
"""
|
|
||||||
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.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Gelesener RawConfigParser (case-sensitive Keys)
|
|
||||||
"""
|
|
||||||
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)
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
|
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.
|
||||||
@@ -425,7 +400,20 @@ def load_symbol_attribute_mapping(cfg_path: Path) -> dict[str, str]:
|
|||||||
Returns:
|
Returns:
|
||||||
Dictionary mit Sprachcode -> Attributname Mapping (z.B. "DE" -> "TEXT-D", "EN" -> "TEXT-EN")
|
Dictionary mit Sprachcode -> Attributname Mapping (z.B. "DE" -> "TEXT-D", "EN" -> "TEXT-EN")
|
||||||
"""
|
"""
|
||||||
config = _load_translator_config(cfg_path)
|
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)
|
||||||
|
|
||||||
symbol_mapping: dict[str, str] = {}
|
symbol_mapping: dict[str, str] = {}
|
||||||
|
|
||||||
@@ -458,7 +446,20 @@ def load_symbol_layer_mapping(cfg_path: Path) -> dict[str, str]:
|
|||||||
Returns:
|
Returns:
|
||||||
Dictionary mit Sprachcode -> Layername Mapping
|
Dictionary mit Sprachcode -> Layername Mapping
|
||||||
"""
|
"""
|
||||||
config = _load_translator_config(cfg_path)
|
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] = {}
|
layer_mapping: dict[str, str] = {}
|
||||||
|
|
||||||
@@ -486,8 +487,22 @@ 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 = _load_translator_config(cfg_path)
|
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)
|
||||||
|
|
||||||
wildcard_patterns = []
|
wildcard_patterns = []
|
||||||
regex_patterns = []
|
regex_patterns = []
|
||||||
@@ -693,6 +708,12 @@ 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
|
||||||
@@ -1200,50 +1221,6 @@ 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],
|
||||||
@@ -1279,16 +1256,51 @@ 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, text_skipped, text_ignored = _translate_text_entities(
|
text_translated = 0
|
||||||
msp, 'TEXT', translations, wildcard_patterns, regex_patterns)
|
text_skipped = 0
|
||||||
mtext_translated, mtext_skipped, mtext_ignored = _translate_text_entities(
|
text_ignored = 0
|
||||||
msp, 'MTEXT', translations, wildcard_patterns, regex_patterns)
|
mtext_translated = 0
|
||||||
|
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(
|
||||||
@@ -1375,78 +1387,6 @@ 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,
|
||||||
@@ -1486,14 +1426,49 @@ 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)
|
||||||
output_data.update(_load_existing_lang_blocks(output_path, translation_languages))
|
existing_lang_blocks = {}
|
||||||
|
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]
|
||||||
output_data[f"[{lang}]"] = _build_lang_block(texts, multi, trigramme, bigramme, single)
|
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": ""})
|
||||||
|
|
||||||
|
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
|
||||||
@@ -1502,9 +1477,18 @@ 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
|
||||||
lang_block = _build_lang_block(texts, multi, trigramme, bigramme, single)
|
translations = []
|
||||||
output_data["translations"] = lang_block["translations"]
|
untranslated = []
|
||||||
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"] = []
|
||||||
@@ -1607,7 +1591,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 = len(translations)
|
translations_count = sum(1 for text in texts if translate_text(text, multi, trigramme, bigramme, single))
|
||||||
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}")
|
||||||
@@ -1752,119 +1736,6 @@ 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]):
|
||||||
@@ -1893,10 +1764,93 @@ 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":
|
||||||
data = _retranslate_legacy(data, translation_languages, translation_dicts_all)
|
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}]"
|
||||||
|
)
|
||||||
|
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":
|
||||||
_retranslate_multilang(data, existing_languages, translation_languages, translation_dicts_all)
|
print(f"Erkannte mehrsprachige Struktur mit Sprachen: {', '.join(existing_languages)}")
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -1938,201 +1892,6 @@ def resolve_input_file(name: str, work_dir: Path, label: str = "Datei") -> Path:
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def _parse_txt_sections(filename: Path) -> tuple[list[tuple[str, str]], list[str], list[str]]:
|
|
||||||
"""
|
|
||||||
Parst eine Textdatei im Format von write_texts_to_text.
|
|
||||||
|
|
||||||
Erkannte Abschnitte:
|
|
||||||
- "--- translations:" → Zeilen im Format "source -> target"
|
|
||||||
- "--- untranslated:" → einfache Texte (eine pro Zeile)
|
|
||||||
- "--- ignored:" → einfache Texte (eine pro Zeile)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
filename: Pfad zur Textdatei
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Tuple (translations, untranslated, ignored):
|
|
||||||
- translations: Liste von (source, target) Tupeln
|
|
||||||
- untranslated: Liste von source-Texten ohne Übersetzung
|
|
||||||
- ignored: Liste von ignorierten Texten
|
|
||||||
"""
|
|
||||||
translations: list[tuple[str, str]] = []
|
|
||||||
untranslated: list[str] = []
|
|
||||||
ignored: list[str] = []
|
|
||||||
current_section: str | None = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(filename, 'r', encoding='utf-8') as f:
|
|
||||||
for line in f:
|
|
||||||
stripped = line.rstrip('\n\r').strip()
|
|
||||||
|
|
||||||
if stripped.startswith('---'):
|
|
||||||
low = stripped.lower()
|
|
||||||
if 'translations' in low:
|
|
||||||
current_section = 'translations'
|
|
||||||
elif 'untranslated' in low:
|
|
||||||
current_section = 'untranslated'
|
|
||||||
elif 'ignored' in low:
|
|
||||||
current_section = 'ignored'
|
|
||||||
else:
|
|
||||||
current_section = None
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not stripped or current_section is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if current_section == 'translations':
|
|
||||||
if ' -> ' in stripped:
|
|
||||||
source, target = stripped.split(' -> ', 1)
|
|
||||||
translations.append((source, target))
|
|
||||||
else:
|
|
||||||
# Eintrag ohne Ziel → als untranslated behandeln
|
|
||||||
untranslated.append(stripped)
|
|
||||||
elif current_section == 'untranslated':
|
|
||||||
untranslated.append(stripped)
|
|
||||||
elif current_section == 'ignored':
|
|
||||||
ignored.append(stripped)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fehler beim Lesen der Textdatei: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return translations, untranslated, ignored
|
|
||||||
|
|
||||||
|
|
||||||
def retranslate_txt_file(txt_path: Path,
|
|
||||||
translation_dicts_all: dict[str, tuple],
|
|
||||||
translation_languages: list[str],
|
|
||||||
wildcard_patterns: list[str] | None = None,
|
|
||||||
regex_patterns: list[str] | None = None) -> None:
|
|
||||||
"""
|
|
||||||
Re-übersetzt eine Textdatei im Format von write_texts_to_text.
|
|
||||||
Überschreibt die ursprüngliche Datei mit aktualisierten Inhalten.
|
|
||||||
|
|
||||||
Verarbeitungsreihenfolge:
|
|
||||||
1. Bestehende translations werden mit aktueller Config neu übersetzt.
|
|
||||||
Texte für die keine Übersetzung mehr gefunden wird, wandern nach untranslated.
|
|
||||||
2. Einträge aus untranslated werden gegen die Ignore-Pattern geprüft:
|
|
||||||
- Treffer → ignored (neu erkannte Pattern seit dem letzten Extrakt)
|
|
||||||
- Kein Treffer → auto-übersetzen; Erfolg → translations, sonst bleibt in untranslated.
|
|
||||||
|
|
||||||
Arbeitet immer mit der ersten Sprache aus translation_languages.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txt_path: Pfad zur Textdatei (wird in-place überschrieben)
|
|
||||||
translation_dicts_all: Dict mit {LANG: (multi, trigramme, bigramme, single), ...}
|
|
||||||
translation_languages: Liste der Sprachen (nur die erste wird verwendet)
|
|
||||||
wildcard_patterns: Wildcard-Muster zum Filtern (aus translator.cfg)
|
|
||||||
regex_patterns: Regex-Muster zum Filtern (aus translator.cfg)
|
|
||||||
"""
|
|
||||||
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)
|
|
||||||
|
|
||||||
wildcard_patterns = wildcard_patterns or []
|
|
||||||
regex_patterns = regex_patterns or []
|
|
||||||
|
|
||||||
lang = translation_languages[0]
|
|
||||||
multi, trigramme, bigramme, single = translation_dicts_all[lang]
|
|
||||||
|
|
||||||
existing_translations, untranslated, ignored = _parse_txt_sections(txt_path)
|
|
||||||
|
|
||||||
print(f" Vorhandene Übersetzungen: {len(existing_translations)}")
|
|
||||||
print(f" Nicht übersetzt: {len(untranslated)}")
|
|
||||||
print(f" Ignoriert: {len(ignored)}")
|
|
||||||
|
|
||||||
new_translations: list[tuple[str, str]] = []
|
|
||||||
updated = 0
|
|
||||||
unchanged = 0
|
|
||||||
moved_to_untranslated: list[str] = []
|
|
||||||
|
|
||||||
# Schritt 1: Bestehende Übersetzungen neu übersetzen
|
|
||||||
for source, old_target in existing_translations:
|
|
||||||
new_target = translate_text(source, multi, trigramme, bigramme, single)
|
|
||||||
if new_target:
|
|
||||||
new_translations.append((source, new_target))
|
|
||||||
if new_target != old_target:
|
|
||||||
updated += 1
|
|
||||||
else:
|
|
||||||
unchanged += 1
|
|
||||||
else:
|
|
||||||
moved_to_untranslated.append(source)
|
|
||||||
print(f" WARNUNG: Übersetzung nicht mehr verfügbar für '{source}', "
|
|
||||||
f"verschoben zu 'untranslated'")
|
|
||||||
|
|
||||||
# Schritt 2: Untranslated Texte prüfen und auto-übersetzen
|
|
||||||
still_untranslated: list[str] = list(moved_to_untranslated)
|
|
||||||
newly = 0
|
|
||||||
newly_ignored = 0
|
|
||||||
for text in untranslated:
|
|
||||||
# Neu hinzugefügte Ignore-Pattern prüfen
|
|
||||||
if should_ignore_text(text, wildcard_patterns, regex_patterns):
|
|
||||||
ignored.append(text)
|
|
||||||
newly_ignored += 1
|
|
||||||
continue
|
|
||||||
new_target = translate_text(text, multi, trigramme, bigramme, single)
|
|
||||||
if new_target:
|
|
||||||
new_translations.append((text, new_target))
|
|
||||||
newly += 1
|
|
||||||
else:
|
|
||||||
still_untranslated.append(text)
|
|
||||||
|
|
||||||
# Ergebnis zurückschreiben
|
|
||||||
try:
|
|
||||||
with open(txt_path, 'w', encoding='utf-8') as f:
|
|
||||||
f.write("--- translations:\n\n")
|
|
||||||
for source, target in new_translations:
|
|
||||||
f.write(f"{source} -> {target}\n")
|
|
||||||
f.write("\n--- untranslated:\n\n")
|
|
||||||
for text in still_untranslated:
|
|
||||||
f.write(f"{text}\n")
|
|
||||||
f.write("\n--- ignored:\n\n")
|
|
||||||
for text in ignored:
|
|
||||||
f.write(f"{text}\n")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fehler beim Schreiben der Textdatei: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print(f"\nRe-Übersetzung abgeschlossen (Sprache: {lang}):")
|
|
||||||
print(f" Aktualisiert: {updated}")
|
|
||||||
print(f" Unverändert: {unchanged}")
|
|
||||||
if newly:
|
|
||||||
print(f" Neu übersetzt: {newly}")
|
|
||||||
if newly_ignored:
|
|
||||||
print(f" Neu ignoriert (Pattern): {newly_ignored}")
|
|
||||||
if moved_to_untranslated:
|
|
||||||
print(f" Zurück zu untranslated: {len(moved_to_untranslated)}")
|
|
||||||
print(f" Noch nicht übersetzt: {len(still_untranslated)}")
|
|
||||||
print(f"\nDatei aktualisiert: {txt_path}")
|
|
||||||
|
|
||||||
|
|
||||||
def _run_retranslate_txt(
|
|
||||||
args,
|
|
||||||
work_dir: Path,
|
|
||||||
translation_dicts_all: dict,
|
|
||||||
translation_languages: list,
|
|
||||||
wildcard_patterns: list,
|
|
||||||
regex_patterns: list) -> None:
|
|
||||||
"""Workflow: Re-Übersetzung einer bestehenden TXT-Datei (--retranslate-txt)."""
|
|
||||||
print("=== Re-Übersetzung TXT-Datei ===\n")
|
|
||||||
|
|
||||||
input_filename = args.retranslate_txt
|
|
||||||
if not input_filename.lower().endswith('.txt'):
|
|
||||||
print("Mit --retranslate-txt nur .txt Dateien erlaubt")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
txt_file = resolve_input_file(input_filename, work_dir, "TXT-Datei")
|
|
||||||
|
|
||||||
print(f"TXT-Datei: {txt_file}")
|
|
||||||
print(f"Sprache: {translation_languages[0]}")
|
|
||||||
|
|
||||||
retranslate_txt_file(txt_file, translation_dicts_all, translation_languages,
|
|
||||||
wildcard_patterns, regex_patterns)
|
|
||||||
|
|
||||||
print("\nVerarbeitung erfolgreich abgeschlossen.")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
def _build_arg_parser() -> argparse.ArgumentParser:
|
def _build_arg_parser() -> argparse.ArgumentParser:
|
||||||
"""Erstellt und konfiguriert den Argument-Parser für translate.py."""
|
"""Erstellt und konfiguriert den Argument-Parser für translate.py."""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@@ -2165,12 +1924,6 @@ def _build_arg_parser() -> argparse.ArgumentParser:
|
|||||||
metavar='FILE.json',
|
metavar='FILE.json',
|
||||||
help='Re-übersetzt translations Block in JSON-Datei mit aktueller Sprachkonfig (benötigt --translate)'
|
help='Re-übersetzt translations Block in JSON-Datei mit aktueller Sprachkonfig (benötigt --translate)'
|
||||||
)
|
)
|
||||||
input_group.add_argument(
|
|
||||||
'--retranslate-txt',
|
|
||||||
action='store',
|
|
||||||
metavar='FILE.txt',
|
|
||||||
help='Re-übersetzt translations/untranslated Blöcke in TXT-Datei mit aktueller Sprachkonfig (benötigt --translate)'
|
|
||||||
)
|
|
||||||
input_group.add_argument(
|
input_group.add_argument(
|
||||||
'--todxf',
|
'--todxf',
|
||||||
action='store',
|
action='store',
|
||||||
@@ -2410,8 +2163,6 @@ def main() -> None:
|
|||||||
parser.error("--fromjson benötigt --translate (Übersetzung ist erforderlich)")
|
parser.error("--fromjson benötigt --translate (Übersetzung ist erforderlich)")
|
||||||
if args.retranslate_json and not args.translate:
|
if args.retranslate_json and not args.translate:
|
||||||
parser.error("--retranslate-json benötigt --translate (Übersetzung ist erforderlich)")
|
parser.error("--retranslate-json benötigt --translate (Übersetzung ist erforderlich)")
|
||||||
if args.retranslate_txt and not args.translate:
|
|
||||||
parser.error("--retranslate-txt benötigt --translate (Übersetzung ist erforderlich)")
|
|
||||||
if args.todxf and not args.filename:
|
if args.todxf and not args.filename:
|
||||||
parser.error("--todxf benötigt --filename (Quell-DXF muss angegeben werden)")
|
parser.error("--todxf benötigt --filename (Quell-DXF muss angegeben werden)")
|
||||||
if args.translation_json and not args.todxf:
|
if args.translation_json and not args.todxf:
|
||||||
@@ -2466,10 +2217,6 @@ def main() -> None:
|
|||||||
if args.retranslate_json:
|
if args.retranslate_json:
|
||||||
_run_retranslate(args, work_dir, translation_dicts_all, translation_languages)
|
_run_retranslate(args, work_dir, translation_dicts_all, translation_languages)
|
||||||
|
|
||||||
if args.retranslate_txt:
|
|
||||||
_run_retranslate_txt(args, work_dir, translation_dicts_all, translation_languages,
|
|
||||||
wildcard_patterns, regex_patterns)
|
|
||||||
|
|
||||||
if args.todxf:
|
if args.todxf:
|
||||||
_run_todxf(args, work_dir, translation_languages, wildcard_patterns, regex_patterns,
|
_run_todxf(args, work_dir, translation_languages, wildcard_patterns, regex_patterns,
|
||||||
source_attr_name, target_attr_name, target_layer_name)
|
source_attr_name, target_attr_name, target_layer_name)
|
||||||
|
|||||||
+39
-30
@@ -18,11 +18,11 @@ from Storage level=ze skladovací úrovně
|
|||||||
GF GOH operational area, dispatch buffer=Provozní oblast GOH, expediční vyrovnávací paměť
|
GF GOH operational area, dispatch buffer=Provozní oblast GOH, expediční vyrovnávací paměť
|
||||||
IF BMZ=Rozhraní požární ústředna
|
IF BMZ=Rozhraní požární ústředna
|
||||||
IF BST=Rozhraní požární ústředna
|
IF BST=Rozhraní požární ústředna
|
||||||
fire alarm=požár indikace
|
fire alarm=požární alarm
|
||||||
FPC geöffnet=Požární dveře otevřeno
|
FPC geöffnet=Požární dveře otevřeno
|
||||||
Kein Feueralarm=Žádný požár alarm
|
Kein Feueralarm=Žádný požární alarm
|
||||||
Keine Störung=Žádné rušení
|
Keine Störung=Žádné rušení
|
||||||
No fire alarm=Rozhraní BST „Žádný požár alarm“
|
No fire alarm=Rozhraní BST „Žádný požární alarm“
|
||||||
Non fault=Rozhraní BST „Bez poruchy“
|
Non fault=Rozhraní BST „Bez poruchy“
|
||||||
IF fire-alarm-control-panel=Rozhraní požární poplachový panel
|
IF fire-alarm-control-panel=Rozhraní požární poplachový panel
|
||||||
Length of Trolley=Délka vozíku
|
Length of Trolley=Délka vozíku
|
||||||
@@ -59,11 +59,11 @@ IF RFID=Rozhraní RFID
|
|||||||
infiltrate with TEF=infiltrovat pomocí TEF
|
infiltrate with TEF=infiltrovat pomocí TEF
|
||||||
loaded Minitrolleys from=naloženými minivozíky z
|
loaded Minitrolleys from=naloženými minivozíky z
|
||||||
Loading Station for Hangsacks=Nakládací stanice pro závěsné pytle
|
Loading Station for Hangsacks=Nakládací stanice pro závěsné pytle
|
||||||
LS Endlage ausgefahren=NNS KP VY
|
LS Endlage ausgefahren=Nabíjecí smyčka Koncová poloha vysunutá
|
||||||
LS Endlage eingefahren=NS KP ZA
|
LS Endlage eingefahren=Nabíjecí smyčka koncová poloha zasunuta
|
||||||
MSS hat ausgelöst =Spustil se jistič motoru
|
MSS hat ausgelöst =Spustil se jistič motoru
|
||||||
Multi Purpose Station=multifunkční stanice
|
Multi Purpose Station=multifunkční stanice
|
||||||
No fire alarm=Žádný požár alarm
|
No fire alarm=Žádný požární alarm
|
||||||
Not Halt Schnittstelle CH1=Nouzové zastavení rozhraní CH1
|
Not Halt Schnittstelle CH1=Nouzové zastavení rozhraní CH1
|
||||||
Not Halt Schnittstelle CH2=Nouzové zastavení rozhraní CH2
|
Not Halt Schnittstelle CH2=Nouzové zastavení rozhraní CH2
|
||||||
Not Halt Schnittstelle von=Nouzová zastávka rozhraní od
|
Not Halt Schnittstelle von=Nouzová zastávka rozhraní od
|
||||||
@@ -76,7 +76,8 @@ Ready for use=Připraveno k použití
|
|||||||
Reset Bumper Safety relay =Reset Nárazník Bezpečnostní relé
|
Reset Bumper Safety relay =Reset Nárazník Bezpečnostní relé
|
||||||
SEW MOVIMOT OK LS=SEW MOVIMOT OK Nabíjecí smyčka
|
SEW MOVIMOT OK LS=SEW MOVIMOT OK Nabíjecí smyčka
|
||||||
Anfahrwarnung=Varování při rozjezdu
|
Anfahrwarnung=Varování při rozjezdu
|
||||||
Signalsäule Hupe=Signální sloupek Klakson
|
Signalsäule Hupe=Signální sloupek Klakson
|
||||||
|
Signalsäule Hupe=Signální sloupek Klakson
|
||||||
Signalsäule blau=Signální sloup modrý
|
Signalsäule blau=Signální sloup modrý
|
||||||
Signalsäule Blau=Signální sloup modrý
|
Signalsäule Blau=Signální sloup modrý
|
||||||
Fehlerhafter Mini-Trolley=Vadný mini vozík
|
Fehlerhafter Mini-Trolley=Vadný mini vozík
|
||||||
@@ -101,6 +102,15 @@ to operational area=do provozní oblasti
|
|||||||
to Storage level 1=do skladovací úrovně 1
|
to Storage level 1=do skladovací úrovně 1
|
||||||
to Storage level 2 Exit=na úroveň skladování 2 Exit
|
to Storage level 2 Exit=na úroveň skladování 2 Exit
|
||||||
Total power consumption=Celkový příkon
|
Total power consumption=Celkový příkon
|
||||||
|
<<<<<<< HEAD
|
||||||
|
Vorsicherung 24V OK=Předřadný jistič 24 V OK
|
||||||
|
Vorsicherung 24V OK =Přední pojistka 24 V OK
|
||||||
|
DT Anlage Aus=Tlačítko Vypnout zařízení
|
||||||
|
LDT Anlage Ein=Světelný tlačítko Zapnout zařízení
|
||||||
|
LM Brandfall=Světelná signalizace požáru
|
||||||
|
LM Druckluft fehlt=Kontrolka nedostatku stlačeného vzduchu
|
||||||
|
Empty Minitrolleys=Prázdné minivozíky
|
||||||
|
=======
|
||||||
Vorsicherung 24V OK=Předřadný jistič 24 V OK
|
Vorsicherung 24V OK=Předřadný jistič 24 V OK
|
||||||
DT Anlage Aus=T Vypnout zařízení
|
DT Anlage Aus=T Vypnout zařízení
|
||||||
LDT Anlage Ein=OT Zapnout zařízení
|
LDT Anlage Ein=OT Zapnout zařízení
|
||||||
@@ -108,6 +118,7 @@ LM Brandfall=SS požáru
|
|||||||
LM Druckluft fehlt=SS nedostatku stlačeného vzduchu
|
LM Druckluft fehlt=SS nedostatku stlačeného vzduchu
|
||||||
F2H Workstations
|
F2H Workstations
|
||||||
|
|
||||||
|
>>>>>>> 04d73b78c4578c7e6adb6f611123a9c55b30fadd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -125,32 +136,32 @@ Control cabinet=Rozvaděč
|
|||||||
Dispatch Buffer=Dispečerská vyrovnávací paměť
|
Dispatch Buffer=Dispečerská vyrovnávací paměť
|
||||||
Distance to =Vzdálenost k
|
Distance to =Vzdálenost k
|
||||||
Druckluft OK=Stlačený vzduch OK
|
Druckluft OK=Stlačený vzduch OK
|
||||||
DT Lampentest=TL Test lampy
|
DT Lampentest=DT Test lampy
|
||||||
Einfahrt Kreisel=Vjezd do kruhového objezdu
|
Einfahrt Kreisel=Vjezd do kruhového objezdu
|
||||||
Empty hanger=Prázdné věšáky
|
Empty hanger=Prázdné věšáky
|
||||||
Empty Minitrolleys=Prázdné minivozíky
|
Empty Minitrolleys=Prázdné minivozíky
|
||||||
empty Minitrolleys=prázdné minivozíky
|
empty Minitrolleys=prázdné minivozíky
|
||||||
empty Trolleys=prázdné vozíky
|
empty Trolleys=prázdné vozíky
|
||||||
E-stop Kanal =Kanál NZ
|
E-stop Kanal =Kanál E-stop
|
||||||
EU pallet=Paleta EU
|
EU pallet=Paleta EU
|
||||||
F2H Workstations=Pracovní stanice F2H
|
F2H Workstations=Pracovní stanice F2H
|
||||||
Flat packed=Ploché balení
|
Flat packed=Ploché balení
|
||||||
Förderer voll=Plný dopravník
|
Förderer voll=Plný dopravník
|
||||||
FPC opened=FPC otevřen
|
FPC opened=FPC otevřen
|
||||||
Freigabe MT=Uvolnění MT
|
Freigabe MT=Schválení MT
|
||||||
from UH=od UH
|
from UH=od UH
|
||||||
GoH pallet=Paleta GoH
|
GoH pallet=Paleta GoH
|
||||||
Ground Floor=Přízemí
|
Ground Floor=Přízemí
|
||||||
Hand scanner=Ruční skener
|
Hand scanner=Ruční skener
|
||||||
Hauptschütze aktivieren=Aktivace hlavního stykače
|
Hauptschütze aktivieren=Aktivace hlavního stykače
|
||||||
Ladeschleife aktivieren=Aktivovat nabíjecí smyčku
|
Ladebaum aktivieren=Aktivovat nabíjecí strom
|
||||||
Ladeschleife ausfahren =Vysunutí nabíjecí smyčku
|
Ladeschleife ausfahren =Vysunutí nabíjecí smyčky
|
||||||
Ladeschleife einfahren =Zatáhnout nabíjecí smyčku
|
Ladeschleife einfahren =Zatáhnout nabíjecí smyčku
|
||||||
LDT Reset=OT reset
|
LDT Reset=Světelný tlačítko reset
|
||||||
LDT system On=OT systém On
|
LDT system On=LT Spínač systém On
|
||||||
Lenght Measurement=Měření délky
|
Lenght Measurement=Měření délky
|
||||||
LM Störung=Kontrolka poruchy
|
LM Störung=Kontrolka poruchy
|
||||||
loaded Minitrolleys=naložený minivozíky
|
loaded Minitrolleys=naložený Minitrolleys
|
||||||
Loading Boom=Nakládací rameno
|
Loading Boom=Nakládací rameno
|
||||||
max. capacity=maximální kapacita
|
max. capacity=maximální kapacita
|
||||||
Mounting plate=Montážní deska
|
Mounting plate=Montážní deska
|
||||||
@@ -184,8 +195,8 @@ Sub-distributor=Rozvaděč rozvodné skříně
|
|||||||
# Format: Begriffe in der dxf=tschechisch
|
# Format: Begriffe in der dxf=tschechisch
|
||||||
L x D x H=D x Š x V
|
L x D x H=D x Š x V
|
||||||
area=oblast
|
area=oblast
|
||||||
Ausfahren=Výsunout
|
Ausfahren=Výsuv
|
||||||
ausgefahren=vysunoutý
|
ausgefahren=vyjetý
|
||||||
Beladeposition=Poloha nakládky
|
Beladeposition=Poloha nakládky
|
||||||
#Belastung=zatížení
|
#Belastung=zatížení
|
||||||
#Säule=sloup
|
#Säule=sloup
|
||||||
@@ -197,8 +208,8 @@ Bodenabstandssensor =Senzor vzdálenosti od podlahy
|
|||||||
Brandschutztor=Protipožární vrata
|
Brandschutztor=Protipožární vrata
|
||||||
Customer=Zákazník
|
Customer=Zákazník
|
||||||
Door=Dveře
|
Door=Dveře
|
||||||
Einfahren=zasunout
|
Einfahren=Zasunutí
|
||||||
eingefahren=zasunoutý
|
eingefahren=zasunutý
|
||||||
empty=prázdný
|
empty=prázdný
|
||||||
Freigabe=Uvolnění
|
Freigabe=Uvolnění
|
||||||
Freigeben=Uvolnit
|
Freigeben=Uvolnit
|
||||||
@@ -213,7 +224,6 @@ Horse=Kůň
|
|||||||
Hupe=Klakson
|
Hupe=Klakson
|
||||||
Inbound=Příchozí
|
Inbound=Příchozí
|
||||||
inbound=příchozí
|
inbound=příchozí
|
||||||
Kunde=Zákazník
|
|
||||||
Kreisel=Kruhový dopravník
|
Kreisel=Kruhový dopravník
|
||||||
Kriechgang=Pomalu
|
Kriechgang=Pomalu
|
||||||
Ladeschleife=Nabíjecí smyčka
|
Ladeschleife=Nabíjecí smyčka
|
||||||
@@ -235,33 +245,32 @@ Phasenausfall =Výpadek fáze
|
|||||||
Pickstation=Sběrná stanice
|
Pickstation=Sběrná stanice
|
||||||
Placeholder =Zástupný symbol
|
Placeholder =Zástupný symbol
|
||||||
Plastic=Plast
|
Plastic=Plast
|
||||||
Rad=kolo
|
|
||||||
Reading=Čtení
|
Reading=Čtení
|
||||||
Release=Uvolnění
|
Release=Vydání
|
||||||
Reserve=Rezerva
|
Reserve=Rezerva
|
||||||
Rot=Červená
|
Rot=Červená
|
||||||
rot=červená
|
rot=červená
|
||||||
Schaltschrank=Rozvaděč
|
Schaltschrank=Rozvaděč
|
||||||
Schlüsselschalter=klíčový spínač
|
Schlüsselschalter=Klíčový spínač
|
||||||
Schnitt =Řez
|
Schnitt =Řez
|
||||||
Screen=Obrazovka
|
Screen=Obrazovka
|
||||||
Signalsäule=Signální sloup
|
Signalsäule=Signální sloup
|
||||||
Stützfuß=Opěrná noha
|
Stützfuß=Opěrná noha
|
||||||
Table =Tabulka
|
Table =Tabulka
|
||||||
Tray=Zásobník
|
Tray=Zásobník
|
||||||
Unterverteiler=Elektrický rozvaděč
|
Unterverteiler=Rozvaděč
|
||||||
Waste=Odpad
|
Waste=Odpad
|
||||||
Weight=Hmotnost
|
Weight=Hmotnost
|
||||||
wheel=kolo
|
wheel=kolo
|
||||||
Workstation=Pracovní stanice
|
Workstation=Pracovní stanice
|
||||||
LEUCHTDRUCKTASTER=Osvětlené tlačítko
|
Lechtdrucktaster=Osvětlené tlačítko
|
||||||
LDT=OT
|
LDT=TS
|
||||||
DRUCKTASTER=Tlačítko
|
DRUCKTASTER=Tlačítko
|
||||||
DT=T
|
DT=TL
|
||||||
LEUCHTMELDER=Signální svítidlo
|
LEUCHTMELDER=Signální svítidlo
|
||||||
LM=SS
|
LM=SS
|
||||||
RESET=Reset
|
RESET=RESET
|
||||||
reset=reset
|
reset=reset
|
||||||
|
|
||||||
|
|
||||||
[transfer]
|
[transfer]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user