Files
dxfmakros/Lisp/ssg_lang.lsp
T

149 lines
5.6 KiB
Common Lisp

;; ============================================================
;; 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)