From achiumenti at common-lisp.net Wed Mar 12 12:49:11 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Wed, 12 Mar 2008 07:49:11 -0500 (EST) Subject: [claw-cvs] r15 - trunk/main/claw-core/src Message-ID: <20080312124911.A711937014@common-lisp.net> Author: achiumenti Date: Wed Mar 12 07:49:10 2008 New Revision: 15 Modified: trunk/main/claw-core/src/tags.lisp Log: implemented message-dispatch for I18N-AWARE class Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Wed Mar 12 07:49:10 2008 @@ -1133,7 +1133,9 @@ (when dispatcher (progn (setf result (message-dispatch dispatcher key locale)) - (when (null result)))) + (when (and (null result) (> (length key) 2)) + (setf result (message-dispatch dispatcher (subseq key 0 2) locale))))) + result)) From achiumenti at common-lisp.net Wed Mar 12 10:26:41 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Wed, 12 Mar 2008 05:26:41 -0500 (EST) Subject: [claw-cvs] r14 - in trunk/main/claw-core: . src tests Message-ID: <20080312102641.8BBC117038@common-lisp.net> Author: achiumenti Date: Wed Mar 12 05:26:40 2008 New Revision: 14 Added: trunk/main/claw-core/src/validators.lisp Modified: trunk/main/claw-core/claw.asd trunk/main/claw-core/src/components.lisp trunk/main/claw-core/src/lisplet.lisp trunk/main/claw-core/src/misc.lisp trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/server.lisp trunk/main/claw-core/src/tags.lisp trunk/main/claw-core/tests/test1.lisp Log: beginning of translators and i18n support Modified: trunk/main/claw-core/claw.asd ============================================================================== --- trunk/main/claw-core/claw.asd (original) +++ trunk/main/claw-core/claw.asd Wed Mar 12 05:26:40 2008 @@ -37,6 +37,7 @@ (:file "misc" :depends-on ("packages")) (:file "hunchentoot-overrides" :depends-on ("packages")) (:file "tags" :depends-on ("misc")) - (:file "components" :depends-on ("tags")) - (:file "lisplet" :depends-on ("components")) + (:file "validators" :depends-on ("tags")) + (:file "components" :depends-on ("tags" "validators")) + (:file "lisplet" :depends-on ("components")) (:file "server" :depends-on ("lisplet")))))) Modified: trunk/main/claw-core/src/components.lisp ============================================================================== --- trunk/main/claw-core/src/components.lisp (original) +++ trunk/main/claw-core/src/components.lisp Wed Mar 12 05:26:40 2008 @@ -52,10 +52,6 @@ (defmethod wcomponent-template((cform cform)) (let ((client-id (htcomponent-client-id cform)) (class (wcomponent-parameter-value cform :class))) - (when (null client-id) - (setf client-id "")) - (when (null class) - (setf class "")) (form> :static-id client-id :name client-id :class class @@ -111,6 +107,7 @@ :validator-handler nil :class nil :label nil + :translator *simple-translator* :validator nil :type :required)) @@ -118,26 +115,16 @@ '(:value :name)) (defmethod wcomponent-template ((cinput cinput)) - (let* ((client-id (htcomponent-client-id cinput)) + (let ((client-id (htcomponent-client-id cinput)) (type (wcomponent-parameter-value cinput :type)) - (visit-object (wcomponent-parameter-value cinput :visit-object)) - (accessor (wcomponent-parameter-value cinput :accessor)) - (reader (wcomponent-parameter-value cinput :reader)) - (class (wcomponent-parameter-value cinput :class)) - (value "") - (validation-errors (aux-request-value :validation-errors)) - (component-exceptions (assoc client-id validation-errors :test #'equal))) - (when (null visit-object) - (setf visit-object (htcomponent-page cinput))) - (when (null class) - (setf class "")) - (when component-exceptions - (if (string= class "") + (class (wcomponent-parameter-value cinput :class)) + (translator (wcomponent-parameter-value cinput :translator)) + (value "")) + (when (component-validation-errors cinput) + (if (or (null class) (string= class "")) (setf class "error") (setf class (format nil "~a error" class)))) - (if (and (null reader) accessor) - (setf value (funcall (fdefinition accessor) visit-object)) - (setf value (funcall (fdefinition reader) visit-object))) + (setf value (translator-encode translator cinput)) (input> :static-id client-id :type type :name client-id @@ -145,22 +132,28 @@ :value value (wcomponent-informal-parameters cinput)))) -(defmethod wcomponent-after-rewind ((obj cinput) (pobj page)) - (let ((visit-object (wcomponent-parameter-value obj :visit-object)) - (accessor (wcomponent-parameter-value obj :accessor)) - (writer (wcomponent-parameter-value obj :writer)) - (validator (wcomponent-parameter-value obj :validator)) - (new-value (page-req-parameter pobj - (htcomponent-client-id obj) - (cinput-result-as-list obj)))) - (unless (null new-value) - (when (null visit-object) - (setf visit-object (htcomponent-page obj))) - (if (and (null writer) accessor) - (funcall (fdefinition `(setf ,accessor)) new-value visit-object) - (funcall (fdefinition writer) new-value visit-object)) - (when validator - (funcall validator))))) +(defmethod wcomponent-after-rewind ((cinput cinput) (page page)) + (let ((visit-object (wcomponent-parameter-value cinput :visit-object)) + (accessor (wcomponent-parameter-value cinput :accessor)) + (writer (wcomponent-parameter-value cinput :writer)) + (validator (wcomponent-parameter-value cinput :validator)) + (translator (wcomponent-parameter-value cinput :translator)) + (value)) + (multiple-value-bind (client-id request-value) + (component-id-and-value cinput) + (setf value + (handler-case + (translator-decode translator cinput) + (error () request-value))) + (unless (null value) + (when validator + (funcall validator value)) + (unless (component-validation-errors cinput) + (when (null visit-object) + (setf visit-object page)) + (if (and (null writer) accessor) + (funcall (fdefinition `(setf ,accessor)) value visit-object) + (funcall (fdefinition writer) value visit-object))))))) ;--------------------------------------------------------------------------------------- (defcomponent csubmit () () @@ -236,54 +229,5 @@ (htcomponent-body obj)))) -(defun component-id-and-value (component) - (let ((client-id (htcomponent-client-id component)) - (visit-object (wcomponent-parameter-value component :visit-object)) - (accessor (wcomponent-parameter-value component :accessor)) - (reader (wcomponent-parameter-value component :reader)) - (value "")) - (when (null visit-object) - (setf visit-object (htcomponent-page component))) - (if (and (null reader) accessor) - (setf value (funcall (fdefinition accessor) visit-object)) - (setf value (funcall (fdefinition reader) visit-object))) - (values client-id value))) - -(defun add-exception (id reason) - (let* ((validation-errors (aux-request-value :validation-errors)) - (component-exceptions (assoc id validation-errors :test #'equal))) - (if component-exceptions - (push reason (cdr component-exceptions)) - (push (cons id (list reason)) - (aux-request-value :validation-errors))))) - -(defun validator-required (component) - (multiple-value-bind (client-id value) - (component-id-and-value component) - (when (or (null value) (string= value "")) - (add-exception client-id - (format nil "Field ~a may not be null." (wcomponent-parameter-value component :label)))))) -;; ------------------------------------------------------------------------------------ -(defcomponent exce (cinput) () - (:default-initargs :result-as-list t) - (:documentation "This component renders as a normal SELECT tag class, -but it is request cycle aware.")) -(defmethod wcomponent-parameters :around ((obj cselect)) - (declare (ignore obj)) - (let ((params (call-next-method))) - (remf params :reader) - (remf params :type) - params)) - -(defmethod wcomponent-reserved-parameters ((obj cselect)) - (declare (ignore obj)) - '(:type :name)) - -(defmethod wcomponent-template ((obj cselect)) - (let ((client-id (htcomponent-client-id obj))) - (select> :static-id client-id - :name client-id - (wcomponent-informal-parameters obj) - (htcomponent-body obj)))) \ No newline at end of file Modified: trunk/main/claw-core/src/lisplet.lisp ============================================================================== --- trunk/main/claw-core/src/lisplet.lisp (original) +++ trunk/main/claw-core/src/lisplet.lisp Wed Mar 12 05:26:40 2008 @@ -95,11 +95,7 @@ :error-code error-code))) (with-output-to-string (*standard-output*) (page-render error-page))))))) -(defun lisplet-start-session () - "Starts a session boud to the current lisplet base path" - (start-session (format nil "~@[~a~]~a/" *clawserver-base-path* (lisplet-base-path (current-lisplet))))) - -(defclass lisplet () +(defclass lisplet (i18n-aware) ((base-path :initarg :base-path :reader lisplet-base-path :documentation "common base path all resources registered into this lisplet") @@ -123,7 +119,7 @@ :documentation "A collection of cons where the car is the protected url location and the cdr is a string list of roles allowhed to access the relative location") (redirect-protected-resources-p :initarg :redirect-protected-resources-p :accessor lisplet-redirect-protected-resources-p - :documentation "When not null every request will be redirected in https mode. When running in mod-lisp mode, *apache-http-port* and *apache-https-port* values are used")) + :documentation "When not null every request will be redirected in https mode. When running in mod-lisp mode, *apache-http-port* and *apache-https-port* values are used")) (:default-initargs :welcome-page nil :login-page nil :realm "claw" @@ -196,8 +192,10 @@ (uri (request-uri)) (welcome-page (lisplet-welcome-page lisplet))) (progn - (setf (aux-request-value 'lisplet) lisplet) - (setf (aux-request-value 'realm) (lisplet-realm lisplet)) + ;;(setf (aux-request-value 'lisplet) lisplet) + (setf (current-lisplet) lisplet) + ;;(setf (aux-request-value 'realm) (lisplet-realm lisplet)) + (setf (current-realm) (lisplet-realm lisplet)) (lisplet-check-authorization lisplet) (when (= (return-code) +http-ok+) (if (and welcome-page (string= uri base-path)) @@ -263,6 +261,6 @@ (format nil "Basic realm=\"~A\"" (hunchentoot::quote-string (current-realm))))) (setf (return-code) +http-authorization-required+) (throw 'handler-done nil)) - (unless (user-in-role-p) + (unless (user-in-role-p allowed-roles) (setf (return-code) +http-forbidden+) (throw 'handler-done nil)))))))) Modified: trunk/main/claw-core/src/misc.lisp ============================================================================== --- trunk/main/claw-core/src/misc.lisp (original) +++ trunk/main/claw-core/src/misc.lisp Wed Mar 12 05:26:40 2008 @@ -29,6 +29,8 @@ (in-package :claw) +(defvar *clawserver-base-path* nil) + (defvar *apache-http-port* 80 "Default apache http port when claw is running in mod_lisp mode") (defvar *apache-https-port* 443 @@ -71,25 +73,56 @@ (let ((result (remove-by-location (car location-cons) cons-list))) (setf result (push location-cons cons-list)))) +(defun lisplet-start-session () + "Starts a session boud to the current lisplet base path" + (start-session (format nil "~@[~a~]~a/" *clawserver-base-path* (lisplet-base-path (current-lisplet))))) + + +(defun current-page (&optional (request *request*)) + "Returns the page that is rendering" + (aux-request-value 'page request)) + +(defun (setf current-page) (page &optional (request *request*)) + "Setf the page that is to be rendered" + (setf (aux-request-value 'page request) page)) + (defun current-realm (&optional (request *request*)) "Returns the realm under which the request has been sent" (aux-request-value 'realm request)) +(defun (setf current-realm) (realm &optional (request *request*)) + "Setf the realm under which the request has been sent" + (setf (aux-request-value 'realm request) realm)) + (defun current-lisplet (&optional (request *request*)) "Returns the lisplet instance from which the request comes from" (aux-request-value 'lisplet request)) +(defun (setf current-lisplet) (lisplet &optional (request *request*)) + "Sets the lisplet instance from which the request comes from" + (setf (aux-request-value 'lisplet request) lisplet)) + (defun current-server (&optional (request *request*)) "Returns the clawserver instance from which the request comes from" (aux-request-value 'clawserver request)) +(defun (setf current-server) (server &optional (request *request*)) + "Sets the clawserver instance from which the request comes from" + (setf (aux-request-value 'clawserver request) server)) + (defun current-principal (&optional (session *session*)) "Returns the principal(user) that logged into the application" (when session (session-value 'principal session))) +(defun (setf current-principal) (principal &optional (session *session*)) + "Setf the principal(user) that logged into the application" + (unless session + (setf session (lisplet-start-session))) + (setf (session-value 'principal session) principal)) + (defun user-in-role-p (roles &optional (session *session*)) - "Detects if current principal belongs to any of the expressed roles" + "Detects if current principal belongs to any of the expressed roles" (let ((principal (current-principal session))) (when principal (loop for el in (principal-roles principal) thereis (member el roles))))) @@ -101,3 +134,53 @@ (defun login (&optional (request *request*)) "Perfoms a login action using the configuration object given for the request realm" (configuration-login (current-config request))) + +(defun flatten (tree &optional result-list) + "Traverses the tree in order, collecting even non-null leaves into a list." + (let ((result result-list)) + (loop for element in tree + do (cond + ((consp element) (setf result (append (nreverse (flatten element result-list)) result))) + (t (push element result)))) + (nreverse result))) + +(defmacro message (key locale &optional (default "")) + (let ((current-lisplet (gensym)) + (current-page (gensym)) + (current-component (gensym)) + (result (gensym)) + (key-val key) + (locale-val locale) + (default-val default)) + `#'(lambda () + (let ((,current-lisplet (current-lisplet)) + (,current-page (current-page)) + (,current-component (current-component)) + (,result)) + (when ,current-lisplet + (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) + (when (and (null ,result) ,current-page) + (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) + (when (and (null ,result) ,current-component) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val))) + (when (and (null ,result) (> (length ,locale-val) 2)) + (setf ,locale-val (subseq ,locale-val 0 2)) + (when ,current-lisplet + (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) + (when (and (null ,result) ,current-page) + (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) + (when (and (null ,result) ,current-component) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val)))) + (when (null ,result) + (setf ,locale-val "") + (when ,current-lisplet + (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) + (when (and (null ,result) ,current-page) + (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) + (when (and (null ,result) ,current-component) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val)))) + (if ,result + ,result + ,default-val))))) + + \ No newline at end of file Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Wed Mar 12 05:26:40 2008 @@ -34,6 +34,7 @@ (defpackage :claw (:use :cl :hunchentoot :alexandria :cl-ppcre :cl-fad) + (:shadow :flatten) (:export :*html-4.01-strict* :*html-4.01-transitional* :*html-4.01-frameset* @@ -48,6 +49,7 @@ ;:request-realm :request-id-table-map ;:dyna-id + :flatten :tag-emptyp :tag-symbol-class :strings-to-jsarray @@ -55,6 +57,7 @@ :build-tagf :parse-htcomponent-function :page ;page classes hadle the whole rendering cycle + :message-dispatch :page-writer :page-can-print :page-url @@ -219,8 +222,7 @@ :csubmit :csubmit> :submit-link - :submit-link> - :validator-required + :submit-link> :lisplet :lisplet-realm :lisplet-pages @@ -268,5 +270,26 @@ :current-lisplet :current-server :current-realm + :current-page + :current-component + :page-current-component :user-in-role-p - :login)) + :login + :message + ;;validation + :translator + :translator-integer + :translator-encode + :translator-decode + :*simple-translator* + ;;:with-validators disabled + :validate + :validation-errors + :component-validation-errors + :validator-required + :validator-size + :validator-range + :validator-number + :validator-integer + :exception-monitor + :exception-monitor>)) Modified: trunk/main/claw-core/src/server.lisp ============================================================================== --- trunk/main/claw-core/src/server.lisp (original) +++ trunk/main/claw-core/src/server.lisp Wed Mar 12 05:26:40 2008 @@ -398,7 +398,8 @@ (defmethod clawserver-dispatch-method ((clawserver clawserver)) (let ((result nil)) (progn - (setf (aux-request-value 'clawserver) clawserver) + ;(setf (aux-request-value 'clawserver) clawserver) + (setf (current-server) clawserver) (setf result (clawserver-dispatch-request clawserver)) (if (null result) #'(lambda () (when (= (return-code) +http-ok+) @@ -462,8 +463,8 @@ ;;;---------------------------------------------------------------------------- (defun login (&optional (request *request*)) "Perform user authentication for the reaml where the request has been created" - (let* ((server (aux-request-value 'clawserver)) - (realm (aux-request-value 'realm)) + (let* ((server (current-server request));(aux-request-value 'clawserver)) + (realm (current-realm request));(aux-request-value 'realm)) (login-config (gethash realm (clawserver-login-config server)))) (configuration-login login-config request))) Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Wed Mar 12 05:26:40 2008 @@ -29,7 +29,8 @@ (in-package :claw) - +(defgeneric message-dispatch (object key locale) + (:documentation "Returns the KEY translation by the given LOCALE")) (defgeneric page-req-parameter (page name &optional as-list) (:documentation "This method returns a request parameter given by NAME searching first @@ -213,8 +214,6 @@ - WCOMPONENT is the tag instance - PAGE the page instance")) -(defvar *clawserver-base-path* nil) - (defvar *html-4.01-strict* "" "Page doctype as HTML 4.01 STRICT") @@ -262,22 +261,21 @@ (when (boundp '*request*) (setf (aux-request-value :id-table-map) (make-hash-table :test 'equal)))) - (defun parse-htcomponent-function (function-body) "This function parses attributes passed to a htcomponent creation function" (let ((attributes) (body)) - (loop for last-elem = nil then elem - for elem in function-body - do (if (or (and (stringp last-elem) (stringp elem)) - (and (null last-elem) (stringp elem)) - (subtypep (type-of elem) 'htcomponent) - (and (evenp (length attributes)) (stringp elem)) - body) - (push elem body) - (push elem attributes))) + (loop for last-elem = nil then elem + for elem in function-body + do (if (and (null body) + (or (keywordp elem) + (keywordp last-elem))) + (push elem attributes) + (when elem + (push elem body)))) (list (reverse attributes) (reverse body)))) + (defun generate-id (id) "This function is very useful when having references to components id inside component body. When used with :STATIC-ID the generated id will be mantained as is, and rendered just like the :ID tag attribute." @@ -325,8 +323,17 @@ ;;;---------------------------------------------------------------- +(defclass message-dispatcher () + ()) + +(defclass i18n-aware (message-dispatcher) + ((message-dispatcher :initarg :message-dispatcher + :accessor message-dispatcher + :documentation "Reference to a MESSAGE-DISPATCHER instance")) + (:default-initargs :message-dispatcher nil) + (:documentation "All classes that need to dispatch messages are subclasses of I18N-AWARE")) -(defclass page() +(defclass page(i18n-aware) ((writer :initarg :writer :accessor page-writer :documentation "The output stream for this page instance") (lisplet :initarg :lisplet @@ -570,7 +577,8 @@ (let ((body (page-content page)) (jsonp (page-json-id-list page))) (if (null body) - (format nil "null body for page ~a~%" (type-of page)) + ;(format nil "null body for page ~a~%" (type-of page)) + (setf (current-page) page) (progn (page-init page) (when (page-req-parameter page *rewind-parameter*) @@ -587,9 +595,12 @@ (page-format-raw page "},classInjections:\"") (setf (page-can-print page) t) (dolist (injection (page-init-injections page)) - (htcomponent-render injection page)) + (when injection + (htcomponent-render injection page))) (page-format-raw page "\",instanceInjections:\"") - (htcomponent-render (htbody-init-scripts-tag page) page) + (let ((init-scripts (htbody-init-scripts-tag page))) + (when init-scripts + (htcomponent-render init-scripts page))) (page-format-raw page "\"}")))))) (defmethod page-body-init-scripts ((page page)) @@ -639,6 +650,11 @@ (defmethod page-current-component ((page page)) (car (page-components-stack page))) + +(defmethod current-component () + (let ((page (current-page))) + (when page + (car (page-components-stack page))))) ;;;========= HTCOMPONENT ============================ (defmethod htcomponent-can-print ((htcomponent htcomponent)) (let* ((id (htcomponent-client-id htcomponent)) @@ -708,10 +724,12 @@ (when (null previous-print-status) (setf (page-can-print page) (htcomponent-can-print htcomponent)) (htcomponent-json-print-start-component htcomponent)) - (dolist (tag body-list) - (if (stringp tag) - (htcomponent-render ($> tag) page) - (htcomponent-render tag page))) + (dolist (child-tag body-list) + (when child-tag + (cond + ((stringp child-tag) (htcomponent-render ($> child-tag) page)) + ((functionp child-tag) (funcall child-tag)) + (t (htcomponent-render child-tag page))))) (when (null previous-print-status) (setf (page-can-print page) nil) (htcomponent-json-print-end-component htcomponent)))) @@ -722,7 +740,9 @@ (loop for (k v) on (htcomponent-attributes tag) by #'cddr do (progn (assert (keywordp k)) - (when (and v (string-not-equal v "")) + (when (functionp v) + (setf v (funcall v))) + (when (and v (string-not-equal v "")) (page-format page " ~a=\"~a\"" (string-downcase (if (eq k :static-id) "id" @@ -773,10 +793,12 @@ (htcomponent-json-print-start-component tag)) (when (or (page-can-print page) previous-print-status) (tag-render-starttag tag page)) - (dolist (tag body-list) - (if (stringp tag) - (htcomponent-render ($> tag) page) - (htcomponent-render tag page))) + (dolist (child-tag body-list) + (when child-tag + (cond + ((stringp child-tag) (htcomponent-render ($> child-tag) page)) + ((functionp child-tag) (funcall child-tag)) + (t (htcomponent-render child-tag page))))) (when (or (page-can-print page) previous-print-status) (tag-render-endtag tag page)) (unless previous-print-status @@ -789,12 +811,15 @@ (let ((body-list (htcomponent-body hthead)) (injections (page-init-injections page))) (tag-render-starttag hthead page) - (dolist (tag body-list) - (if (stringp tag) - (htcomponent-render ($> tag) page) - (htcomponent-render tag page))) + (dolist (child-tag body-list) + (when child-tag + (cond + ((stringp child-tag) (htcomponent-render ($> child-tag) page)) + ((functionp child-tag) (funcall child-tag)) + (t (htcomponent-render child-tag page))))) (dolist (injection injections) - (htcomponent-render injection page)) + (when injection + (htcomponent-render injection page))) (tag-render-endtag hthead page)))) ;;;========= HTSTRING =================================== @@ -806,7 +831,9 @@ (let ((body (htcomponent-body htstring)) (jsonp (not (null (page-json-id-list page)))) (print-p (page-can-print page))) - (when (or print-p body) + (when (and print-p body) + (when (functionp body) + (setf body (funcall body))) (when jsonp (setf body (regex-replace-all "\"" (regex-replace-all "\\\\\"" @@ -846,9 +873,11 @@ (unless (listp body) (setf body (list body))) (dolist (element body) - (if (stringp element) - (htcomponent-render ($raw> element) page) - (htcomponent-render element page))) + (when element + (cond + ((stringp element) (htcomponent-render ($> element) page)) + ((functionp element) (funcall element)) + (t (htcomponent-render element page))))) (if (null xml-p) (page-format page "~%//-->") (page-format page "~%//]]>"))) @@ -885,10 +914,12 @@ (htcomponent-json-print-start-component htbody)) (when (page-can-print page) (tag-render-starttag htbody page)) - (dolist (tag body-list) - (if (stringp tag) - (htcomponent-render ($> tag) page) - (htcomponent-render tag page))) + (dolist (child-tag body-list) + (when child-tag + (cond + ((stringp child-tag) (htcomponent-render ($> child-tag) page)) + ((functionp child-tag) (funcall child-tag)) + (t (htcomponent-render child-tag page))))) (when (page-can-print page) (htcomponent-render (htbody-init-scripts-tag page) page) (tag-render-endtag htbody page)) @@ -903,7 +934,7 @@ js)) ;;;========= WCOMPONENT =================================== -(defclass wcomponent (htcomponent) +(defclass wcomponent (htcomponent i18n-aware) ((parameters :initarg :parameters :accessor wcomponent-parameters :type cons @@ -1060,10 +1091,12 @@ (wcomponent-before-render wcomponent page) (unless (listp template) (setf template (list template))) - (dolist (tag template) - (if (stringp tag) - (htcomponent-render ($> tag) page) - (htcomponent-render tag page))) + (dolist (child-tag template) + (when child-tag + (cond + ((stringp child-tag) (htcomponent-render ($> child-tag) page)) + ((functionp child-tag) (funcall child-tag)) + (t (htcomponent-render child-tag page))))) (wcomponent-after-render wcomponent page) (when (null previous-print-status) (setf (page-can-print page) nil) @@ -1071,3 +1104,37 @@ (defmethod wcomponent-before-render ((wcomponent wcomponent) (page page))) (defmethod wcomponent-after-render ((wcomponent wcomponent) (page page))) + +(defun component-id-and-value (component &key (from-request-p t) value-as-list-p) + (let ((client-id (htcomponent-client-id component)) + (page (htcomponent-page component)) + (visit-object (wcomponent-parameter-value component :visit-object)) + (accessor (wcomponent-parameter-value component :accessor)) + (reader (wcomponent-parameter-value component :reader)) + (result-as-list (cinput-result-as-list component)) + (value "")) + (when (null visit-object) + (setf visit-object (htcomponent-page component))) + (cond + (from-request-p (setf value (page-req-parameter page client-id value-as-list-p))) + ((and (null reader) accessor) (setf value (funcall (fdefinition accessor) visit-object))) + (t (setf value (funcall (fdefinition reader) visit-object)))) + (values client-id + (if result-as-list + (list value) + value)))) + + +(defmethod message-dispatch ((message-dispatcher message-dispatcher) key locale) nil) + +(defmethod message-dispatch ((i18n-aware i18n-aware) key locale) + (let ((dispatcher (message-dispatcher i18n-aware)) + (result)) + (when dispatcher + (progn + (setf result (message-dispatch dispatcher key locale)) + (when (null result)))) + + + + Added: trunk/main/claw-core/src/validators.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-core/src/validators.lisp Wed Mar 12 05:26:40 2008 @@ -0,0 +1,273 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: src/components.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :claw) + +(defgeneric translator-encode (translator wcomponent) + (:documentation "Encodes the input component value, used when rendering the component")) + +(defgeneric translator-decode (translator wcomponent) + (:documentation "Decodes the input component value")) + +(defclass translator () + () + (:documentation "a translator object encodes and decodes values passed to a html input component")) + +(defmethod translator-encode ((translator translator) (wcomponent wcomponent)) + (let ((page (htcomponent-page wcomponent)) + (visit-object (wcomponent-parameter-value wcomponent :visit-object)) + (accessor (wcomponent-parameter-value wcomponent :accessor)) + (reader (wcomponent-parameter-value wcomponent :reader))) + (format nil "~a" (if (component-validation-errors wcomponent) + (page-req-parameter page (htcomponent-client-id wcomponent) nil) + (progn + (when (null visit-object) + (setf visit-object (htcomponent-page wcomponent))) + (if (and (null reader) accessor) + (funcall (fdefinition accessor) visit-object) + (funcall (fdefinition reader) visit-object))))))) + +(defmethod translator-decode ((translator translator) (wcomponent wcomponent)) + (multiple-value-bind (client-id new-value) + (component-id-and-value wcomponent) + new-value)) + +(defvar *simple-translator* (make-instance 'translator)) + +(defclass translator-integer (translator) + ((thousand-separator :initarg :thousand-separator + :reader translator-thousand-separator) + (always-show-signum :initarg :always-show-signum + :reader translator-always-show-signum)) + (:default-initargs :thousand-separator nil + :always-show-signum nil) + (:documentation "a translator object encodes and decodes integer values passed to a html input component")) + +(defmethod translator-encode ((translator translator-integer) (wcomponent wcomponent)) + (let* ((page (htcomponent-page wcomponent)) + (visit-object (wcomponent-parameter-value wcomponent :visit-object)) + (accessor (wcomponent-parameter-value wcomponent :accessor)) + (reader (wcomponent-parameter-value wcomponent :reader)) + (thousand-separator (translator-thousand-separator translator)) + (signum-directive (if (translator-always-show-signum translator) + "@" + "")) + (control-string (if thousand-separator + (format nil "~~3,' ,v:~aD" signum-directive) + (format nil "~~~ad" signum-directive))) + + (value (page-req-parameter page (htcomponent-client-id wcomponent) nil))) + (if (component-validation-errors wcomponent) + value + (progn + (when (null visit-object) + (setf visit-object (htcomponent-page wcomponent))) + (setf value (cond + ((and (null reader) accessor) (funcall (fdefinition accessor) visit-object)) + (t (funcall (fdefinition reader) visit-object)))) + (if thousand-separator + (string-trim " " (format nil control-string thousand-separator value)) + (format nil control-string value)))))) + +(defmethod translator-decode ((translator translator-integer) (wcomponent wcomponent)) + (let* ((thousand-separator (translator-thousand-separator translator))) + (multiple-value-bind (client-id new-value) + (component-id-and-value wcomponent) + (if thousand-separator + (parse-integer (regex-replace-all (format nil "~a" thousand-separator) new-value "")) + (parse-integer new-value))))) + +;;========================================= +#| +(defclass translator-number (translator) + ((thousand-separator :initarg :thousand-separator + :reader translator-thousand-separator) + (decimals-separator :initarg :decimals-separator + :reader translator-decimals-separator) + (decimal-digits :initarg :decimal-digits + :reader translator-decimal-digits) + (always-show-signum :initarg :always-show-signum + :reader translator-always-show-signum)) + (:default-initargs :thousand-separator nil :decimals-separator #\. + :integer-digits nil + :decimal-digits nil + :always-show-signum nil) + (:documentation "a translator object encodes and decodes integer values passed to a html input component")) + +(defmethod translator-encode ((translator translator-number) (wcomponent wcomponent)) + (let* ((page (htcomponent-page wcomponent)) + (visit-object (wcomponent-parameter-value wcomponent :visit-object)) + (accessor (wcomponent-parameter-value wcomponent :accessor)) + (reader (wcomponent-parameter-value wcomponent :reader)) + (thousand-separator (translator-thousand-separator translator)) + (decimal-digits (translator-decimal-digits translator)) + (decimals-separator (translator-decimals-separator translator)) + (signum-directive (if (translator-always-show-signum translator) + "@" + "")) + (integer-control-string (if thousand-separator + (format nil "~~3,' ,v:~aD" signum-directive) + (format nil "~~~ad" signum-directive))) + + (value (page-req-parameter page (htcomponent-client-id wcomponent) nil))) + (if (component-validation-errors wcomponent) + value + (progn + (when (null visit-object) + (setf visit-object (htcomponent-page wcomponent))) + (multiple-value-bind (int-value dec-value) + (floor (cond + ((and (null reader) accessor) (funcall (fdefinition accessor) visit-object)) + (t (funcall (fdefinition reader) visit-object)))) + (format nil "~a~a" (if thousand-separator + (string-trim " " (format nil control-string thousand-separator int-value)) + (format nil control-string int-value)) + (cond + ((and (= 0.0 (coerce dec-value 'double-float)) decimal-digits) + (format "~a~a" decimals-separator (make-string decimal-digits #\0))) + (decimal-digits + (format "~a~a" decimals-separator (make-string decimal-digits #\0)) + +(defmethod translator-decode ((translator translator-number) (wcomponent wcomponent)) + (let* ((thousand-separator (translator-thousand-separator translator))) + (multiple-value-bind (client-id new-value) + (component-id-and-value wcomponent) + (if thousand-separator + (parse-integer (regex-replace-all (format nil "~a" thousand-separator) new-value "")) + (parse-integer new-value))))) + +|# +;;---------------------------------------------------------------------------------------- +(defun add-exception (id reason) + (let* ((validation-errors (aux-request-value :validation-errors)) + (component-exceptions (assoc id validation-errors :test #'equal))) + (if component-exceptions + (setf (cdr component-exceptions) (append (cdr component-exceptions) (list reason))) + (if validation-errors + (setf (aux-request-value :validation-errors) (append validation-errors (list (cons id (list reason))))) + (setf (aux-request-value :validation-errors) (list (cons id (list reason)))))))) + + +(defun validate (test &key component message) + (let ((client-id (htcomponent-client-id component))) + (unless test + (add-exception client-id message)))) + +(defun validation-errors (&optional (request *request*)) + "Resurns possible validation errors occurred during form rewinding" + (aux-request-value :validation-errors request)) + +(defun component-validation-errors (component &optional (request *request*)) + "Resurns possible validation errors occurred during form rewinding bound to a specific component" + (let ((client-id (htcomponent-client-id component))) + (assoc client-id (validation-errors request) :test #'equal))) + +(defun validator-required (component value) + (when (stringp value) + (validate (and value (string-not-equal value "")) + :component component + :message (format nil "Field ~a may not be null." (wcomponent-parameter-value component :label))))) + +(defun validator-size (component value &key min-size max-size) + (let ((value-len 0)) + (when value + (setf value (format nil "~a" value)) + (setf value-len (length value)) + (or (= value-len 0) + (when min-size + (validate (>= value-len min-size) + :component component + :message (format nil "Size of ~a may not be less then ~a" + (wcomponent-parameter-value component :label) + min-size))) + (when max-size + (validate (<= value-len max-size) + :component component + :message (format nil "Size of ~a may not be more then ~a" + (wcomponent-parameter-value component :label) + max-size))))))) + +(defun validator-range (component value &key min max) + (when value + (or (when min + (validate (>= value min) + :component component + :message (format nil "Field ~a is not greater then or equal to ~d" (wcomponent-parameter-value component :label) min))) + (when max + (validate (<= value max) + :component component + :message (format nil "Field ~a is not less then or equal to ~d" (wcomponent-parameter-value component :label) max)))))) + +(defun validator-number (component value &key min max) + (when value + (let ((test (numberp value))) + (or (validate test + :component component + :message (format nil "Field ~a is not a valid number" (wcomponent-parameter-value component :label))) + (validator-range component value :min min :max max))))) + +(defun validator-integer (component value &key min max) + (when value + (let ((test (integerp value))) + (or (validate test + :component component + :message (format nil "Field ~a is not a valid integer" (wcomponent-parameter-value component :label))) + (validator-range component value :min min :max max))))) + + +;; ------------------------------------------------------------------------------------ +(defcomponent exception-monitor () () + (:documentation "If from submission contains exceptions. It displays exception messages")) + +(defmethod wcomponent-parameters ((exception-monitor exception-monitor)) + (declare (ignore exception-monitor)) + (list :class nil)) + +(defmethod wcomponent-template ((exception-monitor exception-monitor)) + (let ((client-id (htcomponent-client-id exception-monitor)) + (validation-errors (aux-request-value :validation-errors))) + (when validation-errors + (ul> :static-id client-id + (loop for component-exceptions in validation-errors + collect (loop for message in (cdr component-exceptions) + collect (li> message))))))) + +;;------------------------------------------------------------------------------------------- + +#| +(defmacro with-validators (&rest rest) + (let* ((component (gensym)) + (value (gensym)) + (validators (loop for validator in rest + collect (list 'funcall validator component value)))) + `#'(lambda (,value) + (let ((,component (current-component))) + (or , at validators))))) +|# + Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Wed Mar 12 05:26:40 2008 @@ -41,8 +41,6 @@ (defvar *test-lisplet2*) (setf *test-lisplet2* (make-instance 'lisplet :realm "test2" :base-path "/test2")) - - ;;(defparameter *clawserver* (make-instance 'clawserver :port 4242)) (defparameter *clawserver* (make-instance 'clawserver :port 4242 :sslport 4445 @@ -60,9 +58,10 @@ (when (and (string-equal user "kiuma") (string-equal password "password")) (progn - (unless session - (setf session (lisplet-start-session))) - (setf (session-value 'principal session) (make-instance 'principal :name user :roles '("user"))))))) + ;;(unless session + ;; (setf session (lisplet-start-session))) + ;;(setf (session-value 'principal session) (make-instance 'principal :name user :roles '("user"))))))) + (setf (current-principal session) (make-instance 'principal :name user :roles '("user"))))))) @@ -117,9 +116,11 @@ (defclass auth-page (page) ()) (defmethod page-content ((page auth-page)) (site-template> :title "Unauth test page" - (p> "not here"))) + (p> "protected content"))) (lisplet-register-page-location *test-lisplet* 'auth-page "unauth.html") -(lisplet-protect *test-lisplet* "unauth.html" '("admin" "user")) +(lisplet-register-page-location *test-lisplet* 'auth-page "auth.html") +(lisplet-protect *test-lisplet* "auth.html" '("admin" "user")) +(lisplet-protect *test-lisplet* "unauth.html" '("nobody")) (defclass index-page (page) ()) @@ -129,6 +130,8 @@ (ul> (li> (a> :href "login.html" "Do login")) + (li> (a> :href "info.html" + "Headers info")) (li> (a> :href "images/matrix.jpg" "show static file")) (li> (a> :href "images/matrix2.jpg" @@ -139,11 +142,28 @@ "realm on lisplet 'test2'")) (li> (a> :href "id-tests.html" "id generation test")) (li> (a> :href "form.html" "form components test")) + (li> (a> :href "auth.html" "authorized page")) (li> (a> :href "unauth.html" "unauthorized page")))))) +(lisplet-register-page-location *test-lisplet* 'index-page "index.html" :welcome-page-p t) + +(defclass info-page (page) ()) + +(defmethod page-content ((o info-page)) + (let ((header-props (headers-in))) + (site-template> :title "Header info page" + (p> :id "p" + (table> + (tr> (td> :colspan "2" "Header info")) + (loop for key-val in header-props + collect (tr> + (td> (format nil "~a" (car key-val)) + (td> (format nil "~a" (cdr key-val))))))))))) + +(lisplet-register-page-location *test-lisplet* 'info-page "info.html") + (defun test-image-file () (make-pathname :directory (append (pathname-directory *this-file*) '("img")) :name "matrix" :type "jpg")) -(lisplet-register-page-location *test-lisplet* 'index-page "index.html" :welcome-page-p t) (lisplet-register-resource-location *test-lisplet* (test-image-file) "images/matrix.jpg" "image/jpeg") @@ -266,8 +286,10 @@ (surname :initarg :surname :accessor user-surname) (gender :initarg :gender - :accessor user-gender)) - (:default-initargs :name "" :surname "" :gender "")) + :accessor user-gender) + (age :initarg :age + :accessor user-age)) + (:default-initargs :name "" :surname "" :gender "" :age "")) (defgeneric form-page-update-user (form-page)) @@ -282,21 +304,29 @@ :writer setf-gender :accessor form-page-gender) (user :initarg :user - :accessor form-page-user)) + :accessor form-page-user) + (age :initarg :age + :accessor form-page-age)) (:default-initargs :name "kiuma" :surname "surnk" :colors nil :gender '("M") + :age 1800 :user (make-instance 'user))) (defmethod form-page-update-user ((form-page form-page)) (let ((user (form-page-user form-page)) (name (form-page-name form-page)) (surname (form-page-surname form-page)) - (gender (first (form-page-gender form-page)))) + (gender (first (form-page-gender form-page))) + (age (form-page-age form-page))) (setf (user-name user) name (user-surname user) surname - (user-gender user) gender))) + (user-gender user) gender + (user-age user) age))) + +;(defmethod message-dispatch ((object form-page) key locale) + (defmethod page-content ((o form-page)) (site-template> :title "a page title" @@ -308,17 +338,18 @@ (cinput> :id "name" :type "text" :label "Name" - :validator #'(lambda () - (validator-required (page-current-component o))) + :validator #'(lambda (value) + (validator-required (page-current-component o) value)) :accessor 'form-page-name)"*")) (tr> (td> "Surname") (td> (cinput> :id "surname" :type "text" - :label "Name" - :validator #'(lambda () - (validator-required (page-current-component o))) + :label "Surname" + :validator #'(lambda (value) + (validator-required (page-current-component o) value) + (validator-size (page-current-component o) value :min-size 1 :max-size 20)) :accessor 'form-page-surname)"*")) (tr> (td> "Gender") @@ -333,6 +364,18 @@ "Male" "Female")))))) (tr> + (td> "Age") + (td> + (cinput> :id "age" + :type "text" + :label "Age" + :translator (make-instance 'translator-integer :thousand-separator #\') + :validator #'(lambda (value) + (let ((component (page-current-component o))) + (validator-required component value) + (validator-integer component value :min 1 :max 2000))) + :accessor 'form-page-age)"*")) + (tr> (td> "Colors") (td> (cselect> :id "colors" @@ -350,12 +393,14 @@ (tr> (td> :colspan "2" (csubmit> :id "submit" :value "OK"))))) - (p> + (p> + (exception-monitor>) (hr>) (h2> "From result:") (div> (format nil "Name: ~a" (user-name (form-page-user o)))) (div> (format nil "Surname: ~a" (user-surname (form-page-user o)))) - (div> (format nil "Gender: ~a" (user-gender (form-page-user o))))))) + (div> (format nil "Gender: ~a" (user-gender (form-page-user o)))) + (div> (format nil "Age: ~a" (user-age (form-page-user o))))))) (lisplet-register-page-location *test-lisplet* 'form-page "form.html") From achiumenti at common-lisp.net Wed Mar 12 20:20:24 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Wed, 12 Mar 2008 15:20:24 -0500 (EST) Subject: [claw-cvs] r16 - in trunk/main/claw-core: src tests Message-ID: <20080312202024.CF807586D8@common-lisp.net> Author: achiumenti Date: Wed Mar 12 15:20:24 2008 New Revision: 16 Modified: trunk/main/claw-core/src/misc.lisp trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/tags.lisp trunk/main/claw-core/tests/test1.lisp Log: beginning of translators and i18n support Modified: trunk/main/claw-core/src/misc.lisp ============================================================================== --- trunk/main/claw-core/src/misc.lisp (original) +++ trunk/main/claw-core/src/misc.lisp Wed Mar 12 15:20:24 2008 @@ -144,33 +144,31 @@ (t (push element result)))) (nreverse result))) -(defmacro message (key locale &optional (default "")) +(defmacro with-message (key locale &optional (default "")) (let ((current-lisplet (gensym)) (current-page (gensym)) (current-component (gensym)) (result (gensym)) (key-val key) - (locale-val locale) + (locale-val (gensym)) (default-val default)) `#'(lambda () (let ((,current-lisplet (current-lisplet)) - (,current-page (current-page)) - (,current-component (current-component)) - (,result)) + (,current-page (current-page)) + (,current-component (current-component)) + (,locale-val ,locale) + (,result)) + (log-message :info "LISPLET: ~a; PAGE: ~a; COMPONENT: ~a" + ,current-lisplet + ,current-page + ,current-component) (when ,current-lisplet + (log-message :info "CALLING (message-dispatch ~a ~a ~a)" ,current-lisplet ,key-val ,locale-val) (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) (when (and (null ,result) ,current-page) (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) (when (and (null ,result) ,current-component) - (setf ,result (message-dispatch ,current-component ,key-val ,locale-val))) - (when (and (null ,result) (> (length ,locale-val) 2)) - (setf ,locale-val (subseq ,locale-val 0 2)) - (when ,current-lisplet - (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) - (when (and (null ,result) ,current-page) - (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) - (when (and (null ,result) ,current-component) - (setf ,result (message-dispatch ,current-component ,key-val ,locale-val)))) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val))) (when (null ,result) (setf ,locale-val "") (when ,current-lisplet Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Wed Mar 12 15:20:24 2008 @@ -275,7 +275,12 @@ :page-current-component :user-in-role-p :login - :message + ;;i18n + :message-dispatcher + :message-dispatch + :simple-message-dispatcher + :simple-message-dispatcher-add-message + :with-message ;;validation :translator :translator-integer Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Wed Mar 12 15:20:24 2008 @@ -214,6 +214,9 @@ - WCOMPONENT is the tag instance - PAGE the page instance")) +(defgeneric simple-message-dispatcher-add-message (simple-message-dispatcher locale key value) + (:documentation "Adds a key value pair to a given locale for message translation")) + (defvar *html-4.01-strict* "" "Page doctype as HTML 4.01 STRICT") @@ -326,6 +329,10 @@ (defclass message-dispatcher () ()) +(defclass simple-message-dispatcher (message-dispatcher) + ((locales :initform (make-hash-table :test #'equal) + :accessor simple-message-dispatcher-locales))) + (defclass i18n-aware (message-dispatcher) ((message-dispatcher :initarg :message-dispatcher :accessor message-dispatcher @@ -577,9 +584,9 @@ (let ((body (page-content page)) (jsonp (page-json-id-list page))) (if (null body) - ;(format nil "null body for page ~a~%" (type-of page)) - (setf (current-page) page) + (format nil "null body for page ~a~%" (type-of page)) (progn + (setf (current-page) page) (page-init page) (when (page-req-parameter page *rewind-parameter*) (htcomponent-rewind body page)) @@ -728,7 +735,7 @@ (when child-tag (cond ((stringp child-tag) (htcomponent-render ($> child-tag) page)) - ((functionp child-tag) (funcall child-tag)) + ((functionp child-tag) (htcomponent-render ($> (funcall child-tag)) page)) (t (htcomponent-render child-tag page))))) (when (null previous-print-status) (setf (page-can-print page) nil) @@ -793,11 +800,13 @@ (htcomponent-json-print-start-component tag)) (when (or (page-can-print page) previous-print-status) (tag-render-starttag tag page)) + (when (string-equal "messaged" (htcomponent-client-id tag)) + (log-message :info "RENDEING ~a: body ~a" (htcomponent-client-id tag) body-list)) (dolist (child-tag body-list) - (when child-tag - (cond + (when child-tag + (cond ((stringp child-tag) (htcomponent-render ($> child-tag) page)) - ((functionp child-tag) (funcall child-tag)) + ((functionp child-tag) (htcomponent-render ($> (funcall child-tag)) page)) (t (htcomponent-render child-tag page))))) (when (or (page-can-print page) previous-print-status) (tag-render-endtag tag page)) @@ -815,7 +824,7 @@ (when child-tag (cond ((stringp child-tag) (htcomponent-render ($> child-tag) page)) - ((functionp child-tag) (funcall child-tag)) + ((functionp child-tag) (htcomponent-render ($> (funcall child-tag)) page)) (t (htcomponent-render child-tag page))))) (dolist (injection injections) (when injection @@ -876,7 +885,7 @@ (when element (cond ((stringp element) (htcomponent-render ($> element) page)) - ((functionp element) (funcall element)) + ((functionp element) (htcomponent-render ($> (funcall element)) page)) (t (htcomponent-render element page))))) (if (null xml-p) (page-format page "~%//-->") @@ -918,7 +927,7 @@ (when child-tag (cond ((stringp child-tag) (htcomponent-render ($> child-tag) page)) - ((functionp child-tag) (funcall child-tag)) + ((functionp child-tag) (htcomponent-render ($> (funcall child-tag)) page)) (t (htcomponent-render child-tag page))))) (when (page-can-print page) (htcomponent-render (htbody-init-scripts-tag page) page) @@ -1095,7 +1104,7 @@ (when child-tag (cond ((stringp child-tag) (htcomponent-render ($> child-tag) page)) - ((functionp child-tag) (funcall child-tag)) + ((functionp child-tag) (htcomponent-render ($> (funcall child-tag)) page)) (t (htcomponent-render child-tag page))))) (wcomponent-after-render wcomponent page) (when (null previous-print-status) @@ -1137,6 +1146,13 @@ (setf result (message-dispatch dispatcher (subseq key 0 2) locale))))) result)) - - +(defmethod simple-message-dispatcher-add-message ((simple-message-dispatcher simple-message-dispatcher) locale key value) + (let ((current-locale (gethash locale (simple-message-dispatcher-locales simple-message-dispatcher) (make-hash-table :test #'equal)))) + (setf (gethash key current-locale) value) + (setf (gethash locale (simple-message-dispatcher-locales simple-message-dispatcher)) current-locale))) + +(defmethod message-dispatch ((simple-message-dispatcher simple-message-dispatcher) key locale) + (let ((current-locale (gethash locale (simple-message-dispatcher-locales simple-message-dispatcher)))) + (when current-locale + (gethash key current-locale)))) Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Wed Mar 12 15:20:24 2008 @@ -35,11 +35,22 @@ (setf *clawserver-base-path* "/claw") +(defvar *lisplet-messages* + (make-instance 'simple-message-dispatcher)) + +(simple-message-dispatcher-add-message *lisplet-messages* "en" "NAME" "Name") +(simple-message-dispatcher-add-message *lisplet-messages* "en" "SURNAME" "Surname") + +(simple-message-dispatcher-add-message *lisplet-messages* "it" "NAME" "Nome") +(simple-message-dispatcher-add-message *lisplet-messages* "it" "SURNAME" "Cognome") + (defvar *test-lisplet*) -(setf *test-lisplet* (make-instance 'lisplet :realm "test1" :base-path "/test")) +(setf *test-lisplet* (make-instance 'lisplet :realm "test1" :base-path "/test" + ));:message-dispatcher *lisplet-messages*)) (defvar *test-lisplet2*) -(setf *test-lisplet2* (make-instance 'lisplet :realm "test2" :base-path "/test2")) +(setf *test-lisplet2* (make-instance 'lisplet :realm "test2" :base-path "/test2" + ));:message-dispatcher *lisplet-messages*)) ;;(defparameter *clawserver* (make-instance 'clawserver :port 4242)) @@ -312,6 +323,7 @@ :colors nil :gender '("M") :age 1800 + :message-dispatcher *lisplet-messages* :user (make-instance 'user))) (defmethod form-page-update-user ((form-page form-page)) @@ -341,8 +353,8 @@ :validator #'(lambda (value) (validator-required (page-current-component o) value)) :accessor 'form-page-name)"*")) - (tr> - (td> "Surname") + (tr> :id "messaged" + (td> (with-message "SURNAME" "it")) (td> (cinput> :id "surname" :type "text" From achiumenti at common-lisp.net Fri Mar 14 07:57:31 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Fri, 14 Mar 2008 02:57:31 -0500 (EST) Subject: [claw-cvs] r17 - in trunk/main/claw-core: src tests Message-ID: <20080314075731.49DADD00C@common-lisp.net> Author: achiumenti Date: Fri Mar 14 02:57:28 2008 New Revision: 17 Modified: trunk/main/claw-core/src/misc.lisp trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/tags.lisp trunk/main/claw-core/tests/test1.lisp Log: beginning of translators and i18n support Modified: trunk/main/claw-core/src/misc.lisp ============================================================================== --- trunk/main/claw-core/src/misc.lisp (original) +++ trunk/main/claw-core/src/misc.lisp Fri Mar 14 02:57:28 2008 @@ -144,7 +144,7 @@ (t (push element result)))) (nreverse result))) -(defmacro with-message (key locale &optional (default "")) +(defmacro with-message (key &optional (default "") locale) (let ((current-lisplet (gensym)) (current-page (gensym)) (current-component (gensym)) @@ -157,28 +157,43 @@ (,current-page (current-page)) (,current-component (current-component)) (,locale-val ,locale) - (,result)) - (log-message :info "LISPLET: ~a; PAGE: ~a; COMPONENT: ~a" - ,current-lisplet - ,current-page - ,current-component) - (when ,current-lisplet - (log-message :info "CALLING (message-dispatch ~a ~a ~a)" ,current-lisplet ,key-val ,locale-val) - (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) - (when (and (null ,result) ,current-page) - (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) - (when (and (null ,result) ,current-component) - (setf ,result (message-dispatch ,current-component ,key-val ,locale-val))) - (when (null ,result) - (setf ,locale-val "") + (,result)) + (unless ,locale-val + (setf ,locale-val (user-locale))) (when ,current-lisplet (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) (when (and (null ,result) ,current-page) (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) (when (and (null ,result) ,current-component) - (setf ,result (message-dispatch ,current-component ,key-val ,locale-val)))) - (if ,result - ,result - ,default-val))))) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val))) + (when (null ,result) + (setf ,locale-val "") + (when ,current-lisplet + (setf ,result (message-dispatch ,current-lisplet ,key-val ,locale-val))) + (when (and (null ,result) ,current-page) + (setf ,result (message-dispatch ,current-page ,key-val ,locale-val))) + (when (and (null ,result) ,current-component) + (setf ,result (message-dispatch ,current-component ,key-val ,locale-val)))) + (if ,result + ,result + ,default-val))))) - \ No newline at end of file + +(defun user-locale (&optional (request *request*) (session *session*)) + (let ((locale (when session + (session-value 'locale session)))) + (unless locale + (setf locale (first (loop for str in (all-matches-as-strings + "[A-Z|a-z|_]+" + (regex-replace-all "-" (regex-replace-all ";.*" (header-in "ACCEPT-LANGUAGE" request) "") "_")) + collect (if (> (length str) 2) + (string-upcase str :start 2) + str))))) + locale)) + +(defun (setf user-locale) (locale &optional (session *session*)) + (unless session + (setf session (lisplet-start-session))) + (setf (session-value 'locale session) locale)) + + Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Fri Mar 14 02:57:28 2008 @@ -272,6 +272,7 @@ :current-realm :current-page :current-component + :user-locale :page-current-component :user-in-role-p :login Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Fri Mar 14 02:57:28 2008 @@ -389,7 +389,7 @@ :url nil) (:documentation "A page object holds claw components to be rendered") ) -(defclass htcomponent () +(defclass htcomponent (i18n-aware) ((page :initarg :page :reader htcomponent-page :documentation "The owner page") (body :initarg :body @@ -431,6 +431,8 @@ (:default-initargs :raw nil) (:documentation "Component needed to render strings")) + + (defmethod initialize-instance :after ((inst tag) &rest keys) (let ((emptyp (getf keys :empty)) (body (getf keys :body))) @@ -943,7 +945,7 @@ js)) ;;;========= WCOMPONENT =================================== -(defclass wcomponent (htcomponent i18n-aware) +(defclass wcomponent (htcomponent) ((parameters :initarg :parameters :accessor wcomponent-parameters :type cons @@ -1142,8 +1144,8 @@ (when dispatcher (progn (setf result (message-dispatch dispatcher key locale)) - (when (and (null result) (> (length key) 2)) - (setf result (message-dispatch dispatcher (subseq key 0 2) locale))))) + (when (and (null result) (> (length locale) 2)) + (setf result (message-dispatch dispatcher key (subseq locale 0 2)))))) result)) (defmethod simple-message-dispatcher-add-message ((simple-message-dispatcher simple-message-dispatcher) locale key value) Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Fri Mar 14 02:57:28 2008 @@ -354,7 +354,7 @@ (validator-required (page-current-component o) value)) :accessor 'form-page-name)"*")) (tr> :id "messaged" - (td> (with-message "SURNAME" "it")) + (td> (with-message "SURNAME" "SURNAME")) (td> (cinput> :id "surname" :type "text" From achiumenti at common-lisp.net Mon Mar 17 19:57:50 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Mon, 17 Mar 2008 14:57:50 -0500 (EST) Subject: [claw-cvs] r18 - in trunk/main/claw-core: src tests Message-ID: <20080317195750.E98B07C071@common-lisp.net> Author: achiumenti Date: Mon Mar 17 14:57:50 2008 New Revision: 18 Modified: trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/validators.lisp trunk/main/claw-core/tests/test1.lisp Log: added translator-number Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Mon Mar 17 14:57:50 2008 @@ -285,6 +285,7 @@ ;;validation :translator :translator-integer + :translator-number :translator-encode :translator-decode :*simple-translator* Modified: trunk/main/claw-core/src/validators.lisp ============================================================================== --- trunk/main/claw-core/src/validators.lisp (original) +++ trunk/main/claw-core/src/validators.lisp Mon Mar 17 14:57:50 2008 @@ -56,6 +56,7 @@ (defmethod translator-decode ((translator translator) (wcomponent wcomponent)) (multiple-value-bind (client-id new-value) (component-id-and-value wcomponent) + (declare (ignore client-id)) new-value)) (defvar *simple-translator* (make-instance 'translator)) @@ -99,12 +100,13 @@ (let* ((thousand-separator (translator-thousand-separator translator))) (multiple-value-bind (client-id new-value) (component-id-and-value wcomponent) + (declare (ignore client-id)) (if thousand-separator (parse-integer (regex-replace-all (format nil "~a" thousand-separator) new-value "")) (parse-integer new-value))))) ;;========================================= -#| + (defclass translator-number (translator) ((thousand-separator :initarg :thousand-separator :reader translator-thousand-separator) @@ -113,13 +115,17 @@ (decimal-digits :initarg :decimal-digits :reader translator-decimal-digits) (always-show-signum :initarg :always-show-signum - :reader translator-always-show-signum)) + :reader translator-always-show-signum) + (coerce :initarg :coerce + :accessor translator-coerce)) (:default-initargs :thousand-separator nil :decimals-separator #\. - :integer-digits nil + ;:integer-digits nil :decimal-digits nil - :always-show-signum nil) + :always-show-signum nil + :coerce 'ratio) (:documentation "a translator object encodes and decodes integer values passed to a html input component")) + (defmethod translator-encode ((translator translator-number) (wcomponent wcomponent)) (let* ((page (htcomponent-page wcomponent)) (visit-object (wcomponent-parameter-value wcomponent :visit-object)) @@ -145,24 +151,40 @@ (floor (cond ((and (null reader) accessor) (funcall (fdefinition accessor) visit-object)) (t (funcall (fdefinition reader) visit-object)))) + (progn + (setf dec-value (coerce dec-value 'float)) (format nil "~a~a" (if thousand-separator - (string-trim " " (format nil control-string thousand-separator int-value)) - (format nil control-string int-value)) + (string-trim " " (format nil integer-control-string thousand-separator int-value)) + (format nil integer-control-string int-value)) (cond ((and (= 0.0 (coerce dec-value 'double-float)) decimal-digits) - (format "~a~a" decimals-separator (make-string decimal-digits #\0))) + (format nil "~a~a" decimals-separator (make-string decimal-digits :initial-element #\0))) (decimal-digits - (format "~a~a" decimals-separator (make-string decimal-digits #\0)) + (let ((frac-part (subseq (format nil "~f" dec-value) 2))) + (if (> (length frac-part) decimal-digits) + (setf frac-part (subseq frac-part 0 decimal-digits)) + (setf frac-part (concatenate 'string frac-part (make-string (- decimal-digits (length frac-part)) :initial-element #\0)))) + (format nil "~a~a" decimals-separator frac-part))) + (t (format nil "~a~a" decimals-separator (subseq (format nil "~f" dec-value) 2))))))))))) + (defmethod translator-decode ((translator translator-number) (wcomponent wcomponent)) - (let* ((thousand-separator (translator-thousand-separator translator))) - (multiple-value-bind (client-id new-value) + (let* ((thousand-separator (translator-thousand-separator translator)) + (type (translator-coerce translator)) + (int-value) + (dec-value)) + (multiple-value-bind (client-id new-value) (component-id-and-value wcomponent) - (if thousand-separator - (parse-integer (regex-replace-all (format nil "~a" thousand-separator) new-value "")) - (parse-integer new-value))))) + (declare (ignore client-id)) + (when thousand-separator + (setf new-value (regex-replace-all (format nil "~a" thousand-separator) new-value ""))) + (let ((decomposed-string (all-matches-as-strings "[0-9]+" new-value))) + (setf int-value (parse-integer (concatenate 'string (first decomposed-string) (second decomposed-string)))) + (setf dec-value (expt 10 (length (second decomposed-string)))) + (coerce (/ int-value dec-value) type))))) + + -|# ;;---------------------------------------------------------------------------------------- (defun add-exception (id reason) (let* ((validation-errors (aux-request-value :validation-errors)) @@ -218,11 +240,19 @@ (or (when min (validate (>= value min) :component component - :message (format nil "Field ~a is not greater then or equal to ~d" (wcomponent-parameter-value component :label) min))) + :message (format nil "Field ~a is not greater then or equal to ~d" + (wcomponent-parameter-value component :label) + (if (typep min 'ratio) + (coerce min 'float) + min)))) (when max (validate (<= value max) :component component - :message (format nil "Field ~a is not less then or equal to ~d" (wcomponent-parameter-value component :label) max)))))) + :message (format nil "Field ~a is not less then or equal to ~d" + (wcomponent-parameter-value component :label) + (if (typep max 'ratio) + (coerce max 'float) + max))))))) (defun validator-number (component value &key min max) (when value @@ -259,15 +289,3 @@ collect (li> message))))))) ;;------------------------------------------------------------------------------------------- - -#| -(defmacro with-validators (&rest rest) - (let* ((component (gensym)) - (value (gensym)) - (validators (loop for validator in rest - collect (list 'funcall validator component value)))) - `#'(lambda (,value) - (let ((,component (current-component))) - (or , at validators))))) -|# - Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Mon Mar 17 14:57:50 2008 @@ -299,8 +299,10 @@ (gender :initarg :gender :accessor user-gender) (age :initarg :age - :accessor user-age)) - (:default-initargs :name "" :surname "" :gender "" :age "")) + :accessor user-age) + (capital :initarg :capital + :accessor user-capital)) + (:default-initargs :name "" :surname "" :gender "" :age "" :capital 0.0)) (defgeneric form-page-update-user (form-page)) @@ -317,12 +319,15 @@ (user :initarg :user :accessor form-page-user) (age :initarg :age - :accessor form-page-age)) + :accessor form-page-age) + (capital :initarg :capital + :accessor form-page-capital)) (:default-initargs :name "kiuma" :surname "surnk" :colors nil :gender '("M") :age 1800 + :capital 500055/100 :message-dispatcher *lisplet-messages* :user (make-instance 'user))) @@ -388,6 +393,20 @@ (validator-integer component value :min 1 :max 2000))) :accessor 'form-page-age)"*")) (tr> + (td> "Capital") + (td> + (cinput> :id "capital" + :type "text" + :label "Capital" + :translator (make-instance 'translator-number + :decimal-digits 4 + :thousand-separator #\') + :validator #'(lambda (value) + (let ((component (page-current-component o))) + (validator-required component value) + (validator-number component value :min 1000.01 :max 500099/100))) + :accessor 'form-page-capital)"*")) + (tr> (td> "Colors") (td> (cselect> :id "colors" From achiumenti at common-lisp.net Tue Mar 25 10:55:14 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 25 Mar 2008 05:55:14 -0500 (EST) Subject: [claw-cvs] r20 - trunk/main/claw-core/generators Message-ID: <20080325105514.D88EB1B000@common-lisp.net> Author: achiumenti Date: Tue Mar 25 05:55:14 2008 New Revision: 20 Added: trunk/main/claw-core/generators/ trunk/main/claw-core/generators/GenerateLocales.java Log: continuning on l13n Added: trunk/main/claw-core/generators/GenerateLocales.java ============================================================================== --- (empty file) +++ trunk/main/claw-core/generators/GenerateLocales.java Tue Mar 25 05:55:14 2008 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.io.IOException; +import java.text.DateFormatSymbols; +import java.text.DecimalFormatSymbols; +import java.util.Calendar; +import java.util.Locale; +import java.io.File; +import java.io.FileWriter; +import java.io.StringWriter; + +/** + * + * @author Andrea Chiumenti + */ +public class GenerateLocales { + + private StringWriter sw; + private String fileName; + + public GenerateLocales() { + fileName = "locales.lisp"; + } + + public void generateFile(String fileName) throws IOException { + sw = new StringWriter(); + //sw.append("(defvar *locales* (make-hash-table :test 'equal))\n"); + sw.append(";;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-\n"). + append(";;; $Header: src/locales.lisp $\n"). + append("\n"). + append(";;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved.\n"). + append("\n"). + append(";;; Redistribution and use in source and binary forms, with or without\n"). + append(";;; modification, are permitted provided that the following conditions\n"). + append(";;; are met:\n"). + append("\n"). + append(";;; * Redistributions of source code must retain the above copyright\n"). + append(";;; notice, this list of conditions and the following disclaimer.\n"). + append("\n"). + append(";;; * Redistributions in binary form must reproduce the above\n"). + append(";;; copyright notice, this list of conditions and the following\n"). + append(";;; disclaimer in the documentation and/or other materials\n"). + append(";;; provided with the distribution.\n"). + append("\n"). + append(";;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED\n"). + append(";;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"). + append(";;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"). + append(";;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"). + append(";;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"). + append(";;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n"). + append(";;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"). + append(";;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"). + append(";;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n"). + append(";;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"). + append(";;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"). + append(";;; --*-- AUTOMATICALLY GENERATED - DO NOT EDIT !!!!! --*--\n\n"). + append("(in-package :claw)\n\n"); + File f = new File(fileName); + if (f.exists()) { + f.delete(); + } + FileWriter fw = null; + try { + fw = new FileWriter(f); + + Locale[] locales = Locale.getAvailableLocales(); + + for (int i = 0; i < locales.length; i++) { + + DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry())); + DateFormatSymbols datefs = DateFormatSymbols.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry())); + Calendar cal = Calendar.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry())); + + String locale; + if (locales[i].getCountry().equals("")) { + locale = locales[i].getLanguage(); + } else { + locale = locales[i].getLanguage() + "_" + locales[i].getCountry().toUpperCase(); + + } + sw.append("(setf (gethash \"" + locale + + "\" *locales*)" + + "\n (list "); + sw.append("\n :NUMBER-FORMAT " + + "(list :GROUPING-SEPARATOR #\\" + dfs.getGroupingSeparator() + + " :DECIMAL-SEPARATOR #\\" + dfs.getDecimalSeparator() + + " \"" + dfs.getInternationalCurrencySymbol() + "\"" + ")"); + + sw.append("\n :DATE-FORMAT (list"); + printDateSymbols("ampm", datefs.getAmPmStrings()); + printDateSymbols("months", datefs.getMonths()); + printDateSymbols("short-months", datefs.getShortMonths()); + printDateSymbols("first-day-of-the-week", cal.getFirstDayOfWeek()); + printDateSymbols("weekdays", datefs.getWeekdays()); + printDateSymbols("short-weekdays", datefs.getShortWeekdays()); + printDateSymbols("eras", datefs.getEras()); + + sw.append(")))\n\n"); + + } + fw.write(sw.toString()); + } finally { + if (fw != null) { + fw.close(); + } + } + System.out.println(fileName + " successfully generated."); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws IOException { + + + GenerateLocales app = new GenerateLocales(); + + if (args.length > 0) { + String arg0 = args[0]; + if (arg0.equals("--help")) { + app.printUsage(); + return; + } + } + + app.generateFile(app.fileName); + } + + private void printUsage() { + System.out.println("Usage:"); + System.out.println(" java " + GenerateLocales.class.getSimpleName() + + " --help (prints usage)"); + System.out.println(" java " + GenerateLocales.class.getSimpleName() + + " (generates output file)"); + } + + private void printDateSymbols(String symbol, String[] vals) { + sw.append("\n :" + + symbol.toUpperCase() + + " '("); + int i = 0; + for (int x = 0; x < vals.length; x++) { + if (!vals[x].equals("")) { + if (i > 0) { + sw.append(" "); + } + sw.append("\"" + + vals[x] + + "\""); + i++; + } + } + sw.append(")"); + } + + private void printDateSymbols(String symbol, Number val) { + sw.append("\n :" + + symbol.toUpperCase() + + " " + val); + + } + + public String getFileName() { + return fileName; + } +} From achiumenti at common-lisp.net Tue Mar 25 10:54:19 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 25 Mar 2008 05:54:19 -0500 (EST) Subject: [claw-cvs] r19 - in trunk/main/claw-core: . src Message-ID: <20080325105419.D326771123@common-lisp.net> Author: achiumenti Date: Tue Mar 25 05:54:19 2008 New Revision: 19 Added: trunk/main/claw-core/src/i18n.lisp trunk/main/claw-core/src/locales.lisp Modified: trunk/main/claw-core/claw.asd trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/validators.lisp Log: continuning on l13n Modified: trunk/main/claw-core/claw.asd ============================================================================== --- trunk/main/claw-core/claw.asd (original) +++ trunk/main/claw-core/claw.asd Tue Mar 25 05:54:19 2008 @@ -31,10 +31,12 @@ :name "claw" :author "Andrea Chiumenti" :description "Common Lisp Active Web.A famework to write web applications" - :depends-on (:hunchentoot :alexandria :cl-ppcre :cl-fad) + :depends-on (:hunchentoot :alexandria :cl-ppcre :cl-fad :local-time) :components ((:module src :components ((:file "packages") (:file "misc" :depends-on ("packages")) + (:file "i18n" :depends-on ("packages")) + (:file "locales" :depends-on ("i18n")) (:file "hunchentoot-overrides" :depends-on ("packages")) (:file "tags" :depends-on ("misc")) (:file "validators" :depends-on ("tags")) Added: trunk/main/claw-core/src/i18n.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-core/src/i18n.lisp Tue Mar 25 05:54:19 2008 @@ -0,0 +1,111 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: src/components.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :claw) + +(defgeneric local-time-add (local-time field value) + (:documentation "Adds the specified amount of VALUE to the LOCAL_TIME. +FIELD may be any of: +* 'NSEC nano-seconds +* 'MSEC milli-seconds +* 'SEC seconds +* 'MIN minutes +* 'HR hours +* 'DAYS days +* 'MONTH month +* 'YEARS years. +And other FIELD value will produce an error condition.")) + + +(defvar *locales* (make-hash-table :test 'equal)) + +(defun number-format-grouping-separator (&optional (locale (user-locale))) + (getf (getf (gethash locale *locales*) :number-format) :grouping-separator)) + +(defun number-format-decimal-separator (&optional (locale (user-locale))) + (getf (getf (gethash locale *locales*) :number-format) :decimal-separator)) + +(defun ampm (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :ampm)) + +(defun months (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :months)) + +(defun short-months (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :short-months)) + +(defun first-day-of-the-week (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :first-day-of-the-week)) + +(defun weekdays (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :weekdays)) + +(defun short-weekdays (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :short-weekdays)) + +(defun eras (&optional (locale (user-locale))) + (getf (gethash locale *locales*) :eras)) + + +(defun local-time-add-year (local-time value) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (encode-local-time ns ss mm hh day month (+ year value)))) + +(defun local-time-add-month (local-time value) + (multiple-value-bind (d-month d-year) + (floor (abs value) 12) + (when (< value 0) + (setf d-month (* d-month -1) + d-year (* d-year -1)) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (multiple-value-bind (ns ss mm hh day month-ignore year) + (decode-local-time (encode-local-time ns ss mm hh day 1 (+ year d-year))) + (encode-local-time ns ss mm hh day month year)))))) + +(defun local-time-add-day (local-time value) + (let* ((curr-day (day-of local-time)) + (local-time-result (make-instance 'local-time + :day curr-day + :sec (sec-of local-time) + :nsec (nsec-of local-time) + :time-zone (timezone-of local-time)))) + (setf (day-of local-time-result) (+ curr-day value)) + local-time-result)) + +(defun local-time-add-hour (local-time value) + (multiple-value-bind (d-hour d-day) + (floor (abs value) 24) + +#| +(defmethod local-time-add ((local-time local-time) field value) + (ccase field + ('NSEC +|# \ No newline at end of file Added: trunk/main/claw-core/src/locales.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-core/src/locales.lisp Tue Mar 25 05:54:19 2008 @@ -0,0 +1,1857 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: src/locales.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; --*-- AUTOMATICALLY GENERATED - DO NOT EDIT !!!!! --*-- + +(in-package :claw) + +(setf (gethash "ja_JP" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "JPY") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :SHORT-MONTHS '("1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???" "??")))) + +(setf (gethash "es_PE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "PEN") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "en" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "ja_JP" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "JPY") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :SHORT-MONTHS '("1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???" "??")))) + +(setf (gethash "es_PA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "PAB") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "sr_BA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "BAM") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "?????" "???" "????" "????" "??????" "?????????" "???????" "????????" "????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "??????" "???????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?. ?. ?." "?. ?")))) + +(setf (gethash "mk" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("???????" "????????" "????" "?????" "???" "????" "????" "??????" "?????????" "????????" "???????" "????????") + :SHORT-MONTHS '("???." "???." "???." "???." "???." "???." "???." "???." "????." "???." "????." "?????.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????" "??????????" "???????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???." "???." "??." "???." "???." "???." "???.") + :ERAS '("??.?.?." "??.")))) + +(setf (gethash "es_GT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "GTQ") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_AE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "AED") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "no_NO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "NOK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "mars" "april" "mai" "juni" "juli" "august" "september" "oktober" "november" "desember") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "mai" "jun" "jul" "aug" "sep" "okt" "nov" "des") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "mandag" "tirsdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "ma" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "sq_AL" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "ALL") + :DATE-FORMAT (list + :AMPM '("PD" "MD") + :MONTHS '("janar" "shkurt" "mars" "prill" "maj" "qershor" "korrik" "gusht" "shtator" "tetor" "n?ntor" "dhjetor") + :SHORT-MONTHS '("Jan" "Shk" "Mar" "Pri" "Maj" "Qer" "Kor" "Gsh" "Sht" "Tet" "N?n" "Dhj") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("e diel" "e h?n?" "e mart?" "e m?rkur?" "e enjte" "e premte" "e shtun?") + :SHORT-WEEKDAYS '("Die" "H?n" "Mar" "M?r" "Enj" "Pre" "Sht") + :ERAS '("p.e.r." "n.e.r.")))) + +(setf (gethash "bg" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "????????" "????" "?????" "???" "???" "???" "??????" "?????????" "????????" "???????" "????????") + :SHORT-MONTHS '("I" "II" "III" "IV" "V" "VI" "VII" "VIII" "IX" "X" "XI" "XII") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????" "??????????" "???????" "?????" "?????????" "?????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("??.?.?." "?.?.")))) + +(setf (gethash "ar_IQ" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "IQD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "ar_YE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "YER") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "hu" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("DE" "DU") + :MONTHS '("janu?r" "febru?r" "m?rcius" "?prilis" "m?jus" "j?nius" "j?lius" "augusztus" "szeptember" "okt?ber" "november" "december") + :SHORT-MONTHS '("jan." "febr." "m?rc." "?pr." "m?j." "j?n." "j?l." "aug." "szept." "okt." "nov." "dec.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("vas?rnap" "h?tf?" "kedd" "szerda" "cs?t?rt?k" "p?ntek" "szombat") + :SHORT-WEEKDAYS '("V" "H" "K" "Sze" "Cs" "P" "Szo") + :ERAS '("i.e." "i.u.")))) + +(setf (gethash "pt_PT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Janeiro" "Fevereiro" "Mar?o" "Abril" "Maio" "Junho" "Julho" "Agosto" "Setembro" "Outubro" "Novembro" "Dezembro") + :SHORT-MONTHS '("Jan" "Fev" "Mar" "Abr" "Mai" "Jun" "Jul" "Ago" "Set" "Out" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Domingo" "Segunda-feira" "Ter?a-feira" "Quarta-feira" "Quinta-feira" "Sexta-feira" "S?bado") + :SHORT-WEEKDAYS '("Dom" "Seg" "Ter" "Qua" "Qui" "Sex" "S?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "el_CY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "CYP") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??????????" "???????????" "???????" "????????" "?????" "???????" "???????" "?????????" "???????????" "?????????" "?????????" "??????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "????" "????" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("???????" "???????" "?????" "???????" "??????" "?????????" "???????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?.?." "?.?.")))) + +(setf (gethash "ar_QA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "QAR") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "mk_MK" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "MKD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("???????" "????????" "????" "?????" "???" "????" "????" "??????" "?????????" "????????" "???????" "????????") + :SHORT-MONTHS '("???." "???." "???." "???." "???." "???." "???." "???." "????." "???." "????." "?????.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????" "??????????" "???????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???." "???." "??." "???." "???." "???." "???.") + :ERAS '("??.?.?." "??.")))) + +(setf (gethash "sv" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januari" "februari" "mars" "april" "maj" "juni" "juli" "augusti" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "m?ndag" "tisdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "m?" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "de_CH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\' :DECIMAL-SEPARATOR #\. "CHF") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januar" "Februar" "M?rz" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember") + :SHORT-MONTHS '("Jan" "Feb" "Mrz" "Apr" "Mai" "Jun" "Jul" "Aug" "Sep" "Okt" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag") + :SHORT-WEEKDAYS '("So" "Mo" "Di" "Mi" "Do" "Fr" "Sa") + :ERAS '("v. Chr." "n. Chr.")))) + +(setf (gethash "en_US" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "USD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "fi_FI" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("tammikuu" "helmikuu" "maaliskuu" "huhtikuu" "toukokuu" "kes?kuu" "hein?kuu" "elokuu" "syyskuu" "lokakuu" "marraskuu" "joulukuu") + :SHORT-MONTHS '("tammi" "helmi" "maalis" "huhti" "touko" "kes?" "hein?" "elo" "syys" "loka" "marras" "joulu") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("sunnuntai" "maanantai" "tiistai" "keskiviikko" "torstai" "perjantai" "lauantai") + :SHORT-WEEKDAYS '("su" "ma" "ti" "ke" "to" "pe" "la") + :ERAS '("BC" "AD")))) + +(setf (gethash "is" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("jan?ar" "febr?ar" "mars" "apr?l" "ma?" "j?n?" "j?l?" "?g?st" "september" "okt?ber" "n?vember" "desember") + :SHORT-MONTHS '("jan." "feb." "mar." "apr." "ma?" "j?n." "j?l." "?g?." "sep." "okt." "n?v." "des.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("sunnudagur" "m?nudagur" "?ri?judagur" "mi?vikudagur" "fimmtudagur" "f?studagur" "laugardagur") + :SHORT-WEEKDAYS '("sun." "m?n." "?ri." "mi?." "fim." "f?s." "lau.") + :ERAS '("BC" "AD")))) + +(setf (gethash "cs" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("dop." "odp.") + :MONTHS '("leden" "?nor" "b?ezen" "duben" "kv?ten" "?erven" "?ervenec" "srpen" "z???" "??jen" "listopad" "prosinec") + :SHORT-MONTHS '("I" "II" "III" "IV" "V" "VI" "VII" "VIII" "IX" "X" "XI" "XII") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Ned?le" "Pond?l?" "?ter?" "St?eda" "?tvrtek" "P?tek" "Sobota") + :SHORT-WEEKDAYS '("Ne" "Po" "?t" "St" "?t" "P?" "So") + :ERAS '("p?.Kr." "po Kr.")))) + +(setf (gethash "en_MT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "MTL") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "sl_SI" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "marec" "april" "maj" "junij" "julij" "avgust" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "avg" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Nedelja" "Ponedeljek" "Torek" "Sreda" "?etrtek" "Petek" "Sobota") + :SHORT-WEEKDAYS '("Ned" "Pon" "Tor" "Sre" "?et" "Pet" "Sob") + :ERAS '("pr.n.?." "po Kr.")))) + +(setf (gethash "sk_SK" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "SKK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janu?r" "febru?r" "marec" "apr?l" "m?j" "j?n" "j?l" "august" "september" "okt?ber" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "m?j" "j?n" "j?l" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Nede?a" "Pondelok" "Utorok" "Streda" "?tvrtok" "Piatok" "Sobota") + :SHORT-WEEKDAYS '("Ne" "Po" "Ut" "St" "?t" "Pi" "So") + :ERAS '("pred n.l." "n.l.")))) + +(setf (gethash "it" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("gennaio" "febbraio" "marzo" "aprile" "maggio" "giugno" "luglio" "agosto" "settembre" "ottobre" "novembre" "dicembre") + :SHORT-MONTHS '("gen" "feb" "mar" "apr" "mag" "giu" "lug" "ago" "set" "ott" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domenica" "luned?" "marted?" "mercoled?" "gioved?" "venerd?" "sabato") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mer" "gio" "ven" "sab") + :ERAS '("BC" "dopo Cristo")))) + +(setf (gethash "tr_TR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "TRY") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Ocak" "?ubat" "Mart" "Nisan" "May?s" "Haziran" "Temmuz" "A?ustos" "Eyl?l" "Ekim" "Kas?m" "Aral?k") + :SHORT-MONTHS '("Oca" "?ub" "Mar" "Nis" "May" "Haz" "Tem" "A?u" "Eyl" "Eki" "Kas" "Ara") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Pazar" "Pazartesi" "Sal?" "?ar?amba" "Per?embe" "Cuma" "Cumartesi") + :SHORT-WEEKDAYS '("Paz" "Pzt" "Sal" "?ar" "Per" "Cum" "Cmt") + :ERAS '("BC" "AD")))) + +(setf (gethash "zh" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :SHORT-MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("???" "??")))) + +(setf (gethash "th" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("??????????" "??????????") + :MONTHS '("??????" "??????????" "??????" "??????" "???????" "????????" "???????" "???????" "???????" "??????" "?????????" "???????") + :SHORT-MONTHS '("?.?." "?.?." "??.?." "??.?." "?.?." "??.?." "?.?." "?.?." "?.?." "?.?." "?.?." "?.?.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????????" "?????????" "?????????" "??????" "???????????" "????????" "????????") + :SHORT-WEEKDAYS '("??." "?." "?." "?." "??." "?." "?.") + :ERAS '("??????????????????" "?.?.")))) + +(setf (gethash "ar_SA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SAR") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "no" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "mars" "april" "mai" "juni" "juli" "august" "september" "oktober" "november" "desember") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "mai" "jun" "jul" "aug" "sep" "okt" "nov" "des") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "mandag" "tirsdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "ma" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "en_GB" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "GBP") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "sr_CS" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "CSD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "?????" "???" "???" "???" "??????" "?????????" "???????" "????????" "????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "??????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?. ?. ?." "?. ?")))) + +(setf (gethash "lt" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Sausio" "Vasario" "Kovo" "Baland?io" "Gegu??s" "Bir?elio" "Liepos" "Rugpj??io" "Rugs?jo" "Spalio" "Lapkri?io" "Gruod?io") + :SHORT-MONTHS '("Sau" "Vas" "Kov" "Bal" "Geg" "Bir" "Lie" "Rgp" "Rgs" "Spa" "Lap" "Grd") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sekmadienis" "Pirmadienis" "Antradienis" "Tre?iadienis" "Ketvirtadienis" "Penktadienis" "?e?tadienis") + :SHORT-WEEKDAYS '("Sk" "Pr" "An" "Tr" "Kt" "Pn" "?t") + :ERAS '("pr.Kr." "po.Kr.")))) + +(setf (gethash "ro" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("ianuarie" "februarie" "martie" "aprilie" "mai" "iunie" "iulie" "august" "septembrie" "octombrie" "noiembrie" "decembrie") + :SHORT-MONTHS '("Ian" "Feb" "Mar" "Apr" "Mai" "Iun" "Iul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("duminic?" "luni" "mar?i" "miercuri" "joi" "vineri" "s?mb?t?") + :SHORT-WEEKDAYS '("D" "L" "Ma" "Mi" "J" "V" "S") + :ERAS '("d.C." "?.d.C.")))) + +(setf (gethash "en_NZ" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "NZD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "no_NO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "NOK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "mars" "april" "mai" "juni" "juli" "august" "september" "oktober" "november" "desember") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "mai" "jun" "jul" "aug" "sep" "okt" "nov" "des") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "mandag" "tirsdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "ma" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "lt_LT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "LTL") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Sausio" "Vasario" "Kovo" "Baland?io" "Gegu??s" "Bir?elio" "Liepos" "Rugpj??io" "Rugs?jo" "Spalio" "Lapkri?io" "Gruod?io") + :SHORT-MONTHS '("Sau" "Vas" "Kov" "Bal" "Geg" "Bir" "Lie" "Rgp" "Rgs" "Spa" "Lap" "Grd") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sekmadienis" "Pirmadienis" "Antradienis" "Tre?iadienis" "Ketvirtadienis" "Penktadienis" "?e?tadienis") + :SHORT-WEEKDAYS '("Sk" "Pr" "An" "Tr" "Kt" "Pn" "?t") + :ERAS '("pr.Kr." "po.Kr.")))) + +(setf (gethash "es_NI" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "NIO") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "nl" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januari" "februari" "maart" "april" "mei" "juni" "juli" "augustus" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mrt" "apr" "mei" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("zondag" "maandag" "dinsdag" "woensdag" "donderdag" "vrijdag" "zaterdag") + :SHORT-WEEKDAYS '("zo" "ma" "di" "wo" "do" "vr" "za") + :ERAS '("BC" "AD")))) + +(setf (gethash "ga_IE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "EUR") + :DATE-FORMAT (list + :AMPM '("a.m." "p.m.") + :MONTHS '("Ean?ir" "Feabhra" "M?rta" "Aibre?n" "Bealtaine" "Meitheamh" "I?il" "L?nasa" "Me?n F?mhair" "Deireadh F?mhair" "Samhain" "Nollaig") + :SHORT-MONTHS '("Ean" "Feabh" "M?rta" "Aib" "Beal" "Meith" "I?il" "L?n" "MF?mh" "DF?mh" "Samh" "Noll") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("D? Domhnaigh" "D? Luain" "D? M?irt" "D? C?adaoin" "D?ardaoin" "D? hAoine" "D? Sathairn") + :SHORT-WEEKDAYS '("Domh" "Luan" "M?irt" "C?ad" "D?ar" "Aoine" "Sath") + :ERAS '("RC" "AD")))) + +(setf (gethash "fr_BE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "es_ES" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_LB" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "LBP") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("????? ??????" "????" "????" "?????" "????" "??????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :SHORT-MONTHS '("????? ??????" "????" "????" "?????" "????" "??????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :ERAS '("?.?" "?")))) + +(setf (gethash "ko" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :SHORT-MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("BC" "AD")))) + +(setf (gethash "fr_CA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "CAD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "et_EE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "EEK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Jaanuar" "Veebruar" "M?rts" "Aprill" "Mai" "Juuni" "Juuli" "August" "September" "Oktoober" "November" "Detsember") + :SHORT-MONTHS '("Jaan" "Veebr" "M?rts" "Apr" "Mai" "Juuni" "Juuli" "Aug" "Sept" "Okt" "Nov" "Dets") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("p?hap?ev" "esmasp?ev" "teisip?ev" "kolmap?ev" "neljap?ev" "reede" "laup?ev") + :SHORT-WEEKDAYS '("P" "E" "T" "K" "N" "R" "L") + :ERAS '("e.m.a." "m.a.j.")))) + +(setf (gethash "ar_KW" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "KWD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "sr_RS" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "RSD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "?????" "???" "???" "???" "??????" "?????????" "???????" "????????" "????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "??????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?. ?. ?." "?. ?")))) + +(setf (gethash "es_US" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "USD") + :DATE-FORMAT (list + :AMPM '("a.m." "p.m.") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("a.C." "d.C.")))) + +(setf (gethash "es_MX" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "MXN") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_SD" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SDD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "in_ID" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "IDR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januari" "Februari" "Maret" "April" "Mei" "Juni" "Juli" "Agustus" "September" "Oktober" "November" "Desember") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "Mei" "Jun" "Jul" "Agu" "Sep" "Okt" "Nov" "Des") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Minggu" "Senin" "Selasa" "Rabu" "Kamis" "Jumat" "Sabtu") + :SHORT-WEEKDAYS '("Min" "Sen" "Sel" "Rab" "Kam" "Jum" "Sab") + :ERAS '("BCE" "CE")))) + +(setf (gethash "ru" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "??????" "???" "????" "????" "??????" "????????" "???????" "??????" "???????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("???????????" "???????????" "???????" "?????" "???????" "???????" "???????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "?.?.")))) + +(setf (gethash "lv" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janv?ris" "febru?ris" "marts" "apr?lis" "maijs" "j?nijs" "j?lijs" "augusts" "septembris" "oktobris" "novembris" "decembris") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "Maijs" "J?n" "J?l" "Aug" "Sep" "Okt" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("sv?tdiena" "pirmdiena" "otrdiena" "tre?diena" "ceturtdiena" "piektdiena" "sestdiena") + :SHORT-WEEKDAYS '("Sv" "P" "O" "T" "C" "Pk" "S") + :ERAS '("pm?" "m?")))) + +(setf (gethash "es_UY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "UYU") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "lv_LV" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "LVL") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janv?ris" "febru?ris" "marts" "apr?lis" "maijs" "j?nijs" "j?lijs" "augusts" "septembris" "oktobris" "novembris" "decembris") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "Maijs" "J?n" "J?l" "Aug" "Sep" "Okt" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("sv?tdiena" "pirmdiena" "otrdiena" "tre?diena" "ceturtdiena" "piektdiena" "sestdiena") + :SHORT-WEEKDAYS '("Sv" "P" "O" "T" "C" "Pk" "S") + :ERAS '("pm?" "m?")))) + +(setf (gethash "iw" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("?????" "??????" "???" "?????" "???" "????" "????" "??????" "??????" "???????" "??????" "?????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??? ?????" "??? ???" "??? ?????" "??? ?????" "??? ?????" "??? ????" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???"?" "????"?")))) + +(setf (gethash "pt_BR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "BRL") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Janeiro" "Fevereiro" "Mar?o" "Abril" "Maio" "Junho" "Julho" "Agosto" "Setembro" "Outubro" "Novembro" "Dezembro") + :SHORT-MONTHS '("Jan" "Fev" "Mar" "Abr" "Mai" "Jun" "Jul" "Ago" "Set" "Out" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Domingo" "Segunda-feira" "Ter?a-feira" "Quarta-feira" "Quinta-feira" "Sexta-feira" "S?bado") + :SHORT-WEEKDAYS '("Dom" "Seg" "Ter" "Qua" "Qui" "Sex" "S?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_SY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SYP") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("????? ??????" "????" "????" "?????" "??????" "????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :SHORT-MONTHS '("????? ??????" "????" "????" "?????" "????" "??????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :ERAS '("?.?" "?")))) + +(setf (gethash "hr" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("sije?anj" "velja?a" "o?ujak" "travanj" "svibanj" "lipanj" "srpanj" "kolovoz" "rujan" "listopad" "studeni" "prosinac") + :SHORT-MONTHS '("sij" "vel" "o?u" "tra" "svi" "lip" "srp" "kol" "ruj" "lis" "stu" "pro") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("nedjelja" "ponedjeljak" "utorak" "srijeda" "?etvrtak" "petak" "subota") + :SHORT-WEEKDAYS '("ned" "pon" "uto" "sri" "?et" "pet" "sub") + :ERAS '("BC" "AD")))) + +(setf (gethash "et" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Jaanuar" "Veebruar" "M?rts" "Aprill" "Mai" "Juuni" "Juuli" "August" "September" "Oktoober" "November" "Detsember") + :SHORT-MONTHS '("Jaan" "Veebr" "M?rts" "Apr" "Mai" "Juuni" "Juuli" "Aug" "Sept" "Okt" "Nov" "Dets") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("p?hap?ev" "esmasp?ev" "teisip?ev" "kolmap?ev" "neljap?ev" "reede" "laup?ev") + :SHORT-WEEKDAYS '("P" "E" "T" "K" "N" "R" "L") + :ERAS '("e.m.a." "m.a.j.")))) + +(setf (gethash "es_DO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "DOP") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "fr_CH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\' :DECIMAL-SEPARATOR #\. "CHF") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "hi_IN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "INR") + :DATE-FORMAT (list + :AMPM '("?????????" "???????") + :MONTHS '("?????" "??????" "?????" "??????" "??" "???" "?????" "?????" "??????" "????????" "?????" "??????") + :SHORT-MONTHS '("?????" "??????" "?????" "??????" "??" "???" "?????" "?????" "??????" "????????" "?????" "??????") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????" "??????" "???????" "??????" "???????" "????????" "??????") + :SHORT-WEEKDAYS '("???" "???" "????" "???" "????" "?????" "???") + :ERAS '("????????" "??")))) + +(setf (gethash "es_VE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "VEB") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_BH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "BHD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "en_PH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "PHP") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_TN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "TND") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "fi" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("tammikuu" "helmikuu" "maaliskuu" "huhtikuu" "toukokuu" "kes?kuu" "hein?kuu" "elokuu" "syyskuu" "lokakuu" "marraskuu" "joulukuu") + :SHORT-MONTHS '("tammi" "helmi" "maalis" "huhti" "touko" "kes?" "hein?" "elo" "syys" "loka" "marras" "joulu") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("sunnuntai" "maanantai" "tiistai" "keskiviikko" "torstai" "perjantai" "lauantai") + :SHORT-WEEKDAYS '("su" "ma" "ti" "ke" "to" "pe" "la") + :ERAS '("BC" "AD")))) + +(setf (gethash "de_AT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("J?nner" "Februar" "M?rz" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember") + :SHORT-MONTHS '("J?n" "Feb" "M?r" "Apr" "Mai" "Jun" "Jul" "Aug" "Sep" "Okt" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag") + :SHORT-WEEKDAYS '("So" "Mo" "Di" "Mi" "Do" "Fr" "Sa") + :ERAS '("v. Chr." "n. Chr.")))) + +(setf (gethash "es" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "nl_NL" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januari" "februari" "maart" "april" "mei" "juni" "juli" "augustus" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mrt" "apr" "mei" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("zondag" "maandag" "dinsdag" "woensdag" "donderdag" "vrijdag" "zaterdag") + :SHORT-WEEKDAYS '("zo" "ma" "di" "wo" "do" "vr" "za") + :ERAS '("BC" "AD")))) + +(setf (gethash "es_EC" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "USD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "zh_TW" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "TWD") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :SHORT-MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("???" "??")))) + +(setf (gethash "ar_JO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "JOD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("????? ??????" "????" "????" "?????" "????" "??????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :SHORT-MONTHS '("????? ??????" "????" "????" "?????" "????" "??????" "????" "??" "?????" "????? ?????" "????? ??????" "????? ?????") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :ERAS '("?.?" "?")))) + +(setf (gethash "be" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("????????" "??????" "????????" "?????????" "???" "??????" "??????" "??????" "???????" "???????????" "?????????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???????" "??????????" "???????" "??????" "??????" "???????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "?.?.")))) + +(setf (gethash "is_IS" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "ISK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("jan?ar" "febr?ar" "mars" "apr?l" "ma?" "j?n?" "j?l?" "?g?st" "september" "okt?ber" "n?vember" "desember") + :SHORT-MONTHS '("jan." "feb." "mar." "apr." "ma?" "j?n." "j?l." "?g?." "sep." "okt." "n?v." "des.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("sunnudagur" "m?nudagur" "?ri?judagur" "mi?vikudagur" "fimmtudagur" "f?studagur" "laugardagur") + :SHORT-WEEKDAYS '("sun." "m?n." "?ri." "mi?." "fim." "f?s." "lau.") + :ERAS '("BC" "AD")))) + +(setf (gethash "es_CO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "COP") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "es_CR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "CRC") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "es_CL" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "CLP") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_EG" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "EGP") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "en_ZA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "ZAR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "th_TH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "THB") + :DATE-FORMAT (list + :AMPM '("??????????" "??????????") + :MONTHS '("??????" "??????????" "??????" "??????" "???????" "????????" "???????" "???????" "???????" "??????" "?????????" "???????") + :SHORT-MONTHS '("?.?." "?.?." "??.?." "??.?." "?.?." "??.?." "?.?." "?.?." "?.?." "?.?." "?.?." "?.?.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????????" "?????????" "?????????" "??????" "???????????" "????????" "????????") + :SHORT-WEEKDAYS '("??." "?." "?." "?." "??." "?." "?.") + :ERAS '("??????????????????" "?.?.")))) + +(setf (gethash "el_GR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??????????" "???????????" "???????" "????????" "?????" "???????" "???????" "?????????" "???????????" "?????????" "?????????" "??????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "????" "????" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("???????" "???????" "?????" "???????" "??????" "?????????" "???????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("BC" "AD")))) + +(setf (gethash "it_IT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("gennaio" "febbraio" "marzo" "aprile" "maggio" "giugno" "luglio" "agosto" "settembre" "ottobre" "novembre" "dicembre") + :SHORT-MONTHS '("gen" "feb" "mar" "apr" "mag" "giu" "lug" "ago" "set" "ott" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domenica" "luned?" "marted?" "mercoled?" "gioved?" "venerd?" "sabato") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mer" "gio" "ven" "sab") + :ERAS '("BC" "dopo Cristo")))) + +(setf (gethash "ca" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("gener" "febrer" "mar?" "abril" "maig" "juny" "juliol" "agost" "setembre" "octubre" "novembre" "desembre") + :SHORT-MONTHS '("gen." "feb." "mar?" "abr." "maig" "juny" "jul." "ag." "set." "oct." "nov." "des.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("diumenge" "dilluns" "dimarts" "dimecres" "dijous" "divendres" "dissabte") + :SHORT-WEEKDAYS '("dg." "dl." "dt." "dc." "dj." "dv." "ds.") + :ERAS '("BC" "AD")))) + +(setf (gethash "hu_HU" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "HUF") + :DATE-FORMAT (list + :AMPM '("DE" "DU") + :MONTHS '("janu?r" "febru?r" "m?rcius" "?prilis" "m?jus" "j?nius" "j?lius" "augusztus" "szeptember" "okt?ber" "november" "december") + :SHORT-MONTHS '("jan." "febr." "m?rc." "?pr." "m?j." "j?n." "j?l." "aug." "szept." "okt." "nov." "dec.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("vas?rnap" "h?tf?" "kedd" "szerda" "cs?t?rt?k" "p?ntek" "szombat") + :SHORT-WEEKDAYS '("V" "H" "K" "Sze" "Cs" "P" "Szo") + :ERAS '("i.e." "i.u.")))) + +(setf (gethash "fr" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "en_IE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "uk_UA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "UAH") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("?????" "??????" "???????" "??????" "??????" "??????" "?????" "??????" "???????" "??????" "?????????" "??????") + :SHORT-MONTHS '("???" "???" "???" "????" "????" "????" "???" "????" "???" "????" "????" "????") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "????????" "??????" "??????" "?'??????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "????? ?.?.")))) + +(setf (gethash "pl_PL" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "PLN") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("stycze?" "luty" "marzec" "kwiecie?" "maj" "czerwiec" "lipiec" "sierpie?" "wrzesie?" "pa?dziernik" "listopad" "grudzie?") + :SHORT-MONTHS '("sty" "lut" "mar" "kwi" "maj" "cze" "lip" "sie" "wrz" "pa?" "lis" "gru") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("niedziela" "poniedzia?ek" "wtorek" "?roda" "czwartek" "pi?tek" "sobota") + :SHORT-WEEKDAYS '("N" "Pn" "Wt" "?r" "Cz" "Pt" "So") + :ERAS '("p.n.e." "n.e.")))) + +(setf (gethash "fr_LU" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "nl_BE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januari" "februari" "maart" "april" "mei" "juni" "juli" "augustus" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mrt" "apr" "mei" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("zondag" "maandag" "dinsdag" "woensdag" "donderdag" "vrijdag" "zaterdag") + :SHORT-WEEKDAYS '("zo" "ma" "di" "wo" "do" "vr" "za") + :ERAS '("BC" "AD")))) + +(setf (gethash "en_IN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "INR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "ca_ES" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("gener" "febrer" "mar?" "abril" "maig" "juny" "juliol" "agost" "setembre" "octubre" "novembre" "desembre") + :SHORT-MONTHS '("gen." "feb." "mar?" "abr." "maig" "juny" "jul." "ag." "set." "oct." "nov." "des.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("diumenge" "dilluns" "dimarts" "dimecres" "dijous" "divendres" "dissabte") + :SHORT-WEEKDAYS '("dg." "dl." "dt." "dc." "dj." "dv." "ds.") + :ERAS '("BC" "AD")))) + +(setf (gethash "ar_MA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "MAD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "es_BO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "BOB") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "en_AU" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "AUD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "sr" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "?????" "???" "???" "???" "??????" "?????????" "???????" "????????" "????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "??????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?. ?. ?." "?. ?")))) + +(setf (gethash "zh_SG" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SGD") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :SHORT-MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("???" "??")))) + +(setf (gethash "pt" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Janeiro" "Fevereiro" "Mar?o" "Abril" "Maio" "Junho" "Julho" "Agosto" "Setembro" "Outubro" "Novembro" "Dezembro") + :SHORT-MONTHS '("Jan" "Fev" "Mar" "Abr" "Mai" "Jun" "Jul" "Ago" "Set" "Out" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Domingo" "Segunda-feira" "Ter?a-feira" "Quarta-feira" "Quinta-feira" "Sexta-feira" "S?bado") + :SHORT-WEEKDAYS '("Dom" "Seg" "Ter" "Qua" "Qui" "Sex" "S?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "uk" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("?????" "??????" "???????" "??????" "??????" "??????" "?????" "??????" "???????" "??????" "?????????" "??????") + :SHORT-MONTHS '("???" "???" "???" "????" "????" "????" "???" "????" "???" "????" "????" "????") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "????????" "??????" "??????" "?'??????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "????? ?.?.")))) + +(setf (gethash "es_SV" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SVC") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "ru_RU" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "RUB") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "??????" "???" "????" "????" "??????" "????????" "???????" "??????" "???????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("???????????" "???????????" "???????" "?????" "???????" "???????" "???????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "?.?.")))) + +(setf (gethash "ko_KR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "KRW") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :SHORT-MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("BC" "AD")))) + +(setf (gethash "vi" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("SA" "CH") + :MONTHS '("th?ng m?t" "th?ng hai" "th?ng ba" "th?ng t?" "th?ng n?m" "th?ng s?u" "th?ng b?y" "th?ng t?m" "th?ng ch?n" "th?ng m??i" "th?ng m??i m?t" "th?ng m??i hai") + :SHORT-MONTHS '("thg 1" "thg 2" "thg 3" "thg 4" "thg 5" "thg 6" "thg 7" "thg 8" "thg 9" "thg 10" "thg 11" "thg 12") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Ch? nh?t" "Th? hai" "Th? ba" "Th? t?" "Th? n?m" "Th? s?u" "Th? b?y") + :SHORT-WEEKDAYS '("CN" "Th 2" "Th 3" "Th 4" "Th 5" "Th 6" "Th 7") + :ERAS '("tr. CN" "sau CN")))) + +(setf (gethash "ar_DZ" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "DZD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "vi_VN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "VND") + :DATE-FORMAT (list + :AMPM '("SA" "CH") + :MONTHS '("th?ng m?t" "th?ng hai" "th?ng ba" "th?ng t?" "th?ng n?m" "th?ng s?u" "th?ng b?y" "th?ng t?m" "th?ng ch?n" "th?ng m??i" "th?ng m??i m?t" "th?ng m??i hai") + :SHORT-MONTHS '("thg 1" "thg 2" "thg 3" "thg 4" "thg 5" "thg 6" "thg 7" "thg 8" "thg 9" "thg 10" "thg 11" "thg 12") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Ch? nh?t" "Th? hai" "Th? ba" "Th? t?" "Th? n?m" "Th? s?u" "Th? b?y") + :SHORT-WEEKDAYS '("CN" "Th 2" "Th 3" "Th 4" "Th 5" "Th 6" "Th 7") + :ERAS '("tr. CN" "sau CN")))) + +(setf (gethash "sr_ME" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "???????" "????" "?????" "???" "???" "???" "??????" "?????????" "???????" "????????" "????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("??????" "?????????" "??????" "?????" "????????" "?????" "??????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("?. ?. ?." "?. ?")))) + +(setf (gethash "sq" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("PD" "MD") + :MONTHS '("janar" "shkurt" "mars" "prill" "maj" "qershor" "korrik" "gusht" "shtator" "tetor" "n?ntor" "dhjetor") + :SHORT-MONTHS '("Jan" "Shk" "Mar" "Pri" "Maj" "Qer" "Kor" "Gsh" "Sht" "Tet" "N?n" "Dhj") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("e diel" "e h?n?" "e mart?" "e m?rkur?" "e enjte" "e premte" "e shtun?") + :SHORT-WEEKDAYS '("Die" "H?n" "Mar" "M?r" "Enj" "Pre" "Sht") + :ERAS '("p.e.r." "n.e.r.")))) + +(setf (gethash "ar_LY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "LYD") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "ar" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "zh_CN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "CNY") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :SHORT-MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("???" "??")))) + +(setf (gethash "be_BY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "BYR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("????????" "??????" "????????" "?????????" "???" "??????" "??????" "??????" "???????" "???????????" "?????????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???????" "??????????" "???????" "??????" "??????" "???????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("?? ?.?." "?.?.")))) + +(setf (gethash "zh_HK" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "HKD") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??" "??" "??" "??" "??" "??" "??" "??" "??" "??" "???" "???") + :SHORT-MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???" "??")))) + +(setf (gethash "ja" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("1?" "2?" "3?" "4?" "5?" "6?" "7?" "8?" "9?" "10?" "11?" "12?") + :SHORT-MONTHS '("1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???" "??")))) + +(setf (gethash "iw_IL" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "ILS") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("?????" "??????" "???" "?????" "???" "????" "????" "??????" "??????" "???????" "??????" "?????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??? ?????" "??? ???" "??? ?????" "??? ?????" "??? ?????" "??? ????" "???") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("???"?" "????"?")))) + +(setf (gethash "bg_BG" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "BGN") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("??????" "????????" "????" "?????" "???" "???" "???" "??????" "?????????" "????????" "???????" "????????") + :SHORT-MONTHS '("I" "II" "III" "IV" "V" "VI" "VII" "VIII" "IX" "X" "XI" "XII") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????" "??????????" "???????" "?????" "?????????" "?????" "??????") + :SHORT-WEEKDAYS '("??" "??" "??" "??" "??" "??" "??") + :ERAS '("??.?.?." "?.?.")))) + +(setf (gethash "in" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januari" "Februari" "Maret" "April" "Mei" "Juni" "Juli" "Agustus" "September" "Oktober" "November" "Desember") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "Mei" "Jun" "Jul" "Agu" "Sep" "Okt" "Nov" "Des") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Minggu" "Senin" "Selasa" "Rabu" "Kamis" "Jumat" "Sabtu") + :SHORT-WEEKDAYS '("Min" "Sen" "Sel" "Rab" "Kam" "Jum" "Sab") + :ERAS '("BCE" "CE")))) + +(setf (gethash "mt_MT" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "MTL") + :DATE-FORMAT (list + :AMPM '("QN" "WN") + :MONTHS '("Jannar" "Frar" "Marzu" "April" "Mejju" "?unju" "Lulju" "Awissu" "Settembru" "Ottubru" "Novembru" "Di?embru") + :SHORT-MONTHS '("Jan" "Fra" "Mar" "Apr" "Mej" "?un" "Lul" "Awi" "Set" "Ott" "Nov" "Di?") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Il-?add" "It-Tnejn" "It-Tlieta" "L-Erbg?a" "Il-?amis" "Il-?img?a" "Is-Sibt") + :SHORT-WEEKDAYS '("?ad" "Tne" "Tli" "Erb" "?am" "?im" "Sib") + :ERAS '("QK" "WK")))) + +(setf (gethash "es_PY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "PYG") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "sl" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "marec" "april" "maj" "junij" "julij" "avgust" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "avg" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Nedelja" "Ponedeljek" "Torek" "Sreda" "?etrtek" "Petek" "Sobota") + :SHORT-WEEKDAYS '("Ned" "Pon" "Tor" "Sre" "?et" "Pet" "Sob") + :ERAS '("pr.n.?." "po Kr.")))) + +(setf (gethash "fr_FR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janvier" "f?vrier" "mars" "avril" "mai" "juin" "juillet" "ao?t" "septembre" "octobre" "novembre" "d?cembre") + :SHORT-MONTHS '("janv." "f?vr." "mars" "avr." "mai" "juin" "juil." "ao?t" "sept." "oct." "nov." "d?c.") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi") + :SHORT-WEEKDAYS '("dim." "lun." "mar." "mer." "jeu." "ven." "sam.") + :ERAS '("BC" "ap. J.-C.")))) + +(setf (gethash "cs_CZ" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "CZK") + :DATE-FORMAT (list + :AMPM '("dop." "odp.") + :MONTHS '("leden" "?nor" "b?ezen" "duben" "kv?ten" "?erven" "?ervenec" "srpen" "z???" "??jen" "listopad" "prosinec") + :SHORT-MONTHS '("I" "II" "III" "IV" "V" "VI" "VII" "VIII" "IX" "X" "XI" "XII") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Ned?le" "Pond?l?" "?ter?" "St?eda" "?tvrtek" "P?tek" "Sobota") + :SHORT-WEEKDAYS '("Ne" "Po" "?t" "St" "?t" "P?" "So") + :ERAS '("p?.Kr." "po Kr.")))) + +(setf (gethash "it_CH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\' :DECIMAL-SEPARATOR #\. "CHF") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("gennaio" "febbraio" "marzo" "aprile" "maggio" "giugno" "luglio" "agosto" "settembre" "ottobre" "novembre" "dicembre") + :SHORT-MONTHS '("gen" "feb" "mar" "apr" "mag" "giu" "lug" "ago" "set" "ott" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domenica" "luned?" "marted?" "mercoled?" "gioved?" "venerd?" "sabato") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mer" "gio" "ven" "sab") + :ERAS '("BC" "dopo Cristo")))) + +(setf (gethash "ro_RO" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "RON") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("ianuarie" "februarie" "martie" "aprilie" "mai" "iunie" "iulie" "august" "septembrie" "octombrie" "noiembrie" "decembrie") + :SHORT-MONTHS '("Ian" "Feb" "Mar" "Apr" "Mai" "Iun" "Iul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("duminic?" "luni" "mar?i" "miercuri" "joi" "vineri" "s?mb?t?") + :SHORT-WEEKDAYS '("D" "L" "Ma" "Mi" "J" "V" "S") + :ERAS '("d.C." "?.d.C.")))) + +(setf (gethash "es_PR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "USD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "en_CA" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "CAD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "de_DE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januar" "Februar" "M?rz" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember") + :SHORT-MONTHS '("Jan" "Feb" "Mrz" "Apr" "Mai" "Jun" "Jul" "Aug" "Sep" "Okt" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag") + :SHORT-WEEKDAYS '("So" "Mo" "Di" "Mi" "Do" "Fr" "Sa") + :ERAS '("v. Chr." "n. Chr.")))) + +(setf (gethash "ga" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("a.m." "p.m.") + :MONTHS '("Ean?ir" "Feabhra" "M?rta" "Aibre?n" "Bealtaine" "Meitheamh" "I?il" "L?nasa" "Me?n F?mhair" "Deireadh F?mhair" "Samhain" "Nollaig") + :SHORT-MONTHS '("Ean" "Feabh" "M?rta" "Aib" "Beal" "Meith" "I?il" "L?n" "MF?mh" "DF?mh" "Samh" "Noll") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("D? Domhnaigh" "D? Luain" "D? M?irt" "D? C?adaoin" "D?ardaoin" "D? hAoine" "D? Sathairn") + :SHORT-WEEKDAYS '("Domh" "Luan" "M?irt" "C?ad" "D?ar" "Aoine" "Sath") + :ERAS '("RC" "AD")))) + +(setf (gethash "de_LU" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "EUR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januar" "Februar" "M?rz" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember") + :SHORT-MONTHS '("Jan" "Feb" "Mrz" "Apr" "Mai" "Jun" "Jul" "Aug" "Sep" "Okt" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag") + :SHORT-WEEKDAYS '("So" "Mo" "Di" "Mi" "Do" "Fr" "Sa") + :ERAS '("v. Chr." "n. Chr.")))) + +(setf (gethash "de" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januar" "Februar" "M?rz" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember") + :SHORT-MONTHS '("Jan" "Feb" "Mrz" "Apr" "Mai" "Jun" "Jul" "Aug" "Sep" "Okt" "Nov" "Dez") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag") + :SHORT-WEEKDAYS '("So" "Mo" "Di" "Mi" "Do" "Fr" "Sa") + :ERAS '("v. Chr." "n. Chr.")))) + +(setf (gethash "es_AR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "ARS") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + +(setf (gethash "sk" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("janu?r" "febru?r" "marec" "apr?l" "m?j" "j?n" "j?l" "august" "september" "okt?ber" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "m?j" "j?n" "j?l" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Nede?a" "Pondelok" "Utorok" "Streda" "?tvrtok" "Piatok" "Sobota") + :SHORT-WEEKDAYS '("Ne" "Po" "Ut" "St" "?t" "Pi" "So") + :ERAS '("pred n.l." "n.l.")))) + +(setf (gethash "ms_MY" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "MYR") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januari" "Februari" "Mac" "April" "Mei" "Jun" "Julai" "Ogos" "September" "Oktober" "November" "Disember") + :SHORT-MONTHS '("Jan" "Feb" "Mac" "Apr" "Mei" "Jun" "Jul" "Ogos" "Sep" "Okt" "Nov" "Dis") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Ahad" "Isnin" "Selasa" "Rabu" "Khamis" "Jumaat" "Sabtu") + :SHORT-WEEKDAYS '("Ahd" "Isn" "Sel" "Rab" "Kha" "Jum" "Sab") + :ERAS '("BCE" "CE")))) + +(setf (gethash "hr_HR" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "HRK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("sije?anj" "velja?a" "o?ujak" "travanj" "svibanj" "lipanj" "srpanj" "kolovoz" "rujan" "listopad" "studeni" "prosinac") + :SHORT-MONTHS '("sij" "vel" "o?u" "tra" "svi" "lip" "srp" "kol" "ruj" "lis" "stu" "pro") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("nedjelja" "ponedjeljak" "utorak" "srijeda" "?etvrtak" "petak" "subota") + :SHORT-WEEKDAYS '("ned" "pon" "uto" "sri" "?et" "pet" "sub") + :ERAS '("BC" "AD")))) + +(setf (gethash "en_SG" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "SGD") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December") + :SHORT-MONTHS '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") + :SHORT-WEEKDAYS '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") + :ERAS '("BC" "AD")))) + +(setf (gethash "da" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "marts" "april" "maj" "juni" "juli" "august" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "mandag" "tirsdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "ma" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "mt" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("QN" "WN") + :MONTHS '("Jannar" "Frar" "Marzu" "April" "Mejju" "?unju" "Lulju" "Awissu" "Settembru" "Ottubru" "Novembru" "Di?embru") + :SHORT-MONTHS '("Jan" "Fra" "Mar" "Apr" "Mej" "?un" "Lul" "Awi" "Set" "Ott" "Nov" "Di?") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Il-?add" "It-Tnejn" "It-Tlieta" "L-Erbg?a" "Il-?amis" "Il-?img?a" "Is-Sibt") + :SHORT-WEEKDAYS '("?ad" "Tne" "Tli" "Erb" "?am" "?im" "Sib") + :ERAS '("QK" "WK")))) + +(setf (gethash "pl" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("stycze?" "luty" "marzec" "kwiecie?" "maj" "czerwiec" "lipiec" "sierpie?" "wrzesie?" "pa?dziernik" "listopad" "grudzie?") + :SHORT-MONTHS '("sty" "lut" "mar" "kwi" "maj" "cze" "lip" "sie" "wrz" "pa?" "lis" "gru") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("niedziela" "poniedzia?ek" "wtorek" "?roda" "czwartek" "pi?tek" "sobota") + :SHORT-WEEKDAYS '("N" "Pn" "Wt" "?r" "Cz" "Pt" "So") + :ERAS '("p.n.e." "n.e.")))) + +(setf (gethash "ar_OM" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "OMR") + :DATE-FORMAT (list + :AMPM '("?" "?") + :MONTHS '("?????" "??????" "????" "?????" "????" "?????" "?????" "?????" "??????" "??????" "??????" "??????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 7 + :WEEKDAYS '("?????" "???????" "????????" "????????" "??????" "??????" "?????") + :SHORT-WEEKDAYS '("?" "?" "?" "?" "?" "?" "?") + :ERAS '("?.?" "?")))) + +(setf (gethash "tr" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Ocak" "?ubat" "Mart" "Nisan" "May?s" "Haziran" "Temmuz" "A?ustos" "Eyl?l" "Ekim" "Kas?m" "Aral?k") + :SHORT-MONTHS '("Oca" "?ub" "Mar" "Nis" "May" "Haz" "Tem" "A?u" "Eyl" "Eki" "Kas" "Ara") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("Pazar" "Pazartesi" "Sal?" "?ar?amba" "Per?embe" "Cuma" "Cumartesi") + :SHORT-WEEKDAYS '("Paz" "Pzt" "Sal" "?ar" "Per" "Cum" "Cmt") + :ERAS '("BC" "AD")))) + +(setf (gethash "th_TH" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "THB") + :DATE-FORMAT (list + :AMPM '("??????????" "??????????") + :MONTHS '("??????" "??????????" "??????" "??????" "???????" "????????" "???????" "???????" "???????" "??????" "?????????" "???????") + :SHORT-MONTHS '("?.?." "?.?." "??.?." "??.?." "?.?." "??.?." "?.?." "?.?." "?.?." "?.?." "?.?." "?.?.") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("??????????" "?????????" "?????????" "??????" "???????????" "????????" "????????") + :SHORT-WEEKDAYS '("??." "?." "?." "?." "??." "?." "?.") + :ERAS '("??????????????????" "?.?.")))) + +(setf (gethash "el" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "XXX") + :DATE-FORMAT (list + :AMPM '("??" "??") + :MONTHS '("??????????" "???????????" "???????" "????????" "?????" "???????" "???????" "?????????" "???????????" "?????????" "?????????" "??????????") + :SHORT-MONTHS '("???" "???" "???" "???" "???" "????" "????" "???" "???" "???" "???" "???") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("???????" "???????" "?????" "???????" "??????" "?????????" "???????") + :SHORT-WEEKDAYS '("???" "???" "???" "???" "???" "???" "???") + :ERAS '("BC" "AD")))) + +(setf (gethash "ms" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "XXX") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("Januari" "Februari" "Mac" "April" "Mei" "Jun" "Julai" "Ogos" "September" "Oktober" "November" "Disember") + :SHORT-MONTHS '("Jan" "Feb" "Mac" "Apr" "Mei" "Jun" "Jul" "Ogos" "Sep" "Okt" "Nov" "Dis") + :FIRST-DAY-OF-THE-WEEK 1 + :WEEKDAYS '("Ahad" "Isnin" "Selasa" "Rabu" "Khamis" "Jumaat" "Sabtu") + :SHORT-WEEKDAYS '("Ahd" "Isn" "Sel" "Rab" "Kha" "Jum" "Sab") + :ERAS '("BCE" "CE")))) + +(setf (gethash "sv_SE" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\? :DECIMAL-SEPARATOR #\, "SEK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januari" "februari" "mars" "april" "maj" "juni" "juli" "augusti" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "m?ndag" "tisdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "m?" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "da_DK" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\. :DECIMAL-SEPARATOR #\, "DKK") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("januar" "februar" "marts" "april" "maj" "juni" "juli" "august" "september" "oktober" "november" "december") + :SHORT-MONTHS '("jan" "feb" "mar" "apr" "maj" "jun" "jul" "aug" "sep" "okt" "nov" "dec") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("s?ndag" "mandag" "tirsdag" "onsdag" "torsdag" "fredag" "l?rdag") + :SHORT-WEEKDAYS '("s?" "ma" "ti" "on" "to" "fr" "l?") + :ERAS '("BC" "AD")))) + +(setf (gethash "es_HN" *locales*) + (list + :NUMBER-FORMAT (list :GROUPING-SEPARATOR #\, :DECIMAL-SEPARATOR #\. "HNL") + :DATE-FORMAT (list + :AMPM '("AM" "PM") + :MONTHS '("enero" "febrero" "marzo" "abril" "mayo" "junio" "julio" "agosto" "septiembre" "octubre" "noviembre" "diciembre") + :SHORT-MONTHS '("ene" "feb" "mar" "abr" "may" "jun" "jul" "ago" "sep" "oct" "nov" "dic") + :FIRST-DAY-OF-THE-WEEK 2 + :WEEKDAYS '("domingo" "lunes" "martes" "mi?rcoles" "jueves" "viernes" "s?bado") + :SHORT-WEEKDAYS '("dom" "lun" "mar" "mi?" "jue" "vie" "s?b") + :ERAS '("BC" "AD")))) + Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Tue Mar 25 05:54:19 2008 @@ -33,7 +33,7 @@ (export 'HUNCHENTOOT::SESSION-REALM 'HUNCHENTOOT) (defpackage :claw - (:use :cl :hunchentoot :alexandria :cl-ppcre :cl-fad) + (:use :cl :hunchentoot :alexandria :cl-ppcre :cl-fad :local-time) (:shadow :flatten) (:export :*html-4.01-strict* :*html-4.01-transitional* @@ -289,7 +289,7 @@ :translator-encode :translator-decode :*simple-translator* - ;;:with-validators disabled + :*locales* :validate :validation-errors :component-validation-errors Modified: trunk/main/claw-core/src/validators.lisp ============================================================================== --- trunk/main/claw-core/src/validators.lisp (original) +++ trunk/main/claw-core/src/validators.lisp Tue Mar 25 05:54:19 2008 @@ -65,7 +65,9 @@ ((thousand-separator :initarg :thousand-separator :reader translator-thousand-separator) (always-show-signum :initarg :always-show-signum - :reader translator-always-show-signum)) + :reader translator-always-show-signum) + (grouping-size :initarg :grouping-size + :reader translator-grouping-size)) (:default-initargs :thousand-separator nil :always-show-signum nil) (:documentation "a translator object encodes and decodes integer values passed to a html input component")) From achiumenti at common-lisp.net Tue Mar 25 15:42:38 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 25 Mar 2008 10:42:38 -0500 (EST) Subject: [claw-cvs] r21 - trunk/main/claw-core/generators Message-ID: <20080325154238.A6A4330039@common-lisp.net> Author: achiumenti Date: Tue Mar 25 10:42:37 2008 New Revision: 21 Modified: trunk/main/claw-core/generators/GenerateLocales.java Log: continuning on l13n Modified: trunk/main/claw-core/generators/GenerateLocales.java ============================================================================== --- trunk/main/claw-core/generators/GenerateLocales.java (original) +++ trunk/main/claw-core/generators/GenerateLocales.java Tue Mar 25 10:42:37 2008 @@ -108,8 +108,8 @@ "\" *locales*)" + "\n (list "); sw.append("\n :NUMBER-FORMAT " + - "(list :GROUPING-SEPARATOR #\\" + dfs.getGroupingSeparator() + - " :DECIMAL-SEPARATOR #\\" + dfs.getDecimalSeparator() + + "(list :GROUPING-SEPARATOR " + encodeLispChar(dfs.getGroupingSeparator()) + + " :DECIMAL-SEPARATOR " + encodeLispChar(dfs.getDecimalSeparator()) + " \"" + dfs.getInternationalCurrencySymbol() + "\"" + ")"); sw.append("\n :DATE-FORMAT (list"); @@ -133,6 +133,15 @@ System.out.println(fileName + " successfully generated."); } + private String encodeLispChar(char ch) { + switch (ch) { + case ' ': return "#\\SPACE"; + case 0: return "nil"; + default: return "#\\" + ch; + } + + + } /** * @param args the command line arguments */ From achiumenti at common-lisp.net Tue Mar 25 15:42:54 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 25 Mar 2008 10:42:54 -0500 (EST) Subject: [claw-cvs] r22 - trunk/main/claw-core/src Message-ID: <20080325154254.9A56530053@common-lisp.net> Author: achiumenti Date: Tue Mar 25 10:42:54 2008 New Revision: 22 Modified: trunk/main/claw-core/src/i18n.lisp Log: continuning on l13n Modified: trunk/main/claw-core/src/i18n.lisp ============================================================================== --- trunk/main/claw-core/src/i18n.lisp (original) +++ trunk/main/claw-core/src/i18n.lisp Tue Mar 25 10:42:54 2008 @@ -37,8 +37,8 @@ * 'SEC seconds * 'MIN minutes * 'HR hours -* 'DAYS days -* 'MONTH month +* 'DAY days +* 'MONTH monthes * 'YEARS years. And other FIELD value will produce an error condition.")) @@ -82,8 +82,8 @@ (multiple-value-bind (d-month d-year) (floor (abs value) 12) (when (< value 0) - (setf d-month (* d-month -1) - d-year (* d-year -1)) + (setf d-month (- d-month) + d-year (- d-year)) (multiple-value-bind (ns ss mm hh day month year) (decode-local-time local-time) (multiple-value-bind (ns ss mm hh day month-ignore year) @@ -101,11 +101,63 @@ local-time-result)) (defun local-time-add-hour (local-time value) - (multiple-value-bind (d-hour d-day) - (floor (abs value) 24) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (multiple-value-bind (d-hour d-day) + (floor (abs value) 24) + (when (< value 0) + (setf d-hour (- d-hour) + d-day (- d-day))) + (let ((local-time-result (local-time-add-day local-time d-day))) + (multiple-value-bind (ns2 ss2 mm2 hh2 day2 month2 year2) + (decode-local-time local-time-result) + (encode-local-time ns2 ss2 mm2 (+ hh d-hour) day2 month2 year2)))))) + +(defun local-time-add-min (local-time value) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (multiple-value-bind (d-min d-hour) + (floor (abs value) 60) + (when (< value 0) + (setf d-min (- d-min) + d-hour (- d-hour))) + (let ((local-time-result (local-time-add-hour local-time d-hour))) + (multiple-value-bind (ns2 ss2 mm2 hh2 day2 month2 year2) + (decode-local-time local-time-result) + (encode-local-time ns2 ss2 (+ mm d-min) hh2 day2 month2 year2)))))) -#| +(defun local-time-add-sec (local-time value) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (multiple-value-bind (d-sec d-min) + (floor (abs value) 60) + (when (< value 0) + (setf d-sec (- d-sec) + d-min (- d-min))) + (let ((local-time-result (local-time-add-min local-time d-min))) + (multiple-value-bind (ns2 ss2 mm2 hh2 day2 month2 year2) + (decode-local-time local-time-result) + (encode-local-time ns2 (+ ss d-sec) mm2 hh2 day2 month2 year2)))))) + +(defun local-time-add-nsec (local-time value) + (multiple-value-bind (ns ss mm hh day month year) + (decode-local-time local-time) + (multiple-value-bind (d-nsec d-sec) + (floor (abs value) 10000000) + (when (< value 0) + (setf d-nsec (- d-nsec) + d-sec (- d-sec))) + (let ((local-time-result (local-time-add-sec local-time d-sec))) + (multiple-value-bind (ns2 ss2 mm2 hh2 day2 month2 year2) + (decode-local-time local-time-result) + (encode-local-time (+ ns d-nsec) ss2 mm2 hh2 day2 month2 year2)))))) + (defmethod local-time-add ((local-time local-time) field value) (ccase field - ('NSEC -|# \ No newline at end of file + (NSEC (local-time-add-nsec local-time value)) + (SEC (local-time-add-sec local-time value)) + (MIN (local-time-add-min local-time value)) + (HR (local-time-add-hour local-time value)) + (DAY (local-time-add-day local-time value)) + (MONTH (local-time-add-month local-time value)) + (YEAR (local-time-add-year local-time value)))) From achiumenti at common-lisp.net Sat Mar 29 06:54:21 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Sat, 29 Mar 2008 01:54:21 -0500 (EST) Subject: [claw-cvs] r23 - in trunk/main/claw-core: src tests Message-ID: <20080329065421.E52DD830BC@common-lisp.net> Author: achiumenti Date: Sat Mar 29 01:54:18 2008 New Revision: 23 Modified: trunk/main/claw-core/src/misc.lisp trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/tags.lisp trunk/main/claw-core/src/validators.lisp trunk/main/claw-core/tests/test1.lisp Log: finishing commenting validators forms corrected some validators quirks added content type property to page compoenent Modified: trunk/main/claw-core/src/misc.lisp ============================================================================== --- trunk/main/claw-core/src/misc.lisp (original) +++ trunk/main/claw-core/src/misc.lisp Sat Mar 29 01:54:18 2008 @@ -177,7 +177,9 @@ (if ,result ,result ,default-val))))) - + +(defun do-message (key &optional (default "") locale) + (funcall (with-message key default locale))) (defun user-locale (&optional (request *request*) (session *session*)) (let ((locale (when session Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Sat Mar 29 01:54:18 2008 @@ -75,6 +75,7 @@ :page-xmloutput :page-doc-type :page-current-component + :page-content-type :htclass-body :htcomponent :htcomponent-page @@ -282,6 +283,7 @@ :simple-message-dispatcher :simple-message-dispatcher-add-message :with-message + :do-message ;;validation :translator :translator-integer Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Sat Mar 29 01:54:18 2008 @@ -363,7 +363,7 @@ :accessor page-xmloutput :documentation "Determine if the page must be rendered as an XML") (current-form :initform :nil :accessor page-current-form :documentation "During the rewinding phase the form or the action-link whose action has been fired") - (content-type :initarg :doc-type + (doc-type :initarg :doc-type :accessor page-doc-type :documentation "The DOCUMENT TYPE of the page (default to HTML 4.01 STRICT)") (lasttag :initform nil :accessor page-lasttag :documentation "Last rendered tag. Needed for page output rendering") @@ -372,7 +372,10 @@ (request-parameters :initarg :request-parameters) (components-stack :initform nil :accessor page-components-stack - :documentation "A stack of components enetered into rendering process.") + :documentation "A stack of components enetered into rendering process.") + (content-type :initarg :content-type + :accessor page-content-type + :documentation "Define the content type of the page when rendered") (url :initarg :url :accessor page-url :documentation "The URL provided with this page instance")) (:default-initargs :writer t @@ -386,6 +389,7 @@ :xmloutput nil :doc-type *html-4.01-strict* :request-parameters nil + :content-type hunchentoot:*default-content-type* :url nil) (:documentation "A page object holds claw components to be rendered") ) @@ -585,6 +589,7 @@ (defmethod page-render ((page page)) (let ((body (page-content page)) (jsonp (page-json-id-list page))) + (setf (hunchentoot:content-type) (page-content-type page)) (if (null body) (format nil "null body for page ~a~%" (type-of page)) (progn @@ -802,8 +807,6 @@ (htcomponent-json-print-start-component tag)) (when (or (page-can-print page) previous-print-status) (tag-render-starttag tag page)) - (when (string-equal "messaged" (htcomponent-client-id tag)) - (log-message :info "RENDEING ~a: body ~a" (htcomponent-client-id tag) body-list)) (dolist (child-tag body-list) (when child-tag (cond @@ -822,6 +825,7 @@ (let ((body-list (htcomponent-body hthead)) (injections (page-init-injections page))) (tag-render-starttag hthead page) + (htcomponent-render (meta> :http-equiv "Content-Type" :content (page-content-type page)) page) (dolist (child-tag body-list) (when child-tag (cond Modified: trunk/main/claw-core/src/validators.lisp ============================================================================== --- trunk/main/claw-core/src/validators.lisp (original) +++ trunk/main/claw-core/src/validators.lisp Sat Mar 29 01:54:18 2008 @@ -33,7 +33,7 @@ (:documentation "Encodes the input component value, used when rendering the component")) (defgeneric translator-decode (translator wcomponent) - (:documentation "Decodes the input component value")) + (:documentation "Decodes the input component value after a form submit.")) (defclass translator () () @@ -59,30 +59,38 @@ (declare (ignore client-id)) new-value)) -(defvar *simple-translator* (make-instance 'translator)) +(defvar *simple-translator* (make-instance 'translator) + "*SIMPLE-TRANSLATOR* is the default translator for any CINPUT component. +Its encoder and decoder methods pass values unchanged") (defclass translator-integer (translator) ((thousand-separator :initarg :thousand-separator - :reader translator-thousand-separator) + :reader translator-thousand-separator + :documentation "If specified (as character), it is the thousands separator. Despite of +its name, grouping is done following the TRANSLATOR-GROUPING-SIZE, so it's not a real 'tousands' separator") (always-show-signum :initarg :always-show-signum - :reader translator-always-show-signum) + :reader translator-always-show-signum + :documentation "When true the signum is used also for displaying positive numbers.") (grouping-size :initarg :grouping-size - :reader translator-grouping-size)) + :reader translator-grouping-size + :documentation "Used only if TRANSLATOR-THOUSAND-SEPARATOR is defined. Default to 3")) (:default-initargs :thousand-separator nil + :grouping-size 3 :always-show-signum nil) - (:documentation "a translator object encodes and decodes integer values passed to a html input component")) + (:documentation "A translator object encodes and decodes integer values passed to a html input component")) (defmethod translator-encode ((translator translator-integer) (wcomponent wcomponent)) (let* ((page (htcomponent-page wcomponent)) (visit-object (wcomponent-parameter-value wcomponent :visit-object)) (accessor (wcomponent-parameter-value wcomponent :accessor)) (reader (wcomponent-parameter-value wcomponent :reader)) + (grouping-size (translator-grouping-size translator)) (thousand-separator (translator-thousand-separator translator)) (signum-directive (if (translator-always-show-signum translator) "@" "")) (control-string (if thousand-separator - (format nil "~~3,' ,v:~aD" signum-directive) + (format nil "~~~d,' ,v:~aD" grouping-size signum-directive) (format nil "~~~ad" signum-directive))) (value (page-req-parameter page (htcomponent-client-id wcomponent) nil))) @@ -109,21 +117,19 @@ ;;========================================= -(defclass translator-number (translator) - ((thousand-separator :initarg :thousand-separator - :reader translator-thousand-separator) - (decimals-separator :initarg :decimals-separator - :reader translator-decimals-separator) +(defclass translator-number (translator-integer) + ((decimals-separator :initarg :decimals-separator + :reader translator-decimals-separator + :documentation "The decimal separator of the rendered number. Default to #\.") (decimal-digits :initarg :decimal-digits - :reader translator-decimal-digits) - (always-show-signum :initarg :always-show-signum - :reader translator-always-show-signum) + :reader translator-decimal-digits + :documentation "force the rendering of the value to a fixed number of decimal digits") (coerce :initarg :coerce - :accessor translator-coerce)) - (:default-initargs :thousand-separator nil :decimals-separator #\. + :accessor translator-coerce + :documentation "Coerces the decoded input value to the given value type")) + (:default-initargs :decimals-separator #\. ;:integer-digits nil - :decimal-digits nil - :always-show-signum nil + :decimal-digits nil :coerce 'ratio) (:documentation "a translator object encodes and decodes integer values passed to a html input component")) @@ -134,13 +140,14 @@ (accessor (wcomponent-parameter-value wcomponent :accessor)) (reader (wcomponent-parameter-value wcomponent :reader)) (thousand-separator (translator-thousand-separator translator)) + (grouping-size (translator-grouping-size translator)) (decimal-digits (translator-decimal-digits translator)) (decimals-separator (translator-decimals-separator translator)) (signum-directive (if (translator-always-show-signum translator) "@" "")) (integer-control-string (if thousand-separator - (format nil "~~3,' ,v:~aD" signum-directive) + (format nil "~~~d,' ,v:~aD" grouping-size signum-directive) (format nil "~~~ad" signum-directive))) (value (page-req-parameter page (htcomponent-client-id wcomponent) nil))) @@ -180,15 +187,20 @@ (declare (ignore client-id)) (when thousand-separator (setf new-value (regex-replace-all (format nil "~a" thousand-separator) new-value ""))) - (let ((decomposed-string (all-matches-as-strings "[0-9]+" new-value))) - (setf int-value (parse-integer (concatenate 'string (first decomposed-string) (second decomposed-string)))) - (setf dec-value (expt 10 (length (second decomposed-string)))) - (coerce (/ int-value dec-value) type))))) + (let ((decomposed-string (all-matches-as-strings "[0-9]+" new-value)) + (result)) + (setf int-value (parse-integer (concatenate 'string (first decomposed-string) (second decomposed-string))) + dec-value (expt 10 (length (second decomposed-string))) + result (/ int-value dec-value)) + (if (integerp result) + result + (coerce result type)))))) ;;---------------------------------------------------------------------------------------- (defun add-exception (id reason) +"Adds an exception for the given input component identified by its ID with the message expressed by REASON" (let* ((validation-errors (aux-request-value :validation-errors)) (component-exceptions (assoc id validation-errors :test #'equal))) (if component-exceptions @@ -199,6 +211,7 @@ (defun validate (test &key component message) +"When test is nil, an exception message given by MESSAGE is added for the COMPONENT. See: ADD-EXCEPTION..." (let ((client-id (htcomponent-client-id component))) (unless test (add-exception client-id message)))) @@ -213,12 +226,19 @@ (assoc client-id (validation-errors request) :test #'equal))) (defun validator-required (component value) + "Checks if the required input field VALUE is present. If not, a localizable message \"Field ~a may not be null.\" is sent with key \"VALIDATOR-REQUIRED\". +The argument for the message will be the :label attribute of the COMPONENT." (when (stringp value) (validate (and value (string-not-equal value "")) :component component - :message (format nil "Field ~a may not be null." (wcomponent-parameter-value component :label))))) + :message (format nil (do-message "VALIDATOR-REQUIRED" "Field ~a may not be null.") (wcomponent-parameter-value component :label))))) (defun validator-size (component value &key min-size max-size) +"Checks if the input field VALUE legth is less then or greater then rispectively of the form keywords :MIN-SIZE and :MAX-SIZE. +If less then :MIN-SIZE, a localizable message \"Size of ~a may not be less then ~a chars.\" is sent with key \"VALIDATOR-SIZE-MIN\". +The argument for the message will be the :label attribute of the COMPONENT and the :MIN-ZIZE value. +If greater then :MAX-SIZE, a localizable message \"Size of ~a may not be more then ~a chars\" is sent with key \"VALIDATOR-SIZE-MAX\". +The argument for the message will be the :label attribute of the COMPONENT and the :MAX-ZIZE value." (let ((value-len 0)) (when value (setf value (format nil "~a" value)) @@ -227,22 +247,27 @@ (when min-size (validate (>= value-len min-size) :component component - :message (format nil "Size of ~a may not be less then ~a" + :message (format nil (do-message "VALIDATOR-SIZE-MIN" "Size of ~a may not be less then ~a chars." ) (wcomponent-parameter-value component :label) min-size))) (when max-size (validate (<= value-len max-size) :component component - :message (format nil "Size of ~a may not be more then ~a" + :message (format nil (do-message "VALIDATOR-SIZE-MAX" "Size of ~a may not be more then ~a chars." ) (wcomponent-parameter-value component :label) max-size))))))) (defun validator-range (component value &key min max) +"Checks if the numeric input field VALUE is less then or greater then rispectively of the form keywords :MIN and :MAX. +If less then :MIN, a localizable message \"Field ~a is not less then or equal to ~d.\" is sent with key \"VALIDATOR-RANGE-MIN\". +The argument for the message will be the :label attribute of the COMPONENT and the :MIN value. +If greater then :MIN, a localizable message \"Field ~a is not greater then or equal to ~d.\" is sent with key \"VALIDATOR-RANGE-MAX\". +The argument for the message will be the :label attribute of the COMPONENT and the :MAX value." (when value (or (when min (validate (>= value min) :component component - :message (format nil "Field ~a is not greater then or equal to ~d" + :message (format nil (do-message "VALIDATOR-RANGE-MIN" "Field ~a is not greater then or equal to ~d") (wcomponent-parameter-value component :label) (if (typep min 'ratio) (coerce min 'float) @@ -250,26 +275,32 @@ (when max (validate (<= value max) :component component - :message (format nil "Field ~a is not less then or equal to ~d" + :message (format nil (do-message "VALIDATOR-RANGE-MAX" "Field ~a is not less then or equal to ~d") (wcomponent-parameter-value component :label) (if (typep max 'ratio) (coerce max 'float) max))))))) (defun validator-number (component value &key min max) +"Checks if the input field VALUE is a valid number and then passes the validation to VALIDATION-RANGE. +If not a number, a localizable message \"Field ~a is not a valid number.\" is sent with key \"VALIDATOR-NUMBER\". +The argument for the message will be the :label attribute of the COMPONENT." (when value (let ((test (numberp value))) (or (validate test :component component - :message (format nil "Field ~a is not a valid number" (wcomponent-parameter-value component :label))) + :message (format nil (do-message "VALIDATOR-NUMBER" "Field ~a is not a valid number.") (wcomponent-parameter-value component :label))) (validator-range component value :min min :max max))))) (defun validator-integer (component value &key min max) +"Checks if the input field VALUE is a valid number and then passes the validation to VALIDATION-RANGE. +If not a number, a localizable message \"Field ~a is not a valid integer.\" is sent with key \"VALIDATOR-INTEGER\". +The argument for the message will be the :label attribute of the COMPONENT." (when value (let ((test (integerp value))) (or (validate test :component component - :message (format nil "Field ~a is not a valid integer" (wcomponent-parameter-value component :label))) + :message (format nil (do-message "VALIDATOR-INTEGER" "Field ~a is not a valid integer.") (wcomponent-parameter-value component :label))) (validator-range component value :min min :max max))))) Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Sat Mar 29 01:54:18 2008 @@ -29,6 +29,8 @@ (in-package :claw-tests) +(setf *default-content-type* "text/html; charset=UTF-8") + (setf *rewrite-for-session-urls* nil) (defvar *this-file* (load-time-value (or #.*compile-file-pathname* *load-pathname*))) @@ -40,9 +42,13 @@ (simple-message-dispatcher-add-message *lisplet-messages* "en" "NAME" "Name") (simple-message-dispatcher-add-message *lisplet-messages* "en" "SURNAME" "Surname") +(simple-message-dispatcher-add-message *lisplet-messages* "en" "WELCOME" "Welcome") (simple-message-dispatcher-add-message *lisplet-messages* "it" "NAME" "Nome") (simple-message-dispatcher-add-message *lisplet-messages* "it" "SURNAME" "Cognome") +(simple-message-dispatcher-add-message *lisplet-messages* "it" "WELCOME" "Benvenuto") + +(simple-message-dispatcher-add-message *lisplet-messages* "it" "VALIDATOR-REQUIRED" "Il campo ~a non pu? essere vuoto!") (defvar *test-lisplet*) (setf *test-lisplet* (make-instance 'lisplet :realm "test1" :base-path "/test" @@ -56,8 +62,8 @@ (defparameter *clawserver* (make-instance 'clawserver :port 4242 :sslport 4445 :mod-lisp-p nil - :ssl-certificate-file #P"/home/kiuma/pem/cacert.pem" - :ssl-privatekey-file #P"/home/kiuma/pem/privkey.pem")) + :ssl-certificate-file #P"/home/kiuma/pem/cacert.pem" + :ssl-privatekey-file #P"/home/kiuma/pem/privkey.pem")) (setf (lisplet-redirect-protected-resources-p *test-lisplet*) t) @@ -256,7 +262,8 @@ ((username :initform "" :accessor login-page-username) (passowrd :initform "" - :accessor login-page-password))) + :accessor login-page-password)) + (:default-initargs :message-dispatcher *lisplet-messages*)) (defmethod page-content ((login-page login-page)) (let ((princp (current-principal))) @@ -280,7 +287,7 @@ (td> :colspan "2" (csubmit> :id "submit" :value "Login"))))) (p> - "Welcome " + (with-message "WELCOME" "WELCOME") " " (principal-name princp) (a> :href "index.html" "home")))))) From achiumenti at common-lisp.net Mon Mar 31 04:48:37 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Sun, 30 Mar 2008 23:48:37 -0500 (EST) Subject: [claw-cvs] r24 - trunk/main/claw-core/src Message-ID: <20080331044837.31EF955356@common-lisp.net> Author: achiumenti Date: Sun Mar 30 23:48:36 2008 New Revision: 24 Modified: trunk/main/claw-core/src/validators.lisp Log: beginning of local-time integration Modified: trunk/main/claw-core/src/validators.lisp ============================================================================== --- trunk/main/claw-core/src/validators.lisp (original) +++ trunk/main/claw-core/src/validators.lisp Sun Mar 30 23:48:36 2008 @@ -30,10 +30,10 @@ (in-package :claw) (defgeneric translator-encode (translator wcomponent) - (:documentation "Encodes the input component value, used when rendering the component")) + (:documentation "Encodes the input component value, used when rendering the component (Encodes from type to string).")) (defgeneric translator-decode (translator wcomponent) - (:documentation "Decodes the input component value after a form submit.")) + (:documentation "Decodes the input component value after a form submit (Decodes from string to type).")) (defclass translator () () @@ -63,6 +63,11 @@ "*SIMPLE-TRANSLATOR* is the default translator for any CINPUT component. Its encoder and decoder methods pass values unchanged") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;; Integer translator ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defclass translator-integer (translator) ((thousand-separator :initarg :thousand-separator :reader translator-thousand-separator @@ -115,7 +120,9 @@ (parse-integer (regex-replace-all (format nil "~a" thousand-separator) new-value "")) (parse-integer new-value))))) -;;========================================= +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;Folating point number translator ;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defclass translator-number (translator-integer) ((decimals-separator :initarg :decimals-separator @@ -197,7 +204,83 @@ (coerce result type)))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;; Dates translator ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +(defclass translator-date (translator) + ((date-format :initarg :date-format + :reader translator-date-fromat + :documentation "Sets the format of a date using a list where element are joined together and :DATE :MONTH and :YEAR are +expanded into day of the month for :DATE, month number for :MONTH and the year for :YEAR. The Default is the list '(:month \"/\" :date \"/\" :year)")) + (:default-initargs :date-format '(:month "/" :date "/" :year)) + (:documentation "A translator object encodes and decodes local-date object value passed to a html input component")) + + +#| +(defmethod translator-encode ((translator translator-number) (wcomponent wcomponent)) + (let* ((page (htcomponent-page wcomponent)) + (visit-object (wcomponent-parameter-value wcomponent :visit-object)) + (accessor (wcomponent-parameter-value wcomponent :accessor)) + (reader (wcomponent-parameter-value wcomponent :reader)) + (thousand-separator (translator-thousand-separator translator)) + (grouping-size (translator-grouping-size translator)) + (decimal-digits (translator-decimal-digits translator)) + (decimals-separator (translator-decimals-separator translator)) + (signum-directive (if (translator-always-show-signum translator) + "@" + "")) + (integer-control-string (if thousand-separator + (format nil "~~~d,' ,v:~aD" grouping-size signum-directive) + (format nil "~~~ad" signum-directive))) + + (value (page-req-parameter page (htcomponent-client-id wcomponent) nil))) + (if (component-validation-errors wcomponent) + value + (progn + (when (null visit-object) + (setf visit-object (htcomponent-page wcomponent))) + (multiple-value-bind (int-value dec-value) + (floor (cond + ((and (null reader) accessor) (funcall (fdefinition accessor) visit-object)) + (t (funcall (fdefinition reader) visit-object)))) + (progn + (setf dec-value (coerce dec-value 'float)) + (format nil "~a~a" (if thousand-separator + (string-trim " " (format nil integer-control-string thousand-separator int-value)) + (format nil integer-control-string int-value)) + (cond + ((and (= 0.0 (coerce dec-value 'double-float)) decimal-digits) + (format nil "~a~a" decimals-separator (make-string decimal-digits :initial-element #\0))) + (decimal-digits + (let ((frac-part (subseq (format nil "~f" dec-value) 2))) + (if (> (length frac-part) decimal-digits) + (setf frac-part (subseq frac-part 0 decimal-digits)) + (setf frac-part (concatenate 'string frac-part (make-string (- decimal-digits (length frac-part)) :initial-element #\0)))) + (format nil "~a~a" decimals-separator frac-part))) + (t (format nil "~a~a" decimals-separator (subseq (format nil "~f" dec-value) 2))))))))))) + +(defmethod translator-decode ((translator translator-number) (wcomponent wcomponent)) + (let* ((thousand-separator (translator-thousand-separator translator)) + (type (translator-coerce translator)) + (int-value) + (dec-value)) + (multiple-value-bind (client-id new-value) + (component-id-and-value wcomponent) + (declare (ignore client-id)) + (when thousand-separator + (setf new-value (regex-replace-all (format nil "~a" thousand-separator) new-value ""))) + (let ((decomposed-string (all-matches-as-strings "[0-9]+" new-value)) + (result)) + (setf int-value (parse-integer (concatenate 'string (first decomposed-string) (second decomposed-string))) + dec-value (expt 10 (length (second decomposed-string))) + result (/ int-value dec-value)) + (if (integerp result) + result + (coerce result type)))))) +|# ;;---------------------------------------------------------------------------------------- (defun add-exception (id reason) "Adds an exception for the given input component identified by its ID with the message expressed by REASON"