Code

Accept single-character subject lines
[roundup.git] / doc / developers.txt
1 ==================
2 Developing Roundup
3 ==================
5 .. note::
6    The intended audience of this document is the developers of the core
7    Roundup code. If you just wish to alter some behaviour of your Roundup
8    installation, see `customising roundup`_.
10 .. contents::
12 Getting Started
13 ---------------
15 Anyone wishing to help in the development of Roundup must read `Roundup's
16 Design Document`_ and the `implementation notes`_.
18 All development is coordinated through two resources:
20 - roundup-dev mailing list at
21   http://lists.sourceforge.net/mailman/listinfo/roundup-devel
22 - The issue tracker running at
23   http://issues.roundup-tracker.org/
25 Website, wiki
26 -------------
28 1. ssh -t <username>,roundup@shell.sourceforge.net create
29 2. cd /home/groups/r/ro/roundup
30 3. follow instructions in README.txt
33 Issue Tracker
34 -------------
36 The tracker resides on psf.upfronthosting.co.za. The roundup installation
37 belongs to the user roundup. In ~roundup, all trackers are stored and
38 the roundup code itself. roundup is started through /etc/init.d/roundup;
39 other parts of the installation are started through
40 /etc/init.d/{postgresql-8-1,spambayes,postfix}.
42 The machine is operated by Upfronthosting in South Africa. The meta
43 tracker is http://psf.upfronthosting.co.za/roundup/meta/
44 In this tracker, Upfronthosting people are the users izak and roche.
46 The Roundup tracker http://issues.roundup-tracker.org/ is in
47 ~roundup/trackers/roundup
49 The configuration is in the "web/trunk/issues" section of Roundup's
50 Subversion repository and copied manually to the live tracker.
52 A checkout of the roundup sources is in ~roundup/src/roundup-src.
55 Small Changes
56 -------------
58 Most small changes can be submitted through the issue tracker, with
59 patches attached that give context diffs of the affected source.
62 SVN Access
63 ----------
65 See http://www.roundup-tracker.org/code.html.
66 For all other questions ask on the development mailinglist.
69 Project Rules
70 -------------
72 Mostly the project follows Guido's Style (though naming tends to be a little
73 relaxed sometimes). In short:
75 - 80 column width code
76 - 4-space indentations
77 - All modules must have an Id line near the top
79 Other project rules:
81 - New functionality must be documented, even briefly (so at least we know
82   where there's missing documentation) and changes to tracker configuration
83   must be logged in the upgrading document.
84 - subscribe to roundup-checkins to receive checkin notifications from the
85   other developers with write access to the source-code repository.
86 - discuss any changes with the other developers on roundup-dev. If nothing
87   else, this makes sure there's no rude shocks
88 - write unit tests for changes you make (where possible), and ensure that
89   all unit tests run before committing changes
90 - run pychecker over changed code
92 The administrators of the project reserve the right to boot developers who
93 consistently check in code which is either broken or takes the codebase in
94 directions that have not been agreed to.
97 Debugging Aids
98 --------------
100 Try turning on logging of DEBUG level messages. This may be done a number
101 of ways, depending on what it is you're testing:
103 1. If you're testing the database unit tests, then set the environment
104    variable ``LOGGING_LEVEL=DEBUG``. This may be done like so:
106     LOGGING_LEVEL=DEBUG python run_tests.py
108    This variable replaces the older HYPERDBDEBUG environment var.
110 2. If you're testing a particular tracker, then set the logging level in
111    your tracker's ``config.ini``.
114 Internationalization Notes
115 --------------------------
117 How stuff works:
119 1. Strings that may require translation (messages in human language)
120    are marked in the source code.  This step is discussed in
121    `Marking Strings for Translation`_ section.
123 2. These strings are all extracted into Message Template File
124    ``locale/roundup.pot`` (_`POT` file).  See `Extracting Translatable
125    Messages`_ below.
127 3. Language teams use POT file to make Message Files for national
128    languages (_`PO` files).  All PO files for Roundup are kept in
129    the ``locale`` directory.  Names of these files are target
130    locale names, usually just 2-letter language codes.  `Translating
131    Messages`_ section of this chapter gives useful hints for
132    message translators.
134 4. Translated Message Files are compiled into binary form (_`MO` files)
135    and stored in ``locale`` directory (but not kept in the source code
136    repository, as they may be easily made from PO files).
137    See `Compiling Message Catalogs`_ section.
139 5. Roundup installer creates runtime locale structure on the file
140    system, putting MO files in their appropriate places.
142 6. Runtime internationalization (_`I18N`) services use these MO files
143    to translate program messages into language selected by current
144    Roundup user.  Roundup command line interface uses locale name
145    set in OS environment variable ``LANGUAGE``, ``LC_ALL``,
146    ``LC_MESSAGES``, or ``LANG`` (in that order).  Roundup Web User
147    Interface uses language selected by currently authenticated user.
149 Additional details may be found in `GNU gettext`_ and Python `gettext
150 module`_ documentation.
152 `Roundup source distribution`_ includes POT and PO files for message
153 translators, and also pre-built MO files to facilitate installations
154 from source.  Roundup binary distribution includes MO files only.
156 .. _GNU gettext:
158 GNU gettext package
159 ^^^^^^^^^^^^^^^^^^^
161 This chapter is full of references to GNU `gettext package`_.
162 GNU gettext is a "must have" for nearly all steps of internationalizing
163 any program, and it's manual is definetely a recommended reading
164 for people involved in `I18N`_.
166 There are GNU gettext ports to all major OS platforms.
167 Windows binaries are available from `GNU mirror sites`_.
169 Roundup does not use GNU gettext at runtime, but it's tools
170 are used for `extracting translatable messages`_, `compiling
171 message catalogs`_ and, optionally, for `translating messages`_.
173 Note that ``gettext`` package in some OS distributions means just
174 runtime tools and libraries.  In such cases gettext development tools
175 are usually distributed in separate package named ``gettext-devel``.
177 Marking Strings for Translation
178 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
180 Strings that need translation must be marked in the source code.
181 Following subsections explain how this is done in different cases.
183 If translatable string is used as a format string, it is recommended
184 to always use *named* format specifiers::
186   _('Index of %(classname)s') % locals()
188 This helps translators to better understand the context of the
189 message and, with Python formatting, remove format specifier altogether
190 (which is sometimes useful, especially in singular cases of `Plural Forms`_).
192 When there is more than one format specifier in the translatable
193 format string, named format specifiers **must** be used almost always,
194 because translation may require different order of items.
196 It is better to *not* mark for translation strings that are not
197 locale-dependent, as this makes it more difficult to keep track
198 of translation completeness.  For example, string ``</ol></body></html>``
199 (in ``index()`` method of the request handler in ``roundup_server``
200 script) has no human readable parts at all, and needs no translations.
201 Such strings are left untranslated in PO files, and are reported
202 as such by PO status checkers (e.g. ``msgfmt --statistics``).
204 Command Line Interfaces
205 ~~~~~~~~~~~~~~~~~~~~~~~
207 Scripts and routines run from the command line use "static" language
208 defined by environment variables recognized by ``gettext`` module
209 from Python library (``LANGUAGE``, ``LC_ALL``, ``LC_MESSAGES``, and
210 ``LANG``).  Primarilly, these are ``roundup-admin`` script and
211 ``admin.py`` module, but also help texts and startup error messages
212 in other scripts and their supporting modules.
214 For these interfaces, Python ``gettext`` engine must be initialized
215 to use Roundup message catalogs.  This is normally done by including
216 the following line in the module imports::
218   from i18n import _, ngettext
220 Simple translations are automatically marked by calls to builtin
221 message translation function ``_()``::
223   print _("This message is translated")
225 Translations for messages whose grammatical depends on a number
226 must be done by ``ngettext()`` function::
228   print ngettext("Nuked %i file", "Nuked %i files", number_of_files_nuked)
230 Deferred Translations
231 ~~~~~~~~~~~~~~~~~~~~~
233 Sometimes translatable strings appear in the source code in untranslated
234 form [#note_admin.py]_ and must be translated elsewhere.
235 Example::
237   for meal in ("spam", "egg", "beacon"):
238       print _(meal)
240 In such cases, strings must be marked for translation without actual
241 call to the translating function.  To mark these strings, we use Python
242 feature of automatic concatenation of adjacent strings and different
243 types of string quotes::
245   strings_to_translate = (
246       ''"This string will be translated",
247       ""'me too',
248       ''r"\raw string",
249       ''"""
250       multiline string"""
251   )
253 .. [#note_admin.py] In current Roundup sources, this feature is
254    extensively used in the ``admin`` module using method docstrings
255    as help messages.
257 Web User Interface
258 ~~~~~~~~~~~~~~~~~~
260 For Web User Interface, translation services are provided by Client
261 object.  Action classes have methods ``_()`` and ``gettext()``,
262 delegating translation to the Client instance.  In HTML templates,
263 translator object is available as context variable ``i18n``.
265 HTML templates have special markup for translatable strings.
266 The syntax for this markup is defined on `ZPTInternationalizationSupport`_
267 page.  Roundup translation service currently ignores values for
268 ``i18n:domain``, ``i18n:source`` and ``i18n:target``.
270 Template markup examples:
272 * simplest case::
274     <div i18n:translate="">
275      Say
276      no
277      more!
278     </div>
280   this will result in msgid ``"Say no more!"``, with all leading and
281   trailing whitespace stripped, and inner blanks replaced with single
282   space character.
284 * using variable slots::
286     <div i18n:translate="">
287      And now...<br/>
288      No.<span tal:replace="number" i18n:name="slideNo" /><br/>
289      THE LARCH
290     </div>
292   Msgid will be: ``"And now...<br /> No.${slideNo}<br /> THE LARCH"``.
293   Template rendering will use context variable ``number`` (you may use
294   any expression) to put instead of ``${slideNo}`` in translation.
296 * attribute translation::
298     <button name="btn_wink" value=" Wink " i18n:attributes="value" />
300   will translate the caption (and return value) for the "wink" button.
302 * explicit msgids.  Sometimes it may be useful to specify msgid
303   for the element translation explicitely, like this::
305     <span i18n:translate="know what i mean?">this text is ignored</span>
307   When rendered, element contents will be replaced by translation
308   of the string specified in ``i18n:translate`` attribute.
310 * ``i18n`` in `TALES`_.  You may translate strings in `TALES`_ python
311   expressions::
313     <span tal:replace="python: i18n.gettext('Oh, wicked.')" />
315 * plural forms.  There is no markup for plural forms in `TAL`_ i18n.
316   You must use python expression for that::
318     <span tal:replace="python: i18n.ngettext(
319       'Oh but it\'s only %i shilling.',
320       'Oh but it\'s only %i shillings.',
321       fine) % fine"
322     />
324 Extracting Translatable Messages
325 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
327 The most common tool for message extraction is ``xgettext`` utility
328 from `GNU gettext package`_.  Unfortunately, this utility has no means
329 of `Deferred Translations`_ in Python sources.  There is ``xpot`` tool
330 from Francois Pinard free `PO utilities`_ that allows to mark strings
331 for deferred translations, but it does not handle `plural forms`_.
333 Roundup overcomes these limitations by using both of these utilities.
334 This means that you need both `GNU gettext`_ tools and `PO utilities`_
335 to build the Message Template File yourself.
337 Latest Message Template File is kept in the source code repository 
338 and distributed with `Roundup Source`_.  
339 If you wish to rebuild the template yourself,
340 make sure that you have both ``xpot`` and ``xgettext`` installed and
341 just run ``gmake`` (or ``make``, if you are on a `GNU`_ system like
342 `linux`_ or `cygwin`_) in the ``locale`` directory.
344 For on-site i18n, Roundup provides command-line utility::
346   roundup-gettext <tracker_home>
348 extracting translatable messages from tracker's html templates.
349 This utility creates message template file ``messages.pot`` in
350 ``locale`` subdirectory of the tracker home directory.  Translated
351 messages may be put in *locale*.po files (where *locale* is selected
352 locale name) in the same directory, e.g.: ``locale/ru.po``.
353 These message catalogs are searched prior to system-wide translations
354 kept in the ``share`` directory.
356 Translating Messages
357 ^^^^^^^^^^^^^^^^^^^^
359 Gettext Message File (`PO`_ file) is a plain text file, that can be created
360 by simple copying ``roundup.pot`` to new .po file, like this::
362   $ cp roundup.pot ru.po
364 The name of PO file is target locale name, usually just 2-letter language
365 code (``ru`` for Russian in the above example).  Alternatively, PO file
366 may be initialized by ``msginit`` utility from `GNU gettext`_ tools::
368   $ msginit -i roundup.pot
370 ``msginit`` will check your current locale, and initialize the header
371 entry, setting language name, rules for `plural forms`_ and, if available,
372 translator's name and email address.  The name for PO file is also chosen
373 based on current locale.
375 Next, you will need to edit this file, filling all ``msgstr`` lines with
376 translations of the above ``msgid`` entries.  PO file is a plain text
377 file that can be edited with any text editor.  However, there are several
378 tools that may help you with this process:
380  - `poEdit`_ by Vaclav Slavik.  Very nice cross-platform GUI editor.
382  - `KBabel`_.  Being part of `KDE`_, it works in X windows only.
383     At the first glance looks pretty hairy, with all bells and whistles.
384     Haven't had much experience with it, though.
386  - ``po-mode`` for `emacs`_.  One of `GNU gettext`_ tools.  Very handy,
387    definitely recommended if you are comfortable with emacs.  Cannot
388    handle `plural forms`_ per se, but allows to edit them in simple
389    text mode.
391  - `po filetype plugin`_ for `vim`_.  Does not do as much as ``po-mode``,
392    but helps in finding untranslated and fuzzy strings, and checking
393    code references.  Please contact `alexander smishlajev`_ if you
394    prefer this, as i have patched this plugin a bit.  I have also
395    informed the original plugin author about these changes, but got
396    no reply so far.
398 Compiling Message Catalogs
399 ^^^^^^^^^^^^^^^^^^^^^^^^^^
401 Message catalogs (`PO`_ files) must be compiled into binary form
402 (`MO`_ files) before they can be used in the application.  This
403 compilation is handled by ``msgfmt`` utility from `GNU gettext`_
404 tools.  ``GNUmakefile`` in the ``locale`` directory automatically
405 compiles all existing message catalogs after updating them from
406 Roundup source files.  If you wish to rebuild an individual `MO`_
407 file without making everything else, you may, for example::
409   $ msgfmt --statistics -o ru.mo ru.po
411 This way, message translators can check their `PO`_ files without
412 extracting strings from source.  (Note: String extraction requires
413 additional utility that is not part of `GNU gettext`_.  See `Extracting
414 Translatable Messages`_.)
416 At run time, Roundup automatically compiles message catalogs whenever
417 `PO`_ file is changed.
419 .. _`Customising Roundup`: customizing.html
420 .. _`Roundup's Design Document`: spec.html
421 .. _`implementation notes`: implementation.html
424 .. _External hyperlink targets:
426 .. _alexander smishlajev:
427 .. _als: http://sourceforge.net/users/a1s/
428 .. _cygwin: http://www.cygwin.com/
429 .. _emacs: http://www.gnu.org/software/emacs/
430 .. _gettext package: http://www.gnu.org/software/gettext/
431 .. _gettext module: http://docs.python.org/lib/module-gettext.html
432 .. _GNU: http://www.gnu.org/
433 .. _GNU mirror sites: http://www.gnu.org/prep/ftp.html
434 .. _KBabel: http://i18n.kde.org/tools/kbabel/
435 .. _KDE: http://www.kde.org/
436 .. _linux: http://www.linux.org/
437 .. _Plural Forms:
438     http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html
439 .. _po filetype plugin:
440     http://vim.sourceforge.net/scripts/script.php?script_id=695
441 .. _PO utilities: http://po-utils.progiciels-bpi.ca/
442 .. _poEdit: http://poedit.sourceforge.net/
443 .. _Roundup Source:
444 .. _Roundup source distribution:
445 .. _Roundup binary distribution:
446     http://sourceforge.net/project/showfiles.php?group_id=31577
447 .. _TAL:
448 .. _Template Attribute Language:
449    http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4
450 .. _TALES:
451 .. _Template Attribute Language Expression Syntax:
452    http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TALES%20Specification%201.3
453 .. _vim: http://www.vim.org/
454 .. _ZPTInternationalizationSupport: http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport