1<?xml version="1.0" encoding="UTF-8"?>
2
3<section id="i18n-mod"><title>Internationalization of User Programs</title>
4
5<section id="ggettext"><title>The &ggettext;</title>
6
7<para>&ggettext; is a set of functions, included in &clisp; or the
8&c-lang; library, which permit looking up translations of strings
9through message catalogs. It is also a set of tools which makes the
10translation maintenance easy for the translator and the program
11maintainer.</para>
12
13<para>The &ggettext; functions are available in &clisp; in the
14&i18n-pac; package, which is &re-export;ed from the &ext-pac;
15package.</para>
16&base-module;
17<simpara>When this module is present, &features-my;
18 contains the symbol <constant>:I18N</constant>.</simpara>
19
20<variablelist>
21 <varlistentry id="gettext"><term><code>(&gettext;
22    &msgid; &optional-amp; &domain; &category;)</code></term>
23  <listitem><simpara>returns the translation of the message &msgid;,
24    in the given &domain;, depending on the given &category;.
25    &msgid; should be an &ascii; string, and is normally the English message.
26 </simpara></listitem></varlistentry>
27 <varlistentry id="ngettext"><term><code>(&ngettext;
28    &msgid; <replaceable>msgid_plural</replaceable>
29    &n-r; &optional-amp; &domain; &category;)</code></term>
30  <listitem><simpara>returns the plural form of the translation for of
31    &msgid; and &n-r; in the given &domain;, depending on the given
32    &category;.  &msgid; and <replaceable>msgid_plural</replaceable>
33    should be &ascii; strings, and are normally the English singular and
34    English plural variant of the message, respectively.
35 </simpara></listitem></varlistentry>
36</variablelist>
37
38<section id="domain"><title>Domain</title>
39 <para>The &domain; is a string identifier denoting the program that
40is requesting the translation.  The pathname of the message catalog
41depends on the &domain;: usually it is located at
42<filename>TEXTDOMAINDIR/l/LC_MESSAGES/domain.mo</filename>, where
43&l-r; is the <ulink url="http://www.loc.gov/standards/iso639-2/">ISO
44 639-2</ulink> code of the language.
45The notion of &domain; allows several Lisp programs running in the same
46image to request translations independently of each other.</para>
47
48<formalpara id="textdomain"><title>Function &textdomain;</title>
49<para><code>(&textdomain;)</code> is a &place; that returns the default
50 &domain;, used when no &domain; argument is passed to the &gettext; and
51 &ngettext; functions.  It is &setf;able.
52<code>(&setf; &textdomain;)</code> is usually used
53during the startup phase of a program.
54Note that the default &domain; is not saved in a &mem-image;.
55The use of <code>(&setf; &textdomain;)</code> is
56recommended only for programs that are so simple that they will never
57need more than one &domain;.</para></formalpara>
58
59<formalpara id="textdomaindir"><title>Function &textdomaindir;</title>
60<para><code>(&textdomaindir; &domain;)</code>
61is a &place; that returns the base directory, called
62<filename>TEXTDOMAINDIR</filename> above, where the message
63catalogs for the given &domain; are assumed to be installed.
64It is &setf;able.
65<code>(&setf; &textdomaindir;)</code> is usually used
66during the startup phase of a program, and should be used because only
67the program knows where its message catalogs are installed.
68Note that the <filename>TEXTDOMAINDIR</filename>s
69are not saved in a &mem-image;.</para></formalpara>
70
71</section>
72
73<section id="category"><title>Category</title>
74<para>The &category; argument of the &gettext; and &ngettext;
75functions denotes which &locale; facet the result should depend on.
76The possible values are a platform-dependent subset of
77<simplelist type="inline">
78<member><constant>:LC_ADDRESS</constant></member>
79<member><constant>:LC_ALL</constant></member>
80<member><constant>:LC_COLLATE</constant></member>
81<member><constant>:LC_CTYPE</constant></member>
82<member><constant>:LC_IDENTIFICATION</constant></member>
83<member><constant>:LC_MEASUREMENT</constant></member>
84<member><constant>:LC_MESSAGES</constant></member>
85<member><constant>:LC_MONETARY</constant></member>
86<member><constant>:LC_NAME</constant></member>
87<member><constant>:LC_NUMERIC</constant></member>
88<member><constant>:LC_PAPER</constant></member>
89<member><constant>:LC_TELEPHONE</constant></member>
90<member><constant>:LC_TIME</constant></member></simplelist>
91The use of these values is useful for users who have a
92character/time/collation/money handling set differently from the usual
93message handling.
94Note that when a &category; argument is used, the message catalog
95location depends on the &category;: it will be expected at
96<filename>TEXTDOMAINDIR/ll/category/domain.mo</filename>.</para>
97</section>
98
99<section id="i18n-example"><title>Internationalization Example</title>
100
101<para>A non-internationalized program simulating a restaurant dialogue
102might look as follows.</para>
103
104<formalpara id="i18n-non-i"><title>prog.lisp</title>
105<para><programlisting language="lisp">
106(setq n (parse-integer (first &args;)))
107
108(format t "~A~%" "'Your command, please?', asked the waiter.")
109
110(format t "~@?~%"
111          (if (= n 1) "a piece of cake" "~D pieces of cake")
112          n)
113</programlisting></para></formalpara>
114
115<para>After being internationalized, all strings are wrapped in
116&gettext; calls, and &ngettext; is used for plurals.
117Also, &textdomaindir; is assigned a value; in our case, for simplicity,
118the current directory.</para>
119
120<formalpara id="i18n-i"><title>prog.lisp</title>
121<para><programlisting language="lisp">
122(setf (textdomain) "prog")
123(setf (textdomaindir "prog") "./")
124
125(setq n (parse-integer (first &args;)))
126
127(format t "~A~%"
128          (gettext "'Your command, please?', asked the waiter."))
129
130(format t "~@?~%"
131          (ngettext "a piece of cake" "~D pieces of cake" n)
132          n)
133</programlisting></para></formalpara>
134
135<para>For ease of reading, it is customary to define an abbreviation
136for the &gettext; function.  An underscore is customary.</para>
137
138<formalpara id="i18n-i-abbrev"><title>prog.lisp</title>
139<para><programlisting language="lisp">
140(setf (textdomaindir "prog") "./")
141(defun _ (msgid) (gettext msgid "prog"))
142
143(setq n (parse-integer (first &args;)))
144
145(format t "~A~%"
146          (_"'Your command, please?', asked the waiter."))
147
148(format t "~@?~%"
149          (ngettext "a piece of cake" "~D pieces of cake" n "prog")
150          n)
151</programlisting></para></formalpara>
152
153<para>Now the program's maintainer creates a message catalog template
154through the command
155<screen>
156&sh-prompt; xgettext -o prog.pot prog.lisp
157</screen>
158<note><title>Note</title>
159 <para>xgettext version 0.11 or higher is required here.</para></note></para>
160
161<para>The message catalog template looks roughly like this.</para>
162
163<formalpara id="i18n-pot"><title>prog.pot</title>
164<para><programlisting language="pot">
165msgid "'Your command, please?', asked the waiter."
166msgstr ""
167
168msgid "a piece of cake"
169msgid_plural "%d pieces of cake"
170msgstr[0] ""
171msgstr[1] ""
172</programlisting></para></formalpara>
173
174<para>Then a French translator creates a French message catalog</para>
175
176<formalpara id="i18n-fr-po"><title>prog.fr.po</title>
177<para><programlisting language="po">
178msgid ""
179msgstr ""
180"Content-Type: text/plain; charset=ISO-8859-1\n"
181"Plural-Forms: nplurals=2; plural=(n &gt; 1);\n"
182
183msgid "'Your command, please?', asked the waiter."
184msgstr "&laquo;Votre commande, s'il vous plait&raquo;, dit le gar&ccedil;on."
185
186# Les gateaux allemands sont les meilleurs du monde.
187msgid "a piece of cake"
188msgid_plural "%d pieces of cake"
189msgstr[0] "un morceau de gateau"
190msgstr[1] "%d morceaux de gateau"
191</programlisting></para></formalpara>
192
193<para>and sends it to the program's maintainer.</para>
194
195<para>The program's maintainer compiles the catalog as follows:
196<screen>
197&sh-prompt; mkdir -p ./fr/LC_MESSAGES
198&sh-prompt; msgfmt -o ./fr/LC_MESSAGES/prog.mo prog.fr.po
199</screen></para>
200
201<para>When a user in a french &locale; then runs the program
202<screen>
203&sh-prompt; clisp prog.lisp 2
204</screen>
205she will get the output
206<screen>
207    &laquo;Votre commande, s'il vous plait&raquo;, dit le gar&ccedil;on.
208    2 morceaux de gateau
209</screen>
210</para>
211</section>
212
213</section>
214
215<section id="i18n-locale"><title>Locale</title>
216
217<variablelist>
218<varlistentry id="set-locale"><term><code>(&set-locale;
219   &optional-amp; &category; &locale;)</code></term>
220 <listitem><simpara>This is an interface to
221   <function role="unix">setlocale</function>.</simpara>
222  <simpara>When &locale; is missing or &nil;, return the current one.</simpara>
223  <simpara>When &category; is missing or &nil;, return all categories
224   as a &list-t;.</simpara></listitem></varlistentry>
225
226<varlistentry id="locale-conv"><term><code>(&locale-conv;)</code></term>
227 <listitem><simpara>This is an interface to
228   <function role="unix">localeconv</function>.</simpara>
229  <simpara>Returns a <type>I18N:LOCALE-CONV</type>
230   structure.</simpara></listitem></varlistentry>
231
232<varlistentry id="lang-info"><term><code>(&lang-info;
233   &optional-amp; &item-r;)</code></term>
234 <listitem><simpara>This is an interface to
235   <function role="unix">nl_langinfo</function> (&unix;)
236   and <function role="win32">GetLocaleInfo</function> (&win32;).</simpara>
237  <simpara>When &item-r; is missing or &nil;,
238   return all available information as a &list-t;.</simpara>
239</listitem></varlistentry></variablelist>
240
241</section>
242</section>
243