22Developing Roundup
33==================
44
5- :Version: $Revision: 1.8 $
5+ :Version: $Revision: 1.9 $
66
77Note: the intended audience of this document is the developers of the core
88Roundup code. If you just wish to alter some behaviour of your Roundup
@@ -106,6 +106,246 @@ The administrators of the project reserve the right to boot developers who
106106consistently check in code which is either broken or takes the codebase in
107107directions that have not been agreed to.
108108
109+ Internationalization Notes
110+ --------------------------
111+
112+ How stuff works:
113+
114+ 1. Strings that may require translation (messages in human language)
115+ are marked in the source code. This step is discussed in
116+ `Marking Strings for Translation`_ section.
117+
118+ 2. These strings are all extracted into Message Template File
119+ ``locale/roundup.pot`` (_`POT` file). See `Extracting Translatable
120+ Messages`_ below.
121+
122+ 3. Language teams use POT file to make Message Files for national
123+ languages (_`PO` files). All PO files for Roundup are kept in
124+ the ``locale`` directory. Names of these files are target
125+ locale names, usually just 2-letter language codes. `Translating
126+ Messages`_ section of this chapter gives useful hints for
127+ message translators.
128+
129+ 4. Translated Message Files are compiled into binary form (_`MO` files)
130+ and stored in ``locale`` directory (but not kept in the `Roundup
131+ CVS`_ repository, as they may be easily made from PO files).
132+ See `Compiling Message Catalogs`_ section.
133+
134+ 5. Roundup installer creates runtime locale structure on the file
135+ system, putting MO files in their appropriate places.
136+
137+ 6. Runtime internationalization (_`I18N`) services use these MO files
138+ to translate program messages into language selected by current
139+ Roundup user. Roundup command line interface uses locale name
140+ set in OS environment variable ``LANGUAGE``, ``LC_ALL``,
141+ ``LC_MESSAGES``, or ``LANG`` (in that order). Roundup Web User
142+ Interface uses language selected by currently authenticated user.
143+
144+ Additional details may be found in `GNU gettext`_ and Python `gettext
145+ module`_ documentation.
146+
147+ `Roundup source distribution`_ includes POT and PO files for message
148+ translators, and also pre-built MO files to facilitate installations
149+ from source. Roundup binary distribution includes MO files only.
150+
151+ .. _GNU gettext:
152+
153+ GNU gettext package
154+ ^^^^^^^^^^^^^^^^^^^
155+
156+ This chapter is full of references to GNU `gettext package`_.
157+ GNU gettext is a "must have" for nearly all steps of internationalizing
158+ any program, and it's manual is definetely a recommended reading
159+ for people involved in `I18N`_.
160+
161+ There are GNU gettext ports to all major OS platforms.
162+ Windows binaries are available from `GNU mirror sites`_.
163+
164+ Roundup does not use GNU gettext at runtime, but it's tools
165+ are used for `extracting translatable messages`_, `compiling
166+ message catalogs`_ and, optionally, for `translating messages`_.
167+
168+ Note that ``gettext`` package in some OS distributions means just
169+ runtime tools and libraries. In such cases gettext development tools
170+ are usually distributed in separate package named ``gettext-devel``.
171+
172+ Marking Strings for Translation
173+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
174+
175+ Strings that need translation must be marked in the source code.
176+ Following subsections explain how this is done in different cases.
177+
178+ If translatable string is used as a format string, it is recommended
179+ to always use *named* format specifiers::
180+
181+ _('Index of %(classname)s') % locals()
182+
183+ This helps translators to better understand the context of the
184+ message and, in Python, remove format specifier altogether (which
185+ is sometimes useful, especially in singular cases of `Plural Forms`_).
186+
187+ When there is more than one format specifier in the translatable
188+ format string, named format specifiers *must* be used almost always,
189+ because translation may require different order of items.
190+
191+ It is better to *not* mark for translation strings that are not
192+ locale-dependent, as this makes it more difficult to keep track
193+ of translation completeness. For example, string ``</ol></body></html>``
194+ (in ``index()`` method of the request handler in ``roundup_server``
195+ script) has no human readable parts at all, and needs no translations.
196+ Such strings are left untranslated in PO files, and are reported
197+ as such by PO status checkers (e.g. ``msgfmt --statistics``).
198+
199+ Command Line Interfaces
200+ ~~~~~~~~~~~~~~~~~~~~~~~
201+
202+ Scripts and routines run from the command line use "static" language
203+ defined by environment variables recognized by ``gettext`` module
204+ from Python library (``LANGUAGE``, ``LC_ALL``, ``LC_MESSAGES``, and
205+ ``LANG``). Primarilly, these are ``roundup-admin`` script and
206+ ``admin.py`` module, but also help texts and startup error messages
207+ in other scripts and their supporting modules.
208+
209+ For these interfaces, Python ``gettext`` engine must be initialized
210+ to use Roundup message catalogs. This is normally done by including
211+ the following line in the module imports::
212+
213+ from i18n import _, ngettext
214+
215+ Simple translations are automatically marked by calls to builtin
216+ message translation function ``_()``::
217+
218+ print _("This message is translated")
219+
220+ Translations for messages whose grammatical depends on a number
221+ must be done by ``ngettext()`` function::
222+
223+ print ngettext("Nuked %i file", "Nuked %i files", number_of_files_nuked)
224+
225+ User Interfaces
226+ ~~~~~~~~~~~~~~~
227+
228+ *(not yet)*
229+
230+ This includes Mail Gateway and Web User Interfaces, where translation
231+ depends on the language of current Roundup User. These translations
232+ will be done by the tracker configuration object. Translatable strings
233+ will be automatically marked by calls to the ``_()`` and ``ngettext()``
234+ methods of that object::
235+
236+ self.config._("This message is translated")
237+ self.config.ngettext("Nuked %i file", "Nuked %i files",
238+ number_of_files_nuked)
239+
240+ Deferred Translations
241+ ~~~~~~~~~~~~~~~~~~~~~
242+
243+ Sometimes translatable strings appear in the source code in untranslated
244+ form [#note_admin.py]_ and must be translated elsewhere.
245+ Example::
246+
247+ for meal in ("spam", "egg", "beacon"):
248+ print _(meal)
249+
250+ In such cases, strings must be marked for translation without actual
251+ call to the translating function. To mark these strings, we use Python
252+ feature of automatic concatenation of adjacent strings and different
253+ types of string quotes::
254+
255+ strings_to_translate = (
256+ ''"This string will be translated",
257+ ""'me too',
258+ ''r"\raw string",
259+ ''"""
260+ multiline string"""
261+ )
262+
263+ .. [#note_admin.py] In current Roundup sources, this feature is
264+ extensively used in the ``admin`` module using method docstrings
265+ as help messages.
266+
267+ Extracting Translatable Messages
268+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
269+
270+ The most common tool for message extraction is ``xgettext`` utility
271+ from `GNU gettext package`_. Unfortunately, this utility has no means
272+ of `Deferred Translations`_ in Python sources. There is ``xpot`` tool
273+ from Francois Pinard free `PO utilities`_ that allows to mark strings
274+ for deferred translations, but it does not handle `plural forms`_.
275+
276+ Roundup overcomes these limitations by using both of these utilities.
277+ This means that you need both `GNU gettext`_ tools and `PO utilities`_
278+ to build the Message Template File yourself.
279+
280+ Latest Message Template File is kept in `Roundup CVS`_ and distributed
281+ with `Roundup Source`_. If you wish to rebuild the template yourself,
282+ make sure that you have both ``xpot`` and ``xgettext`` installed and
283+ just run ``gmake`` (or ``make``, if you are on a `GNU`_ system like
284+ `linux`_ or `cygwin`_) in the ``locale`` directory.
285+
286+ Translating Messages
287+ ^^^^^^^^^^^^^^^^^^^^
288+
289+ Gettext Message File (`PO`_ file) is a plain text file, that can be created
290+ by simple copying ``roundup.pot`` to new .po file, like this::
291+
292+ $ cp roundup.pot ru.po
293+
294+ The name of PO file is target locale name, usually just 2-letter language
295+ code (``ru`` for Russian in the above example). Alternatively, PO file
296+ may be initialized by ``msginit`` utility from `GNU gettext`_ tools::
297+
298+ $ msginit -i roundup.pot
299+
300+ ``msginit`` will check your current locale, and initialize the header
301+ entry, setting language name, rules for `plural forms`_ and, if available,
302+ translator's name and email address. The name for PO file is also chosen
303+ based on current locale.
304+
305+ Next, you will need to edit this file, filling all ``msgstr`` lines with
306+ translations of the above ``msgid`` entries. PO file is a plain text
307+ file that can be edited with any text editor. However, there are several
308+ tools that may help you with this process:
309+
310+ - ``po-mode`` for `emacs`_. One of `GNU gettext`_ tools. Very handy,
311+ definitely recommended if you are comfortable with emacs. Cannot
312+ handle `plural forms`_ per se, but allows to edit them in simple
313+ text mode.
314+
315+ - `po filetype plugin`_ for `vim`_. Does not do as much as ``po-mode``,
316+ but helps in finding untranslated and fuzzy strings, and checking
317+ code references. Please contact `alexander smishlajev`_ if you
318+ prefer this, as i have patched this plugin a bit. I have also
319+ informed the original plugin author about these changes, but got
320+ no reply so far.
321+
322+ - `poEdit`_ by Vaclav Slavik. Nice cross-platform GUI editor.
323+ Unfortunately, it does not handle `plural forms`_. Even worse,
324+ it deletes all messages with plural forms when the file is saved.
325+ Still, it may be useful to initially translate most of the messages
326+ and add plural form messages later.
327+
328+ - `KBabel`_. Being part of `KDE`_, it works in X windows only.
329+ At the first glance looks pretty hairy, with all bells and whistles.
330+ Haven't had much experience with it, though.
331+
332+ Compiling Message Catalogs
333+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
334+
335+ Message catalogs (`PO`_ files) must be compiled into binary form
336+ (`MO`_ files) before they can be used in the application. This
337+ compilation is handled by ``msgfmt`` utility from `GNU gettext`_
338+ tools. ``GNUmakefile`` in the ``locale`` directory automatically
339+ compiles all existing message catalogs after updating them from
340+ Roundup source files. If you wish to rebuild an individual `MO`_
341+ file without making everything else, you may, for example::
342+
343+ $ msgfmt --statistics -o ru.mo ru.po
344+
345+ This way, message translators can check their `PO`_ files without
346+ extracting strings from source. (Note: String extraction requires
347+ additional utility that is not part of `GNU gettext`_. See `Extracting
348+ Translatable Messages`_.)
109349
110350-----------------
111351
@@ -115,3 +355,30 @@ Back to `Table of Contents`_
115355.. _`Customising Roundup`: customizing.html
116356.. _`Roundup's Design Document`: spec.html
117357.. _`implementation notes`: implementation.html
358+
359+
360+ .. _External hyperlink targets:
361+
362+ .. _alexander smishlajev:
363+ .. _als: http://sourceforge.net/users/a1s/
364+ .. _cygwin: http://www.cygwin.com/
365+ .. _emacs: http://www.gnu.org/software/emacs/
366+ .. _gettext package: http://www.gnu.org/software/gettext/
367+ .. _gettext module: http://docs.python.org/lib/module-gettext.html
368+ .. _GNU: http://www.gnu.org/
369+ .. _GNU mirror sites: http://www.gnu.org/prep/ftp.html
370+ .. _KBabel: http://i18n.kde.org/tools/kbabel/
371+ .. _KDE: http://www.kde.org/
372+ .. _linux: http://www.linux.org/
373+ .. _Plural Forms:
374+ http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html
375+ .. _po filetype plugin:
376+ http://vim.sourceforge.net/scripts/script.php?script_id=695
377+ .. _PO utilities: http://po-utils.progiciels-bpi.ca/
378+ .. _poEdit: http://poedit.sourceforge.net/
379+ .. _Roundup CVS: http://sourceforge.net/cvs/?group_id=31577
380+ .. _Roundup Source:
381+ .. _Roundup source distribution:
382+ .. _Roundup binary distribution:
383+ http://sourceforge.net/project/showfiles.php?group_id=31577
384+ .. _vim: http://www.vim.org/
0 commit comments