149 lines
5.6 KiB
Common Lisp
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)
|