;; ============================================================ ;; SSG_LANG.LSP - Sprachumschaltung (Deutsch/Englisch) ;; Zentrale Textverwaltung fuer benutzersichtbare Meldungen. ;; Kern-Modul, wird direkt nach ssg_core geladen. ;; ;; Die Texte liegen extern in lang/de_DE.json und lang/en_GB.json. ;; Diese Datei ist reiner Lade-/Zugriffscode. Beim Laden wird ;; *ssg-texts* aus den JSON-Dateien befuellt - Format wie bisher: ;; (key (cons "de_DE" wert) (cons "en_GB" wert)) ;; Die JSON-Dateien werden aus Lisp/ssg_lang.lsp einmalig per ;; tools/migrate_lang_to_json.py erzeugt und danach direkt gepflegt. ;; ============================================================ ;; ------------------------------------------------------------ ;; Alle Vorkommen von alt in str durch neu ersetzen. ;; Frueh definiert, da ssg-lang-unescape es beim Laden braucht. ;; ------------------------------------------------------------ (defun ssg-str-replace-all (neu alt str / pos ergebnis) (setq ergebnis "") (while (setq pos (vl-string-search alt str)) (setq ergebnis (strcat ergebnis (substr str 1 pos) neu)) (setq str (substr str (+ pos 1 (strlen alt)))) ) (strcat ergebnis str) ) ;; ------------------------------------------------------------ ;; Sprachordner ermitteln: 1) DXFMAKRO env, 2) *ssg-lisp-pfad*, 3) nil. ;; Gleiches Fallback-Muster wie in Gefaellestrecke.lsp/KreiselInsert.lsp. ;; DXFM_LANG bleibt der Sprachcode und wird hier NICHT als Pfad genutzt. ;; ------------------------------------------------------------ (defun ssg-lang-dir ( / ) (cond ((and (getenv "DXFMAKRO") (= (type (getenv "DXFMAKRO")) 'STR) (> (strlen (getenv "DXFMAKRO")) 0)) (strcat (vl-string-right-trim "/" (vl-string-translate "\\" "/" (getenv "DXFMAKRO"))) "/lang")) ((and (boundp '*ssg-lisp-pfad*) (= (type *ssg-lisp-pfad*) 'STR) (vl-string-search "/Lisp" *ssg-lisp-pfad*)) (strcat (substr *ssg-lisp-pfad* 1 (vl-string-search "/Lisp" *ssg-lisp-pfad*)) "/lang")) (t nil) ) ) ;; ------------------------------------------------------------ ;; Escapes aus einem JSON-Rohwert aufloesen: \n -> Zeilenumbruch. ;; Der JSON-Parser (ssg-cfg-parse-nested) liefert \n als literale ;; 2-Zeichen-Folge (Backslash + n) zurueck; hier wird sie in einen ;; echten Zeilenumbruch gewandelt. Suchmuster ist "\\n" (= die zwei ;; Zeichen Backslash+n); "\n" waere bereits ein Zeilenumbruch. ;; Andere Escapes kommen in den Sprachdateien nicht vor. ;; ------------------------------------------------------------ (defun ssg-lang-unescape (wert) (if wert (ssg-str-replace-all (chr 10) "\\n" wert) ) ) ;; ------------------------------------------------------------ ;; Beide Sprachdateien laden und *ssg-texts* im bisherigen Format ;; befuellen: (key (cons "de_DE" ...) (cons "en_GB" ...)). ;; Fehlt eine Datei oder ein Key, bleibt der jeweilige Wert nil - ;; die Fallback-Kette in ssg-text greift dann automatisch ;; (en_GB -> de_DE -> Key). BricsCAD startet in jedem Fall. ;; ------------------------------------------------------------ (defun ssg-lang-load ( / dir de-datei en-datei de-sec en-sec key wert-de wert-en ergebnis) (setq *ssg-texts* nil) (setq dir (ssg-lang-dir)) (if (null dir) (princ "\n[LANG] WARNUNG: Sprachordner nicht ermittelbar (DXFMAKRO nicht gesetzt).") (progn (setq de-datei (strcat dir "/de_DE.json") en-datei (strcat dir "/en_GB.json")) (if (findfile de-datei) (setq de-sec (cdr (assoc "texts" (ssg-cfg-parse-nested (ssg-read-file-lines de-datei))))) (princ (strcat "\n[LANG] WARNUNG: " de-datei " nicht gefunden.")) ) (if (findfile en-datei) (setq en-sec (cdr (assoc "texts" (ssg-cfg-parse-nested (ssg-read-file-lines en-datei))))) (princ (strcat "\n[LANG] WARNUNG: " en-datei " nicht gefunden.")) ) (foreach paar de-sec (setq key (car paar) wert-de (ssg-lang-unescape (cdr paar)) wert-en (ssg-lang-unescape (cdr (assoc key en-sec)))) (setq ergebnis (cons (list key (cons "de_DE" wert-de) (cons "en_GB" wert-en)) ergebnis)) ) (setq *ssg-texts* (reverse ergebnis)) (princ (strcat "\n[LANG] " (itoa (length *ssg-texts*)) " Texte geladen.")) ) ) (princ) ) ;; ------------------------------------------------------------ ;; AKTUELLE SPRACHE ;; Default de_DE, Init aus DXFM_LANG. Ein erneutes Laden dieses ;; Moduls ueberschreibt eine zur Laufzeit gesetzte Sprache nicht. ;; ------------------------------------------------------------ (if (null *ssg-lang*) (setq *ssg-lang* (getenv "DXFM_LANG")) ) (if (or (null *ssg-lang*) (= *ssg-lang* "")) (setq *ssg-lang* "de_DE") ) ;; Texttabelle aus den JSON-Sprachdateien befuellen (ssg-lang-load) ;; ------------------------------------------------------------ ;; ssg-text - Text zu einem Key in der aktuellen Sprache liefern ;; Fallback-Kette: *ssg-lang* -> de_DE -> Key selbst ;; ------------------------------------------------------------ (defun ssg-text (key / eintrag wert) (setq eintrag (assoc key *ssg-texts*)) (if eintrag (progn (setq wert (cdr (assoc *ssg-lang* (cdr eintrag)))) (if (null wert) (setq wert (cdr (assoc "de_DE" (cdr eintrag)))) ) (if (null wert) key wert) ) key ) ) ;; ssg-textf - Text mit Platzhaltern %1 %2 ... aus einer Werteliste fuellen (defun ssg-textf (key werte / txt i platzhalter) (setq txt (ssg-text key)) (setq i 1) (foreach w werte (setq platzhalter (strcat "%" (itoa i))) (setq txt (ssg-str-replace-all (vl-princ-to-string w) platzhalter txt)) (setq i (1+ i)) ) txt ) (princ)