comparison doc/i18n.txt @ 885:80f80f2eec6a

Started extending the i18n docs.
author cmlenz
date Fri, 16 Apr 2010 22:31:38 +0000
parents 5a1c0ee0f659
children 9bd255289d75
comparison
equal deleted inserted replaced
884:5a1c0ee0f659 885:80f80f2eec6a
3 ===================================== 3 =====================================
4 Internationalization and Localization 4 Internationalization and Localization
5 ===================================== 5 =====================================
6 6
7 Genshi provides basic supporting infrastructure for internationalizing 7 Genshi provides basic supporting infrastructure for internationalizing
8 and localizing templates. That includes functionality for extracting localizable 8 and localizing templates. That includes functionality for extracting
9 strings from templates, as well as a template filter that can apply translations 9 localizable strings from templates, as well as a template filter that can
10 to templates as they get rendered. 10 apply translations to templates as they get rendered.
11 11
12 This support is based on `gettext`_ message catalogs and the `gettext Python 12 This support is based on `gettext`_ message catalogs and the `gettext Python
13 module`_. The extraction process can be used from the API level, or through the 13 module`_. The extraction process can be used from the API level, or through
14 front-ends implemented by the `Babel`_ project, for which Genshi provides a 14 the front-ends implemented by the `Babel`_ project, for which Genshi provides
15 plugin. 15 a plugin.
16 16
17 .. _`gettext`: http://www.gnu.org/software/gettext/ 17 .. _`gettext`: http://www.gnu.org/software/gettext/
18 .. _`gettext python module`: http://docs.python.org/lib/module-gettext.html 18 .. _`gettext python module`: http://docs.python.org/lib/module-gettext.html
19 .. _`babel`: http://babel.edgewall.org/ 19 .. _`babel`: http://babel.edgewall.org/
20 20
26 26
27 Basics 27 Basics
28 ====== 28 ======
29 29
30 The simplest way to internationalize and translate templates would be to wrap 30 The simplest way to internationalize and translate templates would be to wrap
31 all localizable strings in a ``gettext()`` function call (which is often aliased 31 all localizable strings in a ``gettext()`` function call (which is often
32 to ``_()`` for brevity). In that case, no extra template filter is required. 32 aliased to ``_()`` for brevity). In that case, no extra template filter is
33 required.
33 34
34 .. code-block:: genshi 35 .. code-block:: genshi
35 36
36 <p>${_("Hello, world!")}</p> 37 <p>${_("Hello, world!")}</p>
37 38
38 However, this approach results in significant “character noise” in templates, 39 However, this approach results in significant “character noise” in templates,
39 making them harder to read and preview. 40 making them harder to read and preview.
40 41
41 The ``genshi.filters.Translator`` filter allows you to get rid of the 42 The ``genshi.filters.Translator`` filter allows you to get rid of the
42 explicit `gettext`_ function calls, so you can continue to just write: 43 explicit `gettext`_ function calls, so you can continue to just write:
43 44
46 <p>Hello, world!</p> 47 <p>Hello, world!</p>
47 48
48 This text will still be extracted and translated as if you had wrapped it in a 49 This text will still be extracted and translated as if you had wrapped it in a
49 ``_()`` call. 50 ``_()`` call.
50 51
51 .. note:: For parameterized or pluralizable messages, you need to continue using 52 .. note:: For parameterized or pluralizable messages, you need to use the
52 the appropriate ``gettext`` functions. 53 special `template directives`_ described below, or use the
53 54 corresponding ``gettext`` function in embedded Python expressions.
54 You can control which tags should be ignored by this process; for example, it 55
56 You can control which tags should be ignored by this process; for example, it
55 doesn't really make sense to translate the content of the HTML 57 doesn't really make sense to translate the content of the HTML
56 ``<script></script>`` element. Both ``<script>`` and ``<style>`` are excluded 58 ``<script></script>`` element. Both ``<script>`` and ``<style>`` are excluded
57 by default. 59 by default.
58 60
59 Attribute values can also be automatically translated. The default is to 61 Attribute values can also be automatically translated. The default is to
60 consider the attributes ``abbr``, ``alt``, ``label``, ``prompt``, ``standby``, 62 consider the attributes ``abbr``, ``alt``, ``label``, ``prompt``, ``standby``,
61 ``summary``, and ``title``, which is a list that makes sense for HTML documents. 63 ``summary``, and ``title``, which is a list that makes sense for HTML
62 Of course, you can tell the translator to use a different set of attribute 64 documents. Of course, you can tell the translator to use a different set of
63 names, or none at all. 65 attribute names, or none at all.
64 66
65 In addition, you can control automatic translation in your templates using the 67 ----------------
66 ``xml:lang`` attribute. If the value of that attribute is a literal string, the 68 Language Tagging
67 contents and attributes of the element will be ignored: 69 ----------------
70
71 You can control automatic translation in your templates using the ``xml:lang``
72 attribute. If the value of that attribute is a literal string, the contents and
73 attributes of the element will be ignored:
68 74
69 .. code-block:: genshi 75 .. code-block:: genshi
70 76
71 <p xml:lang="en">Hello, world!</p> 77 <p xml:lang="en">Hello, world!</p>
72 78
78 84
79 <html xml:lang="$locale"> 85 <html xml:lang="$locale">
80 ... 86 ...
81 </html> 87 </html>
82 88
89
90 .. _`template directives`:
91
92 Template Directives
93 ===================
94
95 Sometimes localizable strings in templates may contain dynamic parameters, or
96 they may depend on the numeric value of some variable to choose a proper
97 plural form. Sometimes the strings contain embedded markup, such as tags for
98 emphasis or hyperlinks, and you don't want to rely on the people doing the
99 translations to know the syntax and escaping rules of HTML and XML.
100
101 In those cases the simple text extraction and translation process described
102 above is not sufficient. You could just use ``gettext`` API functions in
103 embedded Python expressions for parameters and pluralization, but Genshi also
104 provides special template directives for internationalization that attempt to
105 provide a comprehensive solution for this problem space.
106
107 To enable these directives, you'll need to register them with the templates
108 they are used in. You can do this by adding them manually via the
109 ``Template.add_directives(namespace, factory)`` (where ``namespace`` would be
110 “http://genshi.edgewall.org/i18n” and ``factory`` would be an instance of the
111 ``Translator`` class). Or you can just call the ``Translator.setup(template)``
112 class method, which both registers the directives and adds the translation
113 filter.
114
115 .. note:: The internationalization directives are still somewhat experimental
116 and have some known issues. However, the attribute language they
117 implement should be stable and is not subject to change
118 substantially in future versions.
119
120
121 --------
122 Messages
123 --------
124
125 ``i18n:msg``
126 ------------
127
128 This is the basic directive for defining localizable text passages that
129 contain parameters and/or markup.
130
131 For example, consider the following template snippet:
132
133 .. code-block:: genshi
134
135 <p>
136 Please visit <a href="${site.url}">${site.name}</a> for help.
137 </p>
138
139 Without further annotation, the translation filter would treat this sentence
140 as two separate messages (“Please click” and “here”), and the translator would
141 have no control over the position of the link in the sentence.
142
143 However, when you use the Genshi internationalization directives, you simply
144 add an ``i18n:msg`` attribute to the enclosing ``<p>`` element:
145
146 .. code-block:: genshi
147
148 <p i18n:msg="name">
149 Please visit <a href="${site.url}">${site.name}</a> for help.
150 </p>
151
152 Genshi is then able to identify the text in the ``<p>`` element as a single
153 message for translation purposes. You'll see the following string in your
154 message catalog::
155
156 Please visit [1:%(name)s] for help.
157
158 The `<a>` element with its attribute has been replaced by a part in square
159 brackets, which does not include the tag name or the attributes of the element.
160
161 The value of the ``i18n:msg`` attribute is a comma-separated list of parameter
162 names, which serve as simplified aliases for the actual Python expressions the
163 message contains. The order of the paramer names in the list must correspond
164 to the order of the expressions in the text. In this example, there is only
165 one parameter: its alias for translation is “name”, while the corresponding
166 expression is ``${site.name}``.
167
168 The translator now has complete control over the structure of the sentence. He
169 or she certainly does need to make sure that any bracketed parts are not
170 removed, and that the ``name`` parameter is preserved correctly. But those are
171 things that can be easily checked by validating the message catalogs. The
172 important thing is that the translator can change the sentence structure, and
173 has no way to break the application by forgetting to close a tag, for example.
174
175 So if the German translator of this snippet decided to translate it to::
176
177 Um Hilfe zu erhalten, besuchen Sie bitte [1:%(name)s]
178
179 The resulting output might be:
180
181 .. code-block:: html
182
183 <p>
184 Um Hilfe zu erhalten, besuchen Sie bitte
185 <a href="http://example.com/">Example</a>
186 </p>
187
188 Please note that messages may contain multiple tags, and they may also be
189 nested. For example:
190
191 .. code-block:: genshi
192
193 <p i18n:msg="name">
194 <i>Please</i> visit <b>the site <a href="${site.url}">${site.name}</a></b>
195 for help.
196 </p>
197
198 This would result in the following message ID::
199
200 [1:Please] visit [2:the site [3:%(name)s]] for help.
201
202 Again, the translator has full control over the structure of the sentence. So
203 the German translation could actually look like this::
204
205 Um Hilfe zu erhalten besuchen Sie [1:bitte]
206 [3:%(name)s], [2:das ist eine Web-Site]
207
208 Which Genshi would recompose into the following outout:
209
210 .. code-block:: html
211
212 <p>
213 Um Hilfe zu erhalten besuchen Sie <i>bitte</i>
214 <a href="http://example.com/">Example</a>, <b>das ist eine Web-Site</b>
215 </p>
216
217 Note how the translation has changed the order and even the nesting of the
218 tags.
219
220 .. warning:: Please note that ``i18n:msg`` directives do not support other
221 nested directives. Directives commonly change the structure of
222 the generated markup dynamically, which often would result in the
223 structure of the text changing, thus making translation as a
224 single message ineffective.
225
226 ``i18n:comment``
227 ----------------
228
229 The ``i18n:comment`` directive can be used to supply a comment for the
230 translator. For example, if a template snippet is not easily understood
231 outside of its context, you can add a translator comment to help the
232 translator understand in what context the message will be used:
233
234 .. code-block:: genshi
235
236 <p i18n:msg="name" i18n:comment="Link to the relevant support site">
237 Please visit <a href="${site.url}">${site.name}</a> help.
238 </p>
239
240 This comment will be extracted together with the message itself, and will
241 commonly be placed along the message in the message catalog, so that it is
242 easily visible to the person doing the translation.
243
244 This directive has no impact on how the template is rendered, and is ignored
245 outside of the extraction process.
246
247
248 -------------
249 Pluralization
250 -------------
251
252 ``i18n:choose``, ``i18n:singular``, ``i18n:plural``
253 ---------------------------------------------------
254
255 TODO
256
257 -------------------
258 Translation Domains
259 -------------------
260
261 ``i18n:domain``
262 ---------------
263
264 TODO
83 265
84 Extraction 266 Extraction
85 ========== 267 ==========
86 268
87 The ``Translator`` class provides a class method called ``extract``, which is 269 The ``Translator`` class provides a class method called ``extract``, which is
88 a generator yielding all localizable strings found in a template or markup 270 a generator yielding all localizable strings found in a template or markup
89 stream. This includes both literal strings in text nodes and attribute values, 271 stream. This includes both literal strings in text nodes and attribute values,
90 as well as strings in ``gettext()`` calls in embedded Python code. See the API 272 as well as strings in ``gettext()`` calls in embedded Python code. See the API
91 documentation for details on how to use this method directly. 273 documentation for details on how to use this method directly.
92 274
93 This functionality is integrated into the message extraction framework provided 275 -----------------
276 Babel Integration
277 -----------------
278
279 This functionality is integrated with the message extraction framework provided
94 by the `Babel`_ project. Babel provides a command-line interface as well as 280 by the `Babel`_ project. Babel provides a command-line interface as well as
95 commands that can be used from ``setup.py`` scripts using `Setuptools`_ or 281 commands that can be used from ``setup.py`` scripts using `Setuptools`_ or
96 `Distutils`_. 282 `Distutils`_.
97 283
98 .. _`setuptools`: http://peak.telecommunity.com/DevCenter/setuptools 284 .. _`setuptools`: http://peak.telecommunity.com/DevCenter/setuptools
120 306
121 Please consult the Babel documentation for details on configuration. 307 Please consult the Babel documentation for details on configuration.
122 308
123 If all goes well, running the extraction with Babel should create a POT file 309 If all goes well, running the extraction with Babel should create a POT file
124 containing the strings from your Genshi templates and your Python source files. 310 containing the strings from your Genshi templates and your Python source files.
125
126 .. note:: Genshi currently does not support “translator comments”, i.e. text in
127 template comments that would get added to the POT file. This support
128 may or may not be added in future versions.
129 311
130 312
131 --------------------- 313 ---------------------
132 Configuration Options 314 Configuration Options
133 --------------------- 315 ---------------------
200 382
201 from genshi.filters import Translator 383 from genshi.filters import Translator
202 from genshi.template import TemplateLoader 384 from genshi.template import TemplateLoader
203 385
204 def template_loaded(template): 386 def template_loaded(template):
205 template.filters.insert(0, Translator(translations.ugettext)) 387 Translator(translations.ugettext).setup(template)
206 388
207 loader = TemplateLoader('templates', callback=template_loaded) 389 loader = TemplateLoader('templates', callback=template_loaded)
208 template = loader.load('test.html') 390 template = loader.load('test.html')
209 391
210 This approach ensures that the filter is not added everytime the template is 392 This approach ensures that the filter is not added everytime the template is
Copyright (C) 2012-2017 Edgewall Software