Changes between Version 22 and Version 23 of CookBook/PluginL10N
- Timestamp:
- Sep 25, 2012, 11:02:34 PM (12 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
CookBook/PluginL10N
v22 v23 7 7 If you want to learn about translation for a plugin, that as you know already provides one/several message catalog/s, the section '[#Dotranslatorswork Do translators work]' and following parts are for you. 8 8 9 Ultimately, all plugin maintainers and developers in general, who are facing requests and are willing to take care for growing demand of their plugin to speak same (foreign) language(s) as Trac >= 0.12 should just read on.9 Ultimately, all plugin maintainers and developers in general, who are facing requests and are willing to take care for growing demand of their plugin to speak same (foreign) language(s) as Trac >= 0.12 should, just read on. 10 10 11 11 == i18n, l10n, ... help! == 12 In short '''i18n''' stands for '''`i`'''`nternationalizatio`'''`n`''' (count 18 more chars between i and n) and is defined as software design for programs with translation support. '''`l`'''`ocalisatio`'''`n`''' that is abbreviated as '''l10n''' could be seen as a follow-up process providing data for one or more locales. It is taking care of feature differences between the original/default (that is English is most cases including Trac) and a given locale as well. Such features are i.e. sentence structure including punctuation and formatting of numbers, date/time strings, and currencies. Once you did some ground work at the source (i18n), most remaining is proper translation work (l10n)putting more or less effort in preserving the sense of the original while looking as native locale as possible.^[#a1 1]^12 In short '''i18n''' stands for '''`i`'''`nternationalizatio`'''`n`''' (count 18 chars between i and n) and is defined as software design for programs with translation support. '''`l`'''`ocalisatio`'''`n`''' that is abbreviated as '''l10n''' could be seen as a follow-up process providing data for one or more locales. It is taking care of feature differences between the original/default (that is English is most cases including Trac) and a given locale as well. Such features are i.e. sentence structure including punctuation and formatting of numbers, date/time strings, and currencies. Once you did some ground work at the source (i18n), what's remaining is proper translation work (l10n), putting more or less effort in preserving the sense of the original while looking as native locale as possible.^[#a1 1]^ 13 13 14 14 '''NLS''' (National Language Support or Native Language Support) is meant to be the sum of both. And there are more related terms that we could safely skip for now.^[#a1 1], [#a2 2]^ 15 15 16 16 == Background and concept of i18n/l10n support for Trac plugins == 17 It begun with adding Babel to Trac. Some plugin maintainers created their own translation module inside each plugin separately. Growing amount of code redundancy and possibility of error within imperfect copies and variants of a translation module all that was certainly not a desirable situation. And Trac core maintainers took responsibility with adding functions dedicated to i18n/l10n support for Trac plugins. 17 18 It begun with adding [Babel:] to Trac. Babel is a very powerful translation framework. For one part, it is a message extraction tool: it can extract messages from source code files (in our case, Python and Javascript) as well as from Genshi templates, and create catalog templates (`.pot` files). It can also create and update the message catalogs (`.po` files), and compile those catalogs (`.mo` files). For the other part, as a Python library used within Trac, it provides the implementation of the message retrieval functions (`gettext` and related). And there's even more to it than that, if you're interested please visit the Babel project (also here on edgewall.org). 19 20 Now back to the plugins... 21 22 Some plugin maintainers created their own translation module inside each plugin separately. Growing amount of code redundancy and possibility of error within imperfect copies and variants of a translation module all that was certainly not a desirable situation. And Trac core maintainers took responsibility with adding functions dedicated to i18n/l10n support for Trac plugins. 18 23 19 24 The evolution of this functions has been documented in [comment:11:ticket:7497 ticket 7497]. The final implementation as mentioned there in [comment:12:ticket:7497 comment 12] was introduced to Trac trunk in changeset r7705 and finally done with changeset r7714. 20 25 21 Now adding the needed i18n/l10n helper functions is done by importing a set of functions from `trac/util/translation.py` and providing proper configuration for an additional translation layer ('domain') inside the plugin code. On plugin initialization the dedicated translation domain is created as well and corresponding catalog files holding translated messages are loaded into it. Whenever a translatable text is encountered during runtime inside plugin's code, i18n/l10n helper functions will try to get the corresponding translation from the message catalog of plugin's domain and fall back silently to Trac's main message catalog, if needed.26 Now adding the needed i18n/l10n helper functions is done by importing a set of functions from `trac/util/translation.py` and providing the necessary extra information (''domain'') for storing and fetching the messages from the plugin code into plugin specific message catalogs. During plugin initialization, the dedicated translation domain is created as well and corresponding catalog files holding translated messages are loaded in memory. If everything is setup correctly, when a translatable text is encountered at runtime inside the plugin's code, the i18n/l10n helper functions will try to get the corresponding translation from a message catalog of the plugin's domain. 22 27 23 28 The message catalog selection is done according to the locale setting. Valid settings are a combination of language and country code, optionally extended further by the character encoding used, i.e. to read like ‘de_DE.UTF-8’. Trac uses UTF-8 encoding internally, so there is not much to tell about that. 'C' is a special locale code since it disables all translations and programs use English texts as required by POSIX standard.^[#a3 3]^ 24 29 25 {{{#!comment26 Both searches take the locale setting as a second request argument. Valid settings are a combination of language and country code, often extended further by the character encoding used, i.e. to read like ‘de_DE.UTF-8’. The encoding is of special relevance for languages that had an older encoding per default that was not sufficient for all common chars used by native speakers of that language. 'C' is a special locale code since it disables all translations and programs use English texts as required by POSIX standard. Character encoding is highly dependent on the underlying operation system then.^[#a3 3]^27 //28 I'm not sure to what the above refers. Which search? What locale argument?29 I don't think the character encoding plays any role here (we deal with unicode internally,30 catalogs themselves are always encoded in UTF-8) - cboos31 Thanks for the hint on non-relevance for Trac since this has that uniform encoding. So I hope the current text is better.32 This might be deleted than.33 }}}34 35 First matching translation will replace the default text what by gettext convention is the same as the msgid, that is used, if all attempts fail to find an exact matching translation.36 30 37 31 == Required workflow == 38 A walk-through... 32 33 You need to: 34 - specify in you plugin's `setup.py` file on which files the Babel commands will have to operate 35 - create a `setup.cfg` files for adding options to the Babel commands 36 - in your Python source code: 37 - define specializations of the translation functions for your specific domain (there's a helper function for doing that easily) 38 - in the "root" `Component` in your plugin (one you're sure is always enabled) and initialize the translation domain in its `__init__` method 39 - use your translation functions appropriately 40 - in your Genshi templates: 41 - be sure to have the necessary namespace declaration and domain directive in place 42 - use the i18n: directive as appropriate 43 - in your Javascript code: 44 - be sure to load your catalog and define your domain specific translation functions 45 - use the translation functions as appropriate 46 47 Now, a detailed walk-through... 39 48 40 49 === Prepare plugin code === 41 50 ==== Import i18n/l10n helper programs ==== 42 Pick a reasonably unique name for the domain, e.g. ** 'foo' ** 51 Pick a reasonably unique name for the domain, e.g. ** 'foo' ** (if your plugin is named 'foo', that is). 43 52 44 53 This will be the basename for the various translation catalog files 45 (e.g. ` <path>/locale/fr/LC_MESSAGES/foo.po` for the French catalog).46 47 At run-time, the translation functions (typically `_(...)`) have to know in which catalog the translation will be found. Specifying the 'foo' domain in every such call would be tedious, that's why there's a facility for creating partially instantiated domain-aware translation functions ,`domain_functions`.54 (e.g. `foo/locale/fr/LC_MESSAGES/foo.po` for the French catalog). 55 56 At run-time, the translation functions (typically `_(...)`) have to know in which catalog the translation will be found. Specifying the 'foo' domain in every such call would be tedious, that's why there's a facility for creating partially instantiated domain-aware translation functions: `domain_functions`. 48 57 49 58 This helper function should be called at module load time, like this: … … 60 69 - `'tgettext'`, `'tag_'`: same as `'_'` but for Markup 61 70 - `'tngettext'`, `'tagn_'`: same as `'ngettext'` but for Markup 62 - `'gettext'`: translate only, don't extract63 - `'N_'`: extract only, don't translate71 - `'gettext'`: translate //only//, don't extract 72 - `'N_'`: extract //only//, don't translate 64 73 - `'add_domain'`: register the catalog file for the bound domain 74 75 Note: `N_` and `gettext()` are usually used in tandem. For example, when you have a global dict containing strings that need to extracted, you want to mark those strings for extraction but you don't want to put their //translation// in the dict: use `N_("the string")`; when you later use that dict and want to retrieve the translation for the string corresponding to some key, you don't want to mark anything here: use `gettext(mydict.get(key))`. 65 76 66 77 To inform Trac about where the plugin's message catalogs can be found, you'll have to call the `add_domain` function obtained via `domain_functions` as shown above. One place to do this is in the `__init__` function of your plugin's main component, like this: … … 72 83 add_domain(self.env.path, locale_dir) 73 84 }}} 74 assuming that folder `locale` will reside in the same folder as the file containing the code above, referred to as `<path>` (as observableinside the Python egg after packaging).75 76 The i18n/l10n helper programs are available inside the plugin now, but if the plugin code contains several python script files and you encounter text for translation in one of them too, you need to import the functions from the main script, say its name is `api.py`, there:85 assuming that folder `locale` will reside in the same folder as the file containing the code above, referred to as `<path>` below (as can be observed inside the Python egg after packaging). 86 87 The i18n/l10n helper functions are available inside the plugin now, but if the plugin code contains several python script files and you encounter text for translation in one of them too, you need to import the functions from the main script, say its name is `api.py`, there: 77 88 {{{#!python 78 89 from api import _, tag_, N_ 79 90 }}} 80 91 81 ==== Preset configuration for i18n/l10n helper programs ====92 ==== Preset configuration for Babel commands ==== 82 93 Add some lines to `setup.cfg` or, if it doesn't exist by now, create it with the following content: 83 94 {{{#!ini … … 110 121 Replace `<path>` as appropriate (i.e. the relative path to the folder containing the `locale` directory, for example `mytracplugin`). 111 122 112 This will tell the i18n/l10n helper programswhere to look for and store message catalog files.123 This will tell Babel where to look for and store message catalog files. 113 124 114 125 … … 185 196 }}} 186 197 198 199 187 200 ==== Text extraction from Javascript code ==== #Javascript 188 201