From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Bruno Haible Newsgroups: gmane.lisp.guile.devel Subject: Re: doc gettext Date: Mon, 10 Jan 2005 22:11:05 +0100 Message-ID: <200501102211.05669.bruno@clisp.org> References: <873bxarzgk.fsf@zip.com.au> NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_p9u4BWH8Jzt6LV/" X-Trace: sea.gmane.org 1105391817 14687 80.91.229.6 (10 Jan 2005 21:16:57 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 10 Jan 2005 21:16:57 +0000 (UTC) Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Mon Jan 10 22:16:47 2005 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1Co6u6-0004hC-00 for ; Mon, 10 Jan 2005 22:16:46 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Co75c-0007rU-A5 for guile-devel@m.gmane.org; Mon, 10 Jan 2005 16:28:40 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Co74u-0007OT-LV for guile-devel@gnu.org; Mon, 10 Jan 2005 16:27:56 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Co74k-0007Ji-B0 for guile-devel@gnu.org; Mon, 10 Jan 2005 16:27:49 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Co74j-0007JL-Vo for guile-devel@gnu.org; Mon, 10 Jan 2005 16:27:46 -0500 Original-Received: from [81.80.162.195] (helo=ftp.ilog.fr) by monty-python.gnu.org with esmtp (Exim 4.34) id 1Co6rC-0005MP-K3 for guile-devel@gnu.org; Mon, 10 Jan 2005 16:13:47 -0500 Original-Received: from laposte.ilog.fr (cerbere-qfe0 [81.80.162.193]) by ftp.ilog.fr (8.13.1/8.13.0) with ESMTP id j0ALDiAH010126; Mon, 10 Jan 2005 22:13:45 +0100 (MET) Original-Received: from honolulu.ilog.fr ([172.16.15.122]) by laposte.ilog.fr (8.13.1/8.13.1) with ESMTP id j0ALDb0b014761; Mon, 10 Jan 2005 22:13:37 +0100 (MET) Original-Received: from localhost (localhost [127.0.0.1]) by honolulu.ilog.fr (Postfix) with ESMTP id A72171BB7C; Mon, 10 Jan 2005 21:11:06 +0000 (UTC) Original-To: Kevin Ryde , guile-devel@gnu.org User-Agent: KMail/1.5 In-Reply-To: <873bxarzgk.fsf@zip.com.au> X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: main.gmane.org gmane.lisp.guile.devel:4647 X-Report-Spam: http://spam.gmane.org/gmane.lisp.guile.devel:4647 --Boundary-00=_p9u4BWH8Jzt6LV/ Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Kevin Ryde wrote: > I'm looking at the text below to expand what's in the guile reference > manual for gettext. You can also use text from my original proposal (attached). It has the merit of explaining the terms (domain, category, ...) that are used in the refman. Also it contains complete workable examples. (You need to change the set! notation to the optional-argument notation that is used in guile, though.) > I'm a bit unsure about bind-textdomain-codeset. Thinking about it, if > Guile gets its own notion of coding systems or whatever in the future > then I'm wondering if that function might become obsolete, or even > actively harmful. When that happens, the bind-textdomain-codeset function should become a nop. > It does some good now, but maybe some strong > warning against possible future change is needed. But since in the present this function is _necessary_, I don't think it's useful to make people doubt whether they should use it or not. When bind-textdomain-codeset is no longer needed, you can easily make the compiler emit a warning when it's used. Bruno --Boundary-00=_p9u4BWH8Jzt6LV/ Content-Type: text/html; charset="iso-8859-1"; name="guile-gettext.html" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="guile-gettext.html" Implementation Notes for GNU CLISP.

Internationalization

"Internationalization" means to prepare a program so that it can use multiple national languages and national cultural conventions without requiring further source code changes. Localization means providing the data - mostly textual translations - necessary for an internationalized program to work in a particular language and with particular cultural conventions.

guile supports internationalized Lisp programs, through GNU gettext.

The GNU<= /a> gettext binding

GNU gettext is a set of functions, included in guile= 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 guile= in the =E2=80=9Ci18n=E2=80=9D module.

(i18n:= gettext MSGID [= DOMAIN [CATEGORY]])
returns the translation of the message M= SGID, 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 [= DOMAIN [CATEGORY]])
returns the plural form of the translation for of 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.

1. Domain

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 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:textdoma= in(i18n:textdo= main) is a place that returns the default DOMAIN, used when no DOMAIN argument is passed to the i18n:= gettext and i18n:ngettext functions. It is SET!able. SET! i18n:textdomain is usually used during the startup phase of a program. Note that the default DOMAIN is not saved in a memory image. The use of SET! i18n:textdomain is recommended only for programs that are so simple that they will never need more than one DOMAIN.

Function i18n:textd= omaindir(i18n:tex= tdomaindir DOMAIN) is a place that returns the base directory, called TEXTDOMAINDIR above, where the message catalogs for the given = DOMAIN are assumed to be installed. It is SET!able. SET! i18n:textdomaindir 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 TEXTDOMAINDIRs are not saved in a memory image.

Function i18n:textdomain-codeset(i18n:textdomain-codeset DOMAIN) is a place that returns the specified encoding for the strings returned by i18n:gettext and i18n:ngettext. The default value is #f, denoting the default locale encoding. It is SET!able. The value it is set to must be an encoding name known to the system iconv() function. SET! i18n:textdomain-codeset is usually used during the startup phase of a program whose internal string representation is not in the default locale encoding. Note that the TEXTDOMAIN-CODESETs are not saved in a memory image.

2. Category

The CATEGORY argument of the i18n:gettext and i18n:ngettext functions denotes which locale facet the result should depend on. The default value is :LC_MESSAGES. Other possible values are :LC_CTYPE, :LC_TIME, :LC_COLLATE, :LC_MONETARY. 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.

3. Example

A non-internationalized program simulating a restaurant dialogue might look as follows.

Example 1. prog.scm

(define n (parse-integer (first *ARGS*)))

(for= mat t "~A~%" "'Your command, please?', asked the waiter.")

(format t= "~@?~%"
(if (=3D n 1) "a piece of cake" "~D pieces of cake")<= br> n)

After being internationalized, all strings are wrapped in i18n:gettext calls, and i18n:ngettext is used for plurals. Also, i18n:textdomaindir<= /tt> is assigned a value; in our case, for simplicity, the current directory.

Example 2. prog.scm

(set! (textdomain) "prog")
(set! (te= xtdomaindir "prog") "./")

(define n (parse-integer (first *ARGS*)))

(for= mat t "~A~%"
(gettext "'Your command, please?', asked the wait= er."))

(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.

Example 3. prog.scm

(set! (textdomaindir "prog") "./")
(= define (_ msgid) (gettext msgid "prog"))

(define n (parse-integer (f= irst *ARGS*)))

(for= mat t "~A~%"
(_"'Your command, please?', asked the waiter."))<= br>
(format t "~@?~%"
(ngettext "a piece of cake" "~D piece= s of cake" n "prog")
n)

Now the program's maintainer creates a message catalog template through the command

bash$ xgettext -o prog.pot prog.scm

Note

xgettext version 0.14.2 or higher is required here.

The message catalog template looks roughly like this.

Example 29.4. prog.pot

msgid "'Your command, please?', asked t=
he 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

Example 29.5. prog.fr.po

msgid ""
msgstr ""
"Content-Type:= text/plain; charset=3DISO-8859-1\n"
"Plural-Forms: nplurals=3D2; plural= =3D(n > 1);\n"

msgid "'Your command, please?', asked the waiter."=
msgstr "=C2=ABVotre commande, s'il vous plait=C2=BB, dit le gar=C3=A7on= =2E"

# Les gateaux allemands sont les meilleurs du monde.
msgid "= a piece of cake"
msgid_plural "%d pieces of cake"
msgstr[0] "un morce= au 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:

bash$ mkdir -p ./fr/LC_MESSAGES
bash$ msgfmt= -o ./fr/LC_MESSAGES/prog.mo prog.fr.po

When a user in a french locale then runs the program

bash$ guile prog.scm 2

she will get the output

    =C2=ABVotre commande, s'il vous plait=C2=BB=
, dit le gar=C3=A7on.
2 morceaux de gateau


--Boundary-00=_p9u4BWH8Jzt6LV/ Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel --Boundary-00=_p9u4BWH8Jzt6LV/--