dev.metalisp.sbt/src/main.lisp

122 lines
6.3 KiB
Common Lisp
Raw Normal View History

2023-06-29 17:19:12 +02:00
(defpackage cl-sbt
2023-07-01 16:30:10 +02:00
(:use :cl)
(:export
2023-08-25 15:10:01 +02:00
:write-html-to-file
:with-page
2023-09-13 21:23:19 +02:00
:l10n
:find-l10n))
2023-07-01 16:30:10 +02:00
2023-06-29 17:19:12 +02:00
(in-package :cl-sbt)
2023-07-03 14:43:58 +02:00
2023-07-22 13:58:46 +02:00
(setq spinneret:*fill-column* 120)
(defparameter *cdn-css* "https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css")
(defparameter *cdn-js* "https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js")
2023-09-22 14:44:25 +02:00
(defun dictp (lst)
(loop for entry in lst always
(and (listp entry)
(= (length entry) 2)
(stringp (first entry))
2023-09-22 15:45:33 +02:00
(every #'stringp (second entry)))))
2023-09-22 14:44:25 +02:00
(deftype dict ()
'(and list (satisfies dictp)))
2023-09-22 15:45:33 +02:00
(declaim (type dict *l10n*))
2023-09-22 16:03:14 +02:00
(defparameter *l10n*
2023-09-22 15:45:33 +02:00
'(("submit" ("en" "Submit" "de" "Absenden" "fr" "Soumettre"))
("cancel" ("en" "Cancel" "de" "Abbrechen" "fr" "Annuler"))
("upload" ("en" "Upload" "de" "Hochladen" "fr" "Télécharger"))
("search" ("en" "Search" "de" "Suchen" "fr" "Rechercher"))
2023-09-22 18:08:44 +02:00
("option-selected" ("en" "Open this selected menu" "de" "Das ausgewählte Menü öffnen" "fr" "Ouvrir le menu sélectionné"))
2023-09-22 15:45:33 +02:00
("sign-up" ("en" "Sign Up" "de" "Registrieren" "fr" "Inscrivez-vous"))
("sign-in" ("en" "Sign In" "de" "Anmelden" "fr" "S'identifier"))
("next" ("en" "Next" "de" "Weiter" "fr" "Suivant"))
("previous" ("en" "Previous" "de" "Zurück" "fr" "Précédent"))
("settings" ("en" "Settings" "de" "Einstellungen" "fr" "Paramètres"))
("logout" ("en" "Logout" "de" "Abmelden" "fr" "Déconnexion"))
("profile" ("en" "Profile" "de" "Profil" "fr" "Profil"))
("save" ("en" "Save" "de" "Speichern" "fr" "Enregistrer"))
("delete" ("en" "Delete" "de" "Löschen" "fr" "Supprimer"))
("edit" ("en" "Edit" "de" "Bearbeiten" "fr" "Modifier"))
("confirm" ("en" "Confirm" "de" "Bestätigen" "fr" "Confirmer"))
("loading" ("en" "Loading..." "de" "Lädt..." "fr" "Chargement..."))
("error" ("en" "Error" "de" "Fehler" "fr" "Erreur"))
("success" ("en" "Success" "de" "Erfolg" "fr" "Succès"))
("close" ("en" "Close" "de" "Schließen" "fr" "Fermer"))
("help" ("en" "Help" "de" "Hilfe" "fr" "Aide"))
("home" ("en" "Home" "de" "Startseite" "fr" "Accueil"))
("welcome" ("en" "Welcome" "de" "Willkommen" "fr" "Bienvenue"))
("faq" ("en" "FAQ" "de" "Häufig gestellte Fragen" "fr" "FAQ"))
("contact" ("en" "Contact" "de" "Kontakt" "fr" "Contact"))
("privacy" ("en" "Privacy" "de" "Datenschutz" "fr" "Confidentialité"))
("terms" ("en" "Terms and Conditions" "de" "Allgemeine Geschäftsbedingungen" "fr" "Conditions Générales"))
("about" ("en" "About Us" "de" "Über uns" "fr" "À propos de nous"))
("add-to-cart" ("en" "Add to Cart" "de" "In den Warenkorb" "fr" "Ajouter au panier"))
("checkout" ("en" "Checkout" "de" "Kasse" "fr" "Passer à la caisse"))
("forgot-password" ("en" "Forgot Password?" "de" "Passwort vergessen?" "fr" "Mot de passe oublié ?"))
("username" ("en" "Username" "de" "Benutzername" "fr" "Nom d'utilisateur"))
("password" ("en" "Password" "de" "Passwort" "fr" "Mot de passe"))
("email" ("en" "Email" "de" "E-Mail" "fr" "Courrier électronique"))
("language" ("en" "Language" "de" "Sprache" "fr" "Langue"))
("read-more" ("en" "Read More" "de" "Weiterlesen" "fr" "En savoir plus"))
("show-less" ("en" "Show Less" "de" "Weniger anzeigen" "fr" "Montrer moins"))
("update" ("en" "Update" "de" "Aktualisieren" "fr" "Mettre à jour"))
("new" ("en" "New" "de" "Neu" "fr" "Nouveau"))
("old" ("en" "Old" "de" "Alt" "fr" "Ancien"))
("view-all" ("en" "View All" "de" "Alle anzeigen" "fr" "Voir tout"))
("cart" ("en" "Cart" "de" "Warenkorb" "fr" "Panier"))
("favorites" ("en" "Favorites" "de" "Favoriten" "fr" "Favoris"))
("share" ("en" "Share" "de" "Teilen" "fr" "Partager"))
("download" ("en" "Download" "de" "Herunterladen" "fr" "Télécharger"))
("print" ("en" "Print" "de" "Drucken" "fr" "Imprimer"))
("back" ("en" "Back" "de" "Zurück" "fr" "Retour"))
("create-account" ("en" "Create Account" "de" "Konto erstellen" "fr" "Créer un compte"))
2023-09-22 17:55:29 +02:00
("learn-more" ("en" "Learn More" "de" "Mehr erfahren" "fr" "En savoir plus"))
("filters" ("en" "Filters" "de" "Filter" "fr" "Filtres"))
("sort-by" ("en" "Sort By" "de" "Sortieren nach" "fr" "Trier par"))
("view-details" ("en" "View Details" "de" "Details anzeigen" "fr" "Voir les détails"))
("apply" ("en" "Apply" "de" "Anwenden" "fr" "Appliquer"))
("reset" ("en" "Reset" "de" "Zurücksetzen" "fr" "Réinitialiser"))
("continue" ("en" "Continue" "de" "Fortfahren" "fr" "Continuer"))
("subscribe" ("en" "Subscribe" "de" "Abonnieren" "fr" "S'abonner"))
("unsubscribe" ("en" "Unsubscribe" "de" "Abbestellen" "fr" "Se désabonner"))
("see-more" ("en" "See More" "de" "Mehr sehen" "fr" "Voir plus"))
("see-less" ("en" "See Less" "de" "Weniger sehen" "fr" "Voir moins")))
2023-09-13 21:23:19 +02:00
"Localization (l10n) settings for multi-language support.")
2023-09-22 15:20:19 +02:00
(declaim (ftype (function (string string dict) string) find-l10n))
2023-09-22 14:44:25 +02:00
(defun find-l10n (key lang dict)
2023-09-13 21:49:19 +02:00
"Finds the localized string for a given key and language."
2023-09-22 14:44:25 +02:00
(let ((entry (cadr (assoc key dict :test #'string=))))
2023-09-13 21:49:19 +02:00
(if entry
(let ((term (cadr (member lang entry :test #'string=))))
(or term "Translation not found"))
"Key not found")))
2023-09-13 21:33:19 +02:00
2023-08-25 22:01:55 +02:00
(defmacro with-page ((&key (author "") (description "") (cdn t) (pagetitle "") (theme "dark")) &body body)
2023-07-16 13:57:42 +02:00
`(spinneret:with-html
(:doctype)
2023-08-25 22:01:55 +02:00
(:html :data-bs-theme ,theme
2023-07-16 13:57:42 +02:00
(:head
(:meta :charset "utf-8")
(:meta :name "viewport" :content "width=device-width, initial-scale=1")
2023-08-09 14:12:34 +02:00
(:meta :name "author" :content ,author)
(:meta :name "description" :content ,description)
(:title ,pagetitle)
(if ,cdn
(:link :type "text/css" :rel "stylesheet" :href ,*cdn-css*)
(:link :type "text/css" :rel "stylesheet" :href "5.3.0/bootstrap.min.css")))
2023-08-25 22:01:55 +02:00
(:body (:h1 :class "visually-hidden" ,pagetitle)
2023-08-25 11:09:35 +02:00
(:main ,@body))
(if ,cdn
(:script :src *cdn-js*)
(:script :src "5.3.0/bootstrap.bundle.min.js")))))
2023-07-16 13:57:42 +02:00
2023-08-25 15:10:01 +02:00
(defun write-html-to-file (filename string &key (lang "en") (style :tree) (fc 120))
(let ((spinneret:*html-lang* lang)
(spinneret:*html-style* style)
(spinneret:*fill-column* fc))
(with-open-file (stream filename :direction :output :if-exists :supersede)
(write-string string stream))))