~jtaylor/ubuntu/oneiric/genshi/dh_python2

« back to all changes in this revision

Viewing changes to doc/i18n.html

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-05-05 02:05:51 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100505020551-zmiep9cjs3s5c093
Tags: 0.6-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  - debian/rules: Enable testsuite.
  - Update maintainer according to specification.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
<html lang="en">
4
4
<head>
5
5
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
 
<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/">
 
6
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/">
7
7
<title>Genshi: Internationalization and Localization</title>
8
8
<link rel="stylesheet" href="common/style/edgewall.css" type="text/css">
9
9
</head>
10
10
<body>
11
11
<div class="document" id="internationalization-and-localization">
12
12
    <div id="navigation">
13
 
      <span class="projinfo">Genshi 0.5.1</span>
 
13
      <span class="projinfo">Genshi 0.6</span>
14
14
      <a href="index.html">Documentation Index</a>
15
15
    </div>
16
16
<h1 class="title">Internationalization and Localization</h1>
17
 
<p>Genshi provides basic supporting infrastructure for internationalizing
18
 
and localizing templates. That includes functionality for extracting localizable
19
 
strings from templates, as well as a template filter that can apply translations
20
 
to templates as they get rendered.</p>
21
 
<p>This support is based on <a class="reference" href="http://www.gnu.org/software/gettext/">gettext</a> message catalogs and the <a class="reference" href="http://docs.python.org/lib/module-gettext.html">gettext Python
22
 
module</a>. The extraction process can be used from the API level, or through the
23
 
front-ends implemented by the <a class="reference" href="http://babel.edgewall.org/">Babel</a> project, for which Genshi provides a
24
 
plugin.</p>
25
 
<div class="contents topic">
26
 
<p class="topic-title first"><a id="contents" name="contents">Contents</a></p>
 
17
<p>Genshi provides comprehensive supporting infrastructure for internationalizing
 
18
and localizing templates. That includes functionality for extracting
 
19
localizable strings from templates, as well as a template filter and special
 
20
directives that can apply translations to templates as they get rendered.</p>
 
21
<p>This support is based on <a class="reference external" href="http://www.gnu.org/software/gettext/">gettext</a> message catalogs and the <a class="reference external" href="http://docs.python.org/lib/module-gettext.html">gettext Python
 
22
module</a>. The extraction process can be used from the API level, or through
 
23
the front-ends implemented by the <a class="reference external" href="http://babel.edgewall.org/">Babel</a> project, for which Genshi provides
 
24
a plugin.</p>
 
25
<div class="contents topic" id="contents">
 
26
<p class="topic-title first">Contents</p>
27
27
<ul class="auto-toc simple">
28
 
<li><a class="reference" href="#basics" id="id1" name="id1">1   Basics</a></li>
29
 
<li><a class="reference" href="#extraction" id="id2" name="id2">2   Extraction</a><ul class="auto-toc">
30
 
<li><a class="reference" href="#configuration-options" id="id3" name="id3">2.1   Configuration Options</a></li>
31
 
</ul>
32
 
</li>
33
 
<li><a class="reference" href="#translation" id="id4" name="id4">3   Translation</a></li>
34
 
<li><a class="reference" href="#related-considerations" id="id5" name="id5">4   Related Considerations</a><ul class="auto-toc">
35
 
<li><a class="reference" href="#unicode" id="id6" name="id6">4.1   Unicode</a></li>
36
 
<li><a class="reference" href="#date-and-time" id="id7" name="id7">4.2   Date and Time</a></li>
37
 
<li><a class="reference" href="#formatting-and-locale-data" id="id8" name="id8">4.3   Formatting and Locale Data</a></li>
 
28
<li><a class="reference internal" href="#basics" id="id3">1   Basics</a><ul class="auto-toc">
 
29
<li><a class="reference internal" href="#language-tagging" id="id4">1.1   Language Tagging</a></li>
 
30
</ul>
 
31
</li>
 
32
<li><a class="reference internal" href="#id1" id="id5">2   Template Directives</a><ul class="auto-toc">
 
33
<li><a class="reference internal" href="#messages" id="id6">2.1   Messages</a></li>
 
34
<li><a class="reference internal" href="#comments-and-domains" id="id7">2.2   Comments and Domains</a></li>
 
35
</ul>
 
36
</li>
 
37
<li><a class="reference internal" href="#extraction" id="id8">3   Extraction</a><ul class="auto-toc">
 
38
<li><a class="reference internal" href="#babel-integration" id="id9">3.1   Babel Integration</a></li>
 
39
<li><a class="reference internal" href="#configuration-options" id="id10">3.2   Configuration Options</a></li>
 
40
</ul>
 
41
</li>
 
42
<li><a class="reference internal" href="#translation" id="id11">4   Translation</a></li>
 
43
<li><a class="reference internal" href="#related-considerations" id="id12">5   Related Considerations</a><ul class="auto-toc">
 
44
<li><a class="reference internal" href="#unicode" id="id13">5.1   Unicode</a></li>
 
45
<li><a class="reference internal" href="#date-and-time" id="id14">5.2   Date and Time</a></li>
 
46
<li><a class="reference internal" href="#formatting-and-locale-data" id="id15">5.3   Formatting and Locale Data</a></li>
38
47
</ul>
39
48
</li>
40
49
</ul>
41
50
</div>
42
 
<div class="section">
43
 
<h1><a id="basics" name="basics">1   Basics</a></h1>
 
51
<div class="section" id="basics">
 
52
<h1>1   Basics</h1>
44
53
<p>The simplest way to internationalize and translate templates would be to wrap
45
 
all localizable strings in a <tt class="docutils literal"><span class="pre">gettext()</span></tt> function call (which is often aliased
46
 
to <tt class="docutils literal"><span class="pre">_()</span></tt> for brevity). In that case, no extra template filter is required.</p>
 
54
all localizable strings in a <tt class="docutils literal"><span class="pre">gettext()</span></tt> function call (which is often
 
55
aliased to <tt class="docutils literal"><span class="pre">_()</span></tt> for brevity). In that case, no extra template filter is
 
56
required.</p>
47
57
<div class="highlight"><pre><span class="nt">&lt;p&gt;</span><span class="cp">${</span><span class="n">_</span><span class="p">(</span><span class="s">"Hello, world!"</span><span class="p">)</span><span class="cp">}</span><span class="nt">&lt;/p&gt;</span>
48
58
</pre></div>
49
59
<p>However, this approach results in significant “character noise” in templates,
50
60
making them harder to read and preview.</p>
51
61
<p>The <tt class="docutils literal"><span class="pre">genshi.filters.Translator</span></tt> filter allows you to get rid of the
52
 
explicit <a class="reference" href="http://www.gnu.org/software/gettext/">gettext</a> function calls, so you can continue to just write:</p>
 
62
explicit <a class="reference external" href="http://www.gnu.org/software/gettext/">gettext</a> function calls, so you can (often) just continue to write:</p>
53
63
<div class="highlight"><pre><span class="nt">&lt;p&gt;</span>Hello, world!<span class="nt">&lt;/p&gt;</span>
54
64
</pre></div>
55
65
<p>This text will still be extracted and translated as if you had wrapped it in a
56
66
<tt class="docutils literal"><span class="pre">_()</span></tt> call.</p>
57
67
<div class="note">
58
68
<p class="first admonition-title">Note</p>
59
 
<p class="last">For parameterized or pluralizable messages, you need to continue using
60
 
the appropriate <tt class="docutils literal"><span class="pre">gettext</span></tt> functions.</p>
 
69
<p class="last">For parameterized or pluralizable messages, you need to use the
 
70
special <a class="reference internal" href="#template-directives">template directives</a> described below, or use the
 
71
corresponding <tt class="docutils literal"><span class="pre">gettext</span></tt> function in embedded Python expressions.</p>
61
72
</div>
62
73
<p>You can control which tags should be ignored by this process; for example, it
63
74
doesn't really make sense to translate the content of the HTML
65
76
by default.</p>
66
77
<p>Attribute values can also be automatically translated. The default is to
67
78
consider the attributes <tt class="docutils literal"><span class="pre">abbr</span></tt>, <tt class="docutils literal"><span class="pre">alt</span></tt>, <tt class="docutils literal"><span class="pre">label</span></tt>, <tt class="docutils literal"><span class="pre">prompt</span></tt>, <tt class="docutils literal"><span class="pre">standby</span></tt>,
68
 
<tt class="docutils literal"><span class="pre">summary</span></tt>, and <tt class="docutils literal"><span class="pre">title</span></tt>, which is a list that makes sense for HTML documents.
69
 
Of course, you can tell the translator to use a different set of attribute
70
 
names, or none at all.</p>
71
 
<p>In addition, you can control automatic translation in your templates using the
72
 
<tt class="docutils literal"><span class="pre">xml:lang</span></tt> attribute. If the value of that attribute is a literal string, the
73
 
contents and attributes of the element will be ignored:</p>
 
79
<tt class="docutils literal"><span class="pre">summary</span></tt>, and <tt class="docutils literal"><span class="pre">title</span></tt>, which is a list that makes sense for HTML
 
80
documents.  Of course, you can tell the translator to use a different set of
 
81
attribute names, or none at all.</p>
 
82
<div class="section" id="language-tagging">
 
83
<h2>1.1   Language Tagging</h2>
 
84
<p>You can control automatic translation in your templates using the <tt class="docutils literal"><span class="pre">xml:lang</span></tt>
 
85
attribute. If the value of that attribute is a literal string, the contents and
 
86
attributes of the element will be ignored:</p>
74
87
<div class="highlight"><pre><span class="nt">&lt;p</span> <span class="na">xml:lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>Hello, world!<span class="nt">&lt;/p&gt;</span>
75
88
</pre></div>
76
89
<p>On the other hand, if the value of the <tt class="docutils literal"><span class="pre">xml:lang</span></tt> attribute contains a Python
81
94
<span class="nt">&lt;/html&gt;</span>
82
95
</pre></div>
83
96
</div>
84
 
<div class="section">
85
 
<h1><a id="extraction" name="extraction">2   Extraction</a></h1>
 
97
</div>
 
98
<div class="section" id="id1">
 
99
<span id="template-directives"></span><h1>2   Template Directives</h1>
 
100
<p>Sometimes localizable strings in templates may contain dynamic parameters, or
 
101
they may depend on the numeric value of some variable to choose a proper
 
102
plural form. Sometimes the strings contain embedded markup, such as tags for
 
103
emphasis or hyperlinks, and you don't want to rely on the people doing the
 
104
translations to know the syntax and escaping rules of HTML and XML.</p>
 
105
<p>In those cases the simple text extraction and translation process described
 
106
above is not sufficient. You could just use <tt class="docutils literal"><span class="pre">gettext</span></tt> API functions in
 
107
embedded Python expressions for parameters and pluralization, but that does
 
108
not help when messages contain embedded markup. Genshi provides special
 
109
template directives for internationalization that attempt to provide a
 
110
comprehensive solution for this problem space.</p>
 
111
<p>To enable these directives, you'll need to register them with the templates
 
112
they are used in. You can do this by adding them manually via the
 
113
<tt class="docutils literal"><span class="pre">Template.add_directives(namespace,</span> <span class="pre">factory)</span></tt> (where <tt class="docutils literal"><span class="pre">namespace</span></tt> would be
 
114
“http://genshi.edgewall.org/i18n” and <tt class="docutils literal"><span class="pre">factory</span></tt> would be an instance of the
 
115
<tt class="docutils literal"><span class="pre">Translator</span></tt> class). Or you can just call the <tt class="docutils literal"><span class="pre">Translator.setup(template)</span></tt>
 
116
class method, which both registers the directives and adds the translation
 
117
filter.</p>
 
118
<p>After the directives have been registered with the template engine on the
 
119
Python side of your application, you need to declare the corresponding
 
120
directive namespace in all markup templates that use them. For example:</p>
 
121
<div class="highlight"><pre><span class="nt">&lt;html</span> <span class="na">xmlns:py=</span><span class="s">"http://genshi.edgewall.org/"</span>
 
122
      <span class="na">xmlns:i18n=</span><span class="s">"http://genshi.edgewall.org/i18n/"</span><span class="nt">&gt;</span>
 
123
  …
 
124
<span class="nt">&lt;/html&gt;</span>
 
125
</pre></div>
 
126
<p>These directives only make sense in the context of <a class="reference external" href="xml-templates.html">markup templates</a>. For
 
127
<a class="reference external" href="text-templates.html">text templates</a>, you can just use the corresponding <tt class="docutils literal"><span class="pre">gettext</span></tt> API calls as needed.</p>
 
128
<div class="note">
 
129
<p class="first admonition-title">Note</p>
 
130
<p class="last">The internationalization directives are still somewhat experimental
 
131
and have some known issues. However, the attribute language they
 
132
implement should be stable and is not subject to change
 
133
substantially in future versions.</p>
 
134
</div>
 
135
<div class="section" id="messages">
 
136
<h2>2.1   Messages</h2>
 
137
<div class="section" id="i18n-msg">
 
138
<h3>2.1.1   <tt class="docutils literal"><span class="pre">i18n:msg</span></tt></h3>
 
139
<p>This is the basic directive for defining localizable text passages that
 
140
contain parameters and/or markup.</p>
 
141
<p>For example, consider the following template snippet:</p>
 
142
<div class="highlight"><pre><span class="nt">&lt;p&gt;</span>
 
143
  Please visit <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="cp">}</span><span class="s">"</span><span class="nt">&gt;</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span><span class="nt">&lt;/a&gt;</span> for help.
 
144
<span class="nt">&lt;/p&gt;</span>
 
145
</pre></div>
 
146
<p>Without further annotation, the translation filter would treat this sentence
 
147
as two separate messages (“Please visit” and “for help”), and the translator
 
148
would have no control over the position of the link in the sentence.</p>
 
149
<p>However, when you use the Genshi internationalization directives, you simply
 
150
add an <tt class="docutils literal"><span class="pre">i18n:msg</span></tt> attribute to the enclosing <tt class="docutils literal"><span class="pre">&lt;p&gt;</span></tt> element:</p>
 
151
<div class="highlight"><pre><span class="nt">&lt;p</span> <span class="na">i18n:msg=</span><span class="s">"name"</span><span class="nt">&gt;</span>
 
152
  Please visit <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="cp">}</span><span class="s">"</span><span class="nt">&gt;</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span><span class="nt">&lt;/a&gt;</span> for help.
 
153
<span class="nt">&lt;/p&gt;</span>
 
154
</pre></div>
 
155
<p>Genshi is then able to identify the text in the <tt class="docutils literal"><span class="pre">&lt;p&gt;</span></tt> element as a single
 
156
message for translation purposes. You'll see the following string in your
 
157
message catalog:</p>
 
158
<pre class="literal-block">
 
159
Please visit [1:%(name)s] for help.
 
160
</pre>
 
161
<p>The <cite>&lt;a&gt;</cite> element with its attribute has been replaced by a part in square
 
162
brackets, which does not include the tag name or the attributes of the element.</p>
 
163
<p>The value of the <tt class="docutils literal"><span class="pre">i18n:msg</span></tt> attribute is a comma-separated list of parameter
 
164
names, which serve as simplified aliases for the actual Python expressions the
 
165
message contains. The order of the paramer names in the list must correspond
 
166
to the order of the expressions in the text. In this example, there is only
 
167
one parameter: its alias for translation is “name”, while the corresponding
 
168
expression is <tt class="docutils literal"><span class="pre">${site.name}</span></tt>.</p>
 
169
<p>The translator now has complete control over the structure of the sentence. He
 
170
or she certainly does need to make sure that any bracketed parts are not
 
171
removed, and that the <tt class="docutils literal"><span class="pre">name</span></tt> parameter is preserved correctly. But those are
 
172
things that can be easily checked by validating the message catalogs. The
 
173
important thing is that the translator can change the sentence structure, and
 
174
has no way to break the application by forgetting to close a tag, for example.</p>
 
175
<p>So if the German translator of this snippet decided to translate it to:</p>
 
176
<pre class="literal-block">
 
177
Um Hilfe zu erhalten, besuchen Sie bitte [1:%(name)s]
 
178
</pre>
 
179
<p>The resulting output might be:</p>
 
180
<div class="highlight"><pre><span class="nt">&lt;p&gt;</span>
 
181
  Um Hilfe zu erhalten, besuchen Sie bitte
 
182
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"http://example.com/"</span><span class="nt">&gt;</span>Example<span class="nt">&lt;/a&gt;</span>
 
183
<span class="nt">&lt;/p&gt;</span>
 
184
</pre></div>
 
185
<p>Messages may contain multiple tags, and they may also be nested. For example:</p>
 
186
<div class="highlight"><pre><span class="nt">&lt;p</span> <span class="na">i18n:msg=</span><span class="s">"name"</span><span class="nt">&gt;</span>
 
187
  <span class="nt">&lt;i&gt;</span>Please<span class="nt">&lt;/i&gt;</span> visit <span class="nt">&lt;b&gt;</span>the site <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="cp">}</span><span class="s">"</span><span class="nt">&gt;</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span><span class="nt">&lt;/a&gt;&lt;/b&gt;</span>
 
188
  for help.
 
189
<span class="nt">&lt;/p&gt;</span>
 
190
</pre></div>
 
191
<p>This would result in the following message ID:</p>
 
192
<pre class="literal-block">
 
193
[1:Please] visit [2:the site [3:%(name)s]] for help.
 
194
</pre>
 
195
<p>Again, the translator has full control over the structure of the sentence. So
 
196
the German translation could actually look like this:</p>
 
197
<pre class="literal-block">
 
198
Um Hilfe zu erhalten besuchen Sie [1:bitte]
 
199
[3:%(name)s], [2:das ist eine Web-Site]
 
200
</pre>
 
201
<p>Which Genshi would recompose into the following outout:</p>
 
202
<div class="highlight"><pre><span class="nt">&lt;p&gt;</span>
 
203
  Um Hilfe zu erhalten besuchen Sie <span class="nt">&lt;i&gt;</span>bitte<span class="nt">&lt;/i&gt;</span>
 
204
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"http://example.com/"</span><span class="nt">&gt;</span>Example<span class="nt">&lt;/a&gt;</span>, <span class="nt">&lt;b&gt;</span>das ist eine Web-Site<span class="nt">&lt;/b&gt;</span>
 
205
<span class="nt">&lt;/p&gt;</span>
 
206
</pre></div>
 
207
<p>Note how the translation has changed the order and even the nesting of the
 
208
tags.</p>
 
209
<div class="warning">
 
210
<p class="first admonition-title">Warning</p>
 
211
<p class="last">Please note that <tt class="docutils literal"><span class="pre">i18n:msg</span></tt> directives do not support other
 
212
nested directives. Directives commonly change the structure of
 
213
the generated markup dynamically, which often would result in the
 
214
structure of the text changing, thus making translation as a
 
215
single message ineffective.</p>
 
216
</div>
 
217
</div>
 
218
<div class="section" id="i18n-choose-i18n-singular-i18n-plural">
 
219
<h3>2.1.2   <tt class="docutils literal"><span class="pre">i18n:choose</span></tt>, <tt class="docutils literal"><span class="pre">i18n:singular</span></tt>, <tt class="docutils literal"><span class="pre">i18n:plural</span></tt></h3>
 
220
<p>Translatable strings that vary based on some number of objects, such as “You
 
221
have 1 new message” or “You have 3 new messages”, present their own challenge,
 
222
in particular when you consider that different languages have different rules
 
223
for pluralization. For example, while English and most western languages have
 
224
two plural forms (one for <tt class="docutils literal"><span class="pre">n=1</span></tt> and an other for <tt class="docutils literal"><span class="pre">n&lt;&gt;1</span></tt>), Welsh has five
 
225
different plural forms, while Hungarian only has one.</p>
 
226
<p>The <tt class="docutils literal"><span class="pre">gettext</span></tt> framework has long supported this via the <tt class="docutils literal"><span class="pre">ngettext()</span></tt>
 
227
family of functions. You specify two default messages, one singular and one
 
228
plural, and the number of items. The translations however may contain any
 
229
number of plural forms for the message, depending on how many are commonly
 
230
used in the language. <tt class="docutils literal"><span class="pre">ngettext</span></tt> will choose the correct plural form of the
 
231
translated message based on the specified number of items.</p>
 
232
<p>Genshi provides a variant of the <tt class="docutils literal"><span class="pre">i18n:msg</span></tt> directive described above that
 
233
allows choosing the proper plural form based on the numeric value of a given
 
234
variable. The pluralization support is implemented in a set of three
 
235
directives that must be used together: <tt class="docutils literal"><span class="pre">i18n:choose</span></tt>, <tt class="docutils literal"><span class="pre">i18n:singular</span></tt>, and
 
236
<tt class="docutils literal"><span class="pre">i18n:plural</span></tt>.</p>
 
237
<p>The <tt class="docutils literal"><span class="pre">i18n:choose</span></tt> directive is used to set up the context of the message: it
 
238
simply wraps the singular and plural variants.</p>
 
239
<p>The value of this directive is split into two parts: the first is the
 
240
<em>numeral</em>, a Python expression that evaluates to a number to determine which
 
241
plural form should be chosen. The second part, separated by a semicolon, lists
 
242
the parameter names. This part is equivalent to the value of the <tt class="docutils literal"><span class="pre">i18n:msg</span></tt>
 
243
directive.</p>
 
244
<p>For example:</p>
 
245
<div class="highlight"><pre><span class="nt">&lt;p</span> <span class="na">i18n:choose=</span><span class="s">"len(messages); num"</span><span class="nt">&gt;</span>
 
246
  <span class="nt">&lt;i18n:singular&gt;</span>You have <span class="nt">&lt;b&gt;</span><span class="cp">${</span><span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span><span class="cp">}</span><span class="nt">&lt;/b&gt;</span> new message.<span class="nt">&lt;/i18n:singular&gt;</span>
 
247
  <span class="nt">&lt;i18n:plural&gt;</span>You have <span class="nt">&lt;b&gt;</span><span class="cp">${</span><span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span><span class="cp">}</span><span class="nt">&lt;/b&gt;</span> new messages.<span class="nt">&lt;/i18n:plural&gt;</span>
 
248
<span class="nt">&lt;/p&gt;</span>
 
249
</pre></div>
 
250
<p>All three directives can be used either as elements or attribute. So the above
 
251
example could also be written as follows:</p>
 
252
<div class="highlight"><pre><span class="nt">&lt;i18n:choose</span> <span class="na">numeral=</span><span class="s">"len(messages)"</span> <span class="na">params=</span><span class="s">"num"</span><span class="nt">&gt;</span>
 
253
  <span class="nt">&lt;p</span> <span class="na">i18n:singular=</span><span class="s">""</span><span class="nt">&gt;</span>You have <span class="nt">&lt;b&gt;</span><span class="cp">${</span><span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span><span class="cp">}</span><span class="nt">&lt;/b&gt;</span> new message.<span class="nt">&lt;/p&gt;</span>
 
254
  <span class="nt">&lt;p</span> <span class="na">i18n:plural=</span><span class="s">""</span><span class="nt">&gt;</span>You have <span class="nt">&lt;b&gt;</span><span class="cp">${</span><span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span><span class="cp">}</span><span class="nt">&lt;/b&gt;</span> new messages.<span class="nt">&lt;/p&gt;</span>
 
255
<span class="nt">&lt;/i18n:choose&gt;</span>
 
256
</pre></div>
 
257
<p>When used as an element, the two parts of the <tt class="docutils literal"><span class="pre">i18n:choose</span></tt> value are split
 
258
into two different attributes: <tt class="docutils literal"><span class="pre">numeral</span></tt> and <tt class="docutils literal"><span class="pre">params</span></tt>. The
 
259
<tt class="docutils literal"><span class="pre">i18n:singular</span></tt> and <tt class="docutils literal"><span class="pre">i18n:plural</span></tt> directives do not require or support any
 
260
value (or any extra attributes).</p>
 
261
</div>
 
262
</div>
 
263
<div class="section" id="comments-and-domains">
 
264
<h2>2.2   Comments and Domains</h2>
 
265
<div class="section" id="i18n-comment">
 
266
<h3>2.2.1   <tt class="docutils literal"><span class="pre">i18n:comment</span></tt></h3>
 
267
<p>The <tt class="docutils literal"><span class="pre">i18n:comment</span></tt> directive can be used to supply a comment for the
 
268
translator. For example, if a template snippet is not easily understood
 
269
outside of its context, you can add a translator comment to help the
 
270
translator understand in what context the message will be used:</p>
 
271
<div class="highlight"><pre><span class="nt">&lt;p</span> <span class="na">i18n:msg=</span><span class="s">"name"</span> <span class="na">i18n:comment=</span><span class="s">"Link to the relevant support site"</span><span class="nt">&gt;</span>
 
272
  Please visit <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="cp">}</span><span class="s">"</span><span class="nt">&gt;</span><span class="cp">${</span><span class="n">site</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span><span class="nt">&lt;/a&gt;</span> for help.
 
273
<span class="nt">&lt;/p&gt;</span>
 
274
</pre></div>
 
275
<p>This comment will be extracted together with the message itself, and will
 
276
commonly be placed along the message in the message catalog, so that it is
 
277
easily visible to the person doing the translation.</p>
 
278
<p>This directive has no impact on how the template is rendered, and is ignored
 
279
outside of the extraction process.</p>
 
280
</div>
 
281
<div class="section" id="i18n-domain">
 
282
<h3>2.2.2   <tt class="docutils literal"><span class="pre">i18n:domain</span></tt></h3>
 
283
<p>In larger projects, message catalogs are commonly split up into different
 
284
<em>domains</em>. For example, you might have a core application domain, and then
 
285
separate domains for extensions or libraries.</p>
 
286
<p>Genshi provides a directive called <tt class="docutils literal"><span class="pre">i18n:domain</span></tt> that lets you choose the
 
287
translation domain for a particular scope. For example:</p>
 
288
<div class="highlight"><pre><span class="nt">&lt;div</span> <span class="na">i18n:domain=</span><span class="s">"examples"</span><span class="nt">&gt;</span>
 
289
  <span class="nt">&lt;p&gt;</span>Hello, world!<span class="nt">&lt;/p&gt;</span>
 
290
<span class="nt">&lt;/div&gt;</span>
 
291
</pre></div>
 
292
</div>
 
293
</div>
 
294
</div>
 
295
<div class="section" id="extraction">
 
296
<h1>3   Extraction</h1>
86
297
<p>The <tt class="docutils literal"><span class="pre">Translator</span></tt> class provides a class method called <tt class="docutils literal"><span class="pre">extract</span></tt>, which is
87
298
a generator yielding all localizable strings found in a template or markup
88
299
stream. This includes both literal strings in text nodes and attribute values,
89
300
as well as strings in <tt class="docutils literal"><span class="pre">gettext()</span></tt> calls in embedded Python code. See the API
90
301
documentation for details on how to use this method directly.</p>
91
 
<p>This functionality is integrated into the message extraction framework provided
92
 
by the <a class="reference" href="http://babel.edgewall.org/">Babel</a> project. Babel provides a command-line interface as well as
93
 
commands that can be used from <tt class="docutils literal"><span class="pre">setup.py</span></tt> scripts using <a class="reference" href="http://peak.telecommunity.com/DevCenter/setuptools">Setuptools</a> or
94
 
<a class="reference" href="http://docs.python.org/dist/dist.html">Distutils</a>.</p>
 
302
<div class="section" id="babel-integration">
 
303
<h2>3.1   Babel Integration</h2>
 
304
<p>This functionality is integrated with the message extraction framework provided
 
305
by the <a class="reference external" href="http://babel.edgewall.org/">Babel</a> project. Babel provides a command-line interface as well as
 
306
commands that can be used from <tt class="docutils literal"><span class="pre">setup.py</span></tt> scripts using <a class="reference external" href="http://peak.telecommunity.com/DevCenter/setuptools">Setuptools</a> or
 
307
<a class="reference external" href="http://docs.python.org/dist/dist.html">Distutils</a>.</p>
95
308
<p>The first thing you need to do to make Babel extract messages from Genshi
96
309
templates is to let Babel know which files are Genshi templates. This is done
97
310
using a “mapping configuration”, which can be stored in a configuration file,
111
324
<p>Please consult the Babel documentation for details on configuration.</p>
112
325
<p>If all goes well, running the extraction with Babel should create a POT file
113
326
containing the strings from your Genshi templates and your Python source files.</p>
114
 
<div class="note">
115
 
<p class="first admonition-title">Note</p>
116
 
<p class="last">Genshi currently does not support “translator comments”, i.e. text in
117
 
template comments that would get added to the POT file. This support
118
 
may or may not be added in future versions.</p>
119
327
</div>
120
 
<div class="section">
121
 
<h2><a id="configuration-options" name="configuration-options">2.1   Configuration Options</a></h2>
 
328
<div class="section" id="configuration-options">
 
329
<h2>3.2   Configuration Options</h2>
122
330
<p>The Genshi extraction plugin for Babel supports the following options:</p>
123
 
<div class="section">
124
 
<h3><a id="template-class" name="template-class">2.1.1   <tt class="docutils literal"><span class="pre">template_class</span></tt></a></h3>
 
331
<div class="section" id="template-class">
 
332
<h3>3.2.1   <tt class="docutils literal"><span class="pre">template_class</span></tt></h3>
125
333
<p>The concrete <tt class="docutils literal"><span class="pre">Template</span></tt> class that the file should be loaded with. Specify
126
334
the package/module name and the class name, separated by a colon.</p>
127
335
<p>The default is to use <tt class="docutils literal"><span class="pre">genshi.template:MarkupTemplate</span></tt>, and you'll want to
128
 
set it to <tt class="docutils literal"><span class="pre">genshi.template:TextTemplate</span></tt> for <a class="reference" href="text-templates.html">text templates</a>.</p>
 
336
set it to <tt class="docutils literal"><span class="pre">genshi.template:TextTemplate</span></tt> for <a class="reference external" href="text-templates.html">text templates</a>.</p>
129
337
</div>
130
 
<div class="section">
131
 
<h3><a id="encoding" name="encoding">2.1.2   <tt class="docutils literal"><span class="pre">encoding</span></tt></a></h3>
 
338
<div class="section" id="encoding">
 
339
<h3>3.2.2   <tt class="docutils literal"><span class="pre">encoding</span></tt></h3>
132
340
<p>The encoding of the template file. This is only used for text templates. The
133
341
default is to assume “utf-8”.</p>
134
342
</div>
135
 
<div class="section">
136
 
<h3><a id="include-attrs" name="include-attrs">2.1.3   <tt class="docutils literal"><span class="pre">include_attrs</span></tt></a></h3>
 
343
<div class="section" id="include-attrs">
 
344
<h3>3.2.3   <tt class="docutils literal"><span class="pre">include_attrs</span></tt></h3>
137
345
<p>Comma-separated list of attribute names that should be considered to have
138
346
localizable values. Only used for markup templates.</p>
139
347
</div>
140
 
<div class="section">
141
 
<h3><a id="ignore-tags" name="ignore-tags">2.1.4   <tt class="docutils literal"><span class="pre">ignore_tags</span></tt></a></h3>
 
348
<div class="section" id="ignore-tags">
 
349
<h3>3.2.4   <tt class="docutils literal"><span class="pre">ignore_tags</span></tt></h3>
142
350
<p>Comma-separated list of tag names that should be ignored. Only used for markup
143
351
templates.</p>
144
352
</div>
145
 
<div class="section">
146
 
<h3><a id="extract-text" name="extract-text">2.1.5   <tt class="docutils literal"><span class="pre">extract_text</span></tt></a></h3>
 
353
<div class="section" id="extract-text">
 
354
<h3>3.2.5   <tt class="docutils literal"><span class="pre">extract_text</span></tt></h3>
147
355
<p>Whether text outside explicit <tt class="docutils literal"><span class="pre">gettext</span></tt> function calls should be extracted.
148
356
By default, any text nodes not inside ignored tags, and values of attribute in
149
357
the <tt class="docutils literal"><span class="pre">include_attrs</span></tt> list are extracted. If this option is disabled, only
150
358
strings in <tt class="docutils literal"><span class="pre">gettext</span></tt> function calls are extracted.</p>
151
359
<div class="note">
152
360
<p class="first admonition-title">Note</p>
153
 
<p class="last">If you disable this option, it's not necessary to add the translation
154
 
filter as described above. You only need to make sure that the
155
 
template has access to the <tt class="docutils literal"><span class="pre">gettext</span></tt> functions it uses.</p>
156
 
</div>
157
 
</div>
158
 
</div>
159
 
</div>
160
 
<div class="section">
161
 
<h1><a id="translation" name="translation">3   Translation</a></h1>
 
361
<p class="last">If you disable this option, and do not make use of the
 
362
internationalization directives, it's not necessary to add the
 
363
translation filter as described above. You only need to make sure
 
364
that the template has access to the <tt class="docutils literal"><span class="pre">gettext</span></tt> functions it uses.</p>
 
365
</div>
 
366
</div>
 
367
</div>
 
368
</div>
 
369
<div class="section" id="translation">
 
370
<h1>4   Translation</h1>
162
371
<p>If you have prepared MO files for use with Genshi using the appropriate tools,
163
 
you can access the message catalogs with the <a class="reference" href="http://docs.python.org/lib/module-gettext.html">gettext Python module</a>. You'll
 
372
you can access the message catalogs with the <a class="reference external" href="http://docs.python.org/lib/module-gettext.html">gettext Python module</a>. You'll
164
373
probably want to create a <tt class="docutils literal"><span class="pre">gettext.GNUTranslations</span></tt> instance, and make the
165
374
translation functions it provides available to your templates by putting them
166
375
in the template context.</p>
168
377
(applying it as a stream filter will likely not have the desired effect).
169
378
Furthermore it needs to be the first filter in the list, including the internal
170
379
filters that Genshi adds itself:</p>
171
 
<div class="highlight"><pre><span class="k">from</span> <span class="nn">genshi.filters</span> <span class="k">import</span> <span class="n">Translator</span>
172
 
<span class="k">from</span> <span class="nn">genshi.template</span> <span class="k">import</span> <span class="n">MarkupTemplate</span>
 
380
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">genshi.filters</span> <span class="kn">import</span> <span class="n">Translator</span>
 
381
<span class="kn">from</span> <span class="nn">genshi.template</span> <span class="kn">import</span> <span class="n">MarkupTemplate</span>
173
382
 
174
383
<span class="n">template</span> <span class="o">=</span> <span class="n">MarkupTemplate</span><span class="p">(</span><span class="s">"..."</span><span class="p">)</span>
175
384
<span class="n">template</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="n">Translator</span><span class="p">(</span><span class="n">translations</span><span class="o">.</span><span class="n">ugettext</span><span class="p">))</span>
176
385
</pre></div>
177
 
<p>If you're using <cite>TemplateLoader</cite>, you should specify a callback function in
178
 
which you add the filter:</p>
179
 
<div class="highlight"><pre><span class="k">from</span> <span class="nn">genshi.filters</span> <span class="k">import</span> <span class="n">Translator</span>
180
 
<span class="k">from</span> <span class="nn">genshi.template</span> <span class="k">import</span> <span class="n">TemplateLoader</span>
181
 
 
182
 
<span class="k">def</span> <span class="nf">template_loaded</span><span class="p">(</span><span class="n">template</span><span class="p">):</span>
183
 
    <span class="n">template</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="n">Translator</span><span class="p">(</span><span class="n">translations</span><span class="o">.</span><span class="n">ugettext</span><span class="p">))</span>
184
 
 
185
 
<span class="n">loader</span> <span class="o">=</span> <span class="n">TemplateLoader</span><span class="p">(</span><span class="s">'templates'</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="n">template_loaded</span><span class="p">)</span>
186
 
<span class="n">template</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s">"..."</span><span class="p">)</span>
 
386
<p>The <tt class="docutils literal"><span class="pre">Translator</span></tt> class also provides the convenience method <tt class="docutils literal"><span class="pre">setup()</span></tt>,
 
387
which will both add the filter and register the i18n directives:</p>
 
388
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">genshi.filters</span> <span class="kn">import</span> <span class="n">Translator</span>
 
389
<span class="kn">from</span> <span class="nn">genshi.template</span> <span class="kn">import</span> <span class="n">MarkupTemplate</span>
 
390
 
 
391
<span class="n">template</span> <span class="o">=</span> <span class="n">MarkupTemplate</span><span class="p">(</span><span class="s">"..."</span><span class="p">)</span>
 
392
<span class="n">translator</span> <span class="o">=</span> <span class="n">Translator</span><span class="p">(</span><span class="n">translations</span><span class="o">.</span><span class="n">ugettext</span><span class="p">)</span>
 
393
<span class="n">translator</span><span class="o">.</span><span class="n">setup</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
187
394
</pre></div>
188
 
<p>This approach ensures that the filter is not added everytime the template is
189
 
loaded, and thus being applied multiple times.</p>
190
 
</div>
191
 
<div class="section">
192
 
<h1><a id="related-considerations" name="related-considerations">4   Related Considerations</a></h1>
 
395
<div class="warning">
 
396
<p class="first admonition-title">Warning</p>
 
397
<p class="last">If you're using <tt class="docutils literal"><span class="pre">TemplateLoader</span></tt>, you should specify a
 
398
<a class="reference external" href="loader.html#callback-interface">callback function</a> in which you add the filter. That ensures
 
399
that the filter is not added everytime the template is rendered,
 
400
thereby being applied multiple times.</p>
 
401
</div>
 
402
</div>
 
403
<div class="section" id="related-considerations">
 
404
<h1>5   Related Considerations</h1>
193
405
<p>If you intend to produce an application that is fully prepared for an
194
406
international audience, there are a couple of other things to keep in mind:</p>
195
 
<div class="section">
196
 
<h2><a id="unicode" name="unicode">4.1   Unicode</a></h2>
 
407
<div class="section" id="unicode">
 
408
<h2>5.1   Unicode</h2>
197
409
<p>Use <tt class="docutils literal"><span class="pre">unicode</span></tt> internally, not encoded bytestrings. Only encode/decode where
198
410
data enters or exits the system. This means that your code works with characters
199
411
and not just with bytes, which is an important distinction for example when
200
412
calculating the length of a piece of text. When you need to decode/encode, it's
201
413
probably a good idea to use UTF-8.</p>
202
414
</div>
203
 
<div class="section">
204
 
<h2><a id="date-and-time" name="date-and-time">4.2   Date and Time</a></h2>
 
415
<div class="section" id="date-and-time">
 
416
<h2>5.2   Date and Time</h2>
205
417
<p>If your application uses datetime information that should be displayed to users
206
418
in different timezones, you should try to work with UTC (universal time)
207
419
internally. Do the conversion from and to "local time" when the data enters or
208
 
exits the system. Make use the Python <a class="reference" href="http://docs.python.org/lib/module-datetime.html">datetime</a> module and the third-party
209
 
<a class="reference" href="http://pytz.sourceforge.net/">pytz</a> package.</p>
 
420
exits the system. Make use the Python <a class="reference external" href="http://docs.python.org/lib/module-datetime.html">datetime</a> module and the third-party
 
421
<a class="reference external" href="http://pytz.sourceforge.net/">pytz</a> package.</p>
210
422
</div>
211
 
<div class="section">
212
 
<h2><a id="formatting-and-locale-data" name="formatting-and-locale-data">4.3   Formatting and Locale Data</a></h2>
213
 
<p>Make sure you check out the functionality provided by the <a class="reference" href="http://babel.edgewall.org/">Babel</a> project for
 
423
<div class="section" id="formatting-and-locale-data">
 
424
<h2>5.3   Formatting and Locale Data</h2>
 
425
<p>Make sure you check out the functionality provided by the <a class="reference external" href="http://babel.edgewall.org/">Babel</a> project for
214
426
things like number and date formatting, locale display strings, etc.</p>
215
427
</div>
216
428
</div>