GNU gettext is a set of functions, included in CLISP or the C library, which permit looking up translations of strings through message catalogs. It is also a set of tools which makes the translation maintenance easy for the translator and the program maintainer.
The GNU gettext functions are available in CLISP in the
“I18N” package, which is EXT:RE-EXPORT
ed from the “EXT”
package.
This module is present in the base linking set by default.
When this module is present, *FEATURES*
contains the symbol :I18N
.
(I18N:GETTEXT
MSGID
&OPTIONAL
DOMAIN
CATEGORY
)
MSGID
,
in the given DOMAIN
, depending on the given CATEGORY
.
MSGID
should be an ASCII string, and is normally the English message.
(I18N:NGETTEXT
MSGID
msgid_plural
n
&OPTIONAL
DOMAIN
CATEGORY
)
MSGID
and n
in the given DOMAIN
, depending on the given
CATEGORY
. MSGID
and msgid_plural
should be ASCII strings, and are normally the English singular and
English plural variant of the message, respectively.
The DOMAIN
is a string identifier denoting the program that
is requesting the translation. The pathname of the message catalog
depends on the DOMAIN
: usually it is located at
TEXTDOMAINDIR/l/LC_MESSAGES/domain.mo
, where
l
is the ISO
639-2 code of the language.
The notion of DOMAIN
allows several Lisp programs running in the same
image to request translations independently of each other.
Function I18N:TEXTDOMAIN
. (
is a place that returns the default
I18N:TEXTDOMAIN
)DOMAIN
, used when no DOMAIN
argument is passed to the I18N:GETTEXT
and
I18N:NGETTEXT
functions. It is SETF
able.
(
is usually used
during the startup phase of a program.
Note that the default SETF
I18N:TEXTDOMAIN
)DOMAIN
is not saved in a memory image.
The use of (
is
recommended only for programs that are so simple that they will never
need more than one SETF
I18N:TEXTDOMAIN
)DOMAIN
.
Function I18N:TEXTDOMAINDIR
. (
is a place that returns the base directory, called
I18N:TEXTDOMAINDIR
DOMAIN
)TEXTDOMAINDIR
above, where the message
catalogs for the given DOMAIN
are assumed to be installed.
It is SETF
able.
(
is usually used
during the startup phase of a program, and should be used because only
the program knows where its message catalogs are installed.
Note that the SETF
I18N:TEXTDOMAINDIR
)TEXTDOMAINDIR
s
are not saved in a memory image.
The CATEGORY
argument of the I18N:GETTEXT
and I18N:NGETTEXT
functions denotes which LOCALE
facet the result should depend on.
The possible values are a platform-dependent subset of
:LC_ADDRESS
, :LC_ALL
, :LC_COLLATE
, :LC_CTYPE
, :LC_IDENTIFICATION
, :LC_MEASUREMENT
, :LC_MESSAGES
, :LC_MONETARY
, :LC_NAME
, :LC_NUMERIC
, :LC_PAPER
, :LC_TELEPHONE
, :LC_TIME
The use of these values is useful for users who have a
character/time/collation/money handling set differently from the usual
message handling.
Note that when a CATEGORY
argument is used, the message catalog
location depends on the CATEGORY
: it will be expected at
TEXTDOMAINDIR/ll/category/domain.mo
.
A non-internationalized program simulating a restaurant dialogue might look as follows.
(setq n (parse-integer (first EXT:*ARGS*
)))
(format t "~A~%" "'Your command, please?', asked the waiter.")
(format t "~@?~%"
(if (= n 1) "a piece of cake" "~D pieces of cake")
n)
After being internationalized, all strings are wrapped in
I18N:GETTEXT
calls, and I18N:NGETTEXT
is used for plurals.
Also, I18N:TEXTDOMAINDIR
is assigned a value; in our case, for simplicity,
the current directory.
(setf (textdomain) "prog")
(setf (textdomaindir "prog") "./")
(setq n (parse-integer (first EXT:*ARGS*
)))
(format t "~A~%"
(gettext "'Your command, please?', asked the waiter."))
(format t "~@?~%"
(ngettext "a piece of cake" "~D pieces of cake" n)
n)
For ease of reading, it is customary to define an abbreviation
for the I18N:GETTEXT
function. An underscore is customary.
(setf (textdomaindir "prog") "./")
(defun _ (msgid) (gettext msgid "prog"))
(setq n (parse-integer (first EXT:*ARGS*
)))
(format t "~A~%"
(_"'Your command, please?', asked the waiter."))
(format t "~@?~%"
(ngettext "a piece of cake" "~D pieces of cake" n "prog")
n)
Now the program's maintainer creates a message catalog template through the command
$
xgettext -o prog.pot prog.lisp
xgettext version 0.11 or higher is required here.
The message catalog template looks roughly like this.
msgid "'Your command, please?', asked the waiter." msgstr "" msgid "a piece of cake" msgid_plural "%d pieces of cake" msgstr[0] "" msgstr[1] ""
Then a French translator creates a French message catalog
msgid "" msgstr "" "Content-Type: text/plain; charset=ISO-8859-1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "'Your command, please?', asked the waiter." msgstr "«Votre commande, s'il vous plait», dit le garçon." # Les gateaux allemands sont les meilleurs du monde. msgid "a piece of cake" msgid_plural "%d pieces of cake" msgstr[0] "un morceau de gateau" msgstr[1] "%d morceaux de gateau"
and sends it to the program's maintainer.
The program's maintainer compiles the catalog as follows:
$
mkdir -p ./fr/LC_MESSAGES$
msgfmt -o ./fr/LC_MESSAGES/prog.mo prog.fr.po
When a user in a french LOCALE
then runs the program
$
clisp prog.lisp 2
she will get the output
«Votre commande, s'il vous plait», dit le garçon. 2 morceaux de gateau
(I18N:SET-LOCALE
&OPTIONAL
CATEGORY
LOCALE
)
This is an interface to
setlocale
.
When LOCALE
is missing or NIL
, return the current one.
When CATEGORY
is missing or NIL
, return all categories
as a LIST
.
(I18N:LOCALE-CONV
)
This is an interface to
localeconv
.
Returns a I18N:LOCALE-CONV structure.
(I18N:LANGUAGE-INFORMATION
&OPTIONAL
item
)
This is an interface to
nl_langinfo
(UNIX)
and GetLocaleInfo
(Win32).
When item
is missing or NIL
,
return all available information as a LIST
.
These notes document CLISP version 2.49.93+ | Last modified: 2018-02-19 |