Re: Using Japanese and English strings, encodings



"drrobot" <drrobot@xxxxxxxxx> writes:

Hi! I'm new to lisp, a mediocre-but-trying-to-improve hobbyist
programmer, and just joined this newsgroup. If anyone can point me to
the answers for the following questions, I would greatly appreciate it.


1. In summary: How do I get a macro to turn into NOTHING at all (not
even NIL), or turn into multiple values (like is returned from the
VALUES function)?

I'm not sure if anyone else answered this specific question. In case
not, here's the answer: You can't.

(princ (eng "This is an english sentence.")
(jap "これは日本語の文章です。"))

So, here's a very brief sketch of a set of macros for doing
localization. This is probably ill-conceived in many ways and suffers
from one known bug due to esoterica of compile-time vs run-time
environments. It may be possible to work that out but I don't have the
time at the moment.

;; Some of these EVAL-WHENs wouldn't be needed if the test code was in
;; a separate file from the variabel and macro definitons.
(eval-when (:compile-toplevel :load-toplevel :execute)
(defvar *l10n-messages* (make-hash-table :test 'equal))
(defvar *languages* (make-hash-table))
(defvar *language* 'english))

(defmacro deflanguage (name)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(setf (gethash ',name *languages*) (make-hash-table :test 'equal))))

;; Default language.
(deflanguage english)

(defmacro defmessage (fmt language (&rest args) &body body)
`(setf (gethash ,fmt (gethash ',language *languages*)) #'(lambda (,@args) ,@body)))

(defmacro defsimple-message (fmt language (&rest args) localized-fmt)
`(defmessage ,fmt ,language (,@args) (format nil ,localized-fmt ,@args)))

(defmacro l10n (fmt &rest args)
(let ((parameters (as-symbols args)))
;; This is not quite right since the compilation environment may
;; not be the one we want to effect. But we really do want to do
;; this at compile time, not when the form the l10n form expands
;; into is run. Not sure if there's a better way.
(setf (gethash fmt *l10n-messages*) (list* fmt parameters))
`(progn
(eval-when (:compile-toplevel :load-toplevel :execute)
(defmessage ,fmt english (,@parameters) (format nil ,fmt ,@parameters)))
(funcall (gethash ,fmt (gethash *language* *languages*)) ,@args))))

(defmacro with-language ((language) &body body)
`(let ((*language* ',language))
,@body))

(defun as-symbols (args)
(loop for arg in args collect (gensym)))

(defun dump-messages ()
(maphash #'(lambda (k v) (format t "~a => ~s~%" k v)) *l10n-messages*))

(defun clear-messages ()
(clrhash *l10n-messages*))

Anyway, the idea is that whenever you want to generate a string that
may need to be localized you use the L10N macro which is more or less
equivalent to FORMAT with NIL as a first argument. However it also (at
compile time) squirrels away the string and the number of arguments
needed so you can define functions that generate eqivalent output in
other languages. For instance:

CL-USER> (l10n "I have written ~d book~:p." 1)
"I have written 1 book."

Now I can check what messages I may need to provide localizations for:

CL-USER> (dump-messages)
I have written ~d book~:p. => ("I have written ~d book~:p." #:G786)
NIL

Okay, so define a new language:

(deflanguage pig-latin)

and define how to render than message in my new language:

(defmessage "I have written ~d book~:p." pig-latin (x)
(format nil "Iway avhay ittentray ~d ook~:pbay." x))

And a test:

CL-USER> (defun test () (l10n "I have written ~d book~:p." 1))
TEST
CL-USER> (test)
"I have written 1 book."
CL-USER> (with-language (pig-latin) (test))
"Iway avhay ittentray 1 ookbay."

Obviously the DEFMESSAGE forms can be arbitrarily complex, using
arbitrary Lisp code to generate appropriate gramatical output.
Obviously using the format string as the key to look up the message
function is a bit fragile--if you fix a typo in the English message
you then have to go fix all the localized versions of that message.
But that's could be construed as a feature, as long as the system can
tell you which messages need to be localized in a particular language.
At least this system allows the original code to be written in a way
that works for the default language with hardly any extra effort and
automatically identifies strings that needs to be localized.

-Peter

--
Peter Seibel * peter@xxxxxxxxxxxxxxx
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/
.



Relevant Pages

  • Re: <resource> elements in WSCs
    ... >> never considered using it for localization. ... > Esposito's WSH Programmers Guide) give localization as their only ... > language can be quite a chore... ... don't have a simple string table externalization mechanism. ...
    (microsoft.public.scripting.wsh)
  • Re: <resource> elements in WSCs
    ... >> Esposito's WSH Programmers Guide) give localization as their only ... That the above is said about localization and you haven't ... >> applications written in one language to run as effectively in the other ... > don't have a simple string table externalization mechanism. ...
    (microsoft.public.scripting.wsh)
  • Re: dynamic variable naming
    ... My question would be what happenned when you needed a 3rd or 4th language. ... Firstly localization option would be a good way to go, ... public void ShowMessage(string outputMessage) ... variable gets its string value. ...
    (microsoft.public.dotnet.framework)
  • Re: Operator overloading in C
    ... All development of C as an independent language has ... making any changes or improvements to the standard ... The lack of a counted string data structure, ... Pointers can't be used for arg1 or arg2. ...
    (comp.std.c)
  • Re: syntax...
    ... B&D on the part of the language designer. ... probably handle concatenation of string literals by itself, ... bitwise XOR, or if not that, then exponentiation.) ...
    (comp.lang.misc)