Internationalisation - mf4dl1/jaksafe GitHub Wiki
This document is divided into three parts:
- :ref:`quick-reference` - use this if you just want to quickly remember how to mark a word or phrase for translation
- :ref:`qgis-plugin` - this is in-depth information on how the translation framework is set up for Qt based code components
- :ref:`library-translations` - this is in-depth information on how the translation framework is set up for the pure python library implementation.
The translation system works differently for different parts of the project:
- Strings that appear in the InaSAFE graphical user interface (gui module). These include buttons, help strings, menu items etc.
- Strings that appear in the Python code which constitutes the rest of InaSAFE including the impact functions.
- Strings that appear in data and keywords used by InaSAFE.
- Strings that appear in this documentation and the web site.
Flagging strings for translation is done differently for these four cases and are treated separately in the next sections. However, making and deploying the translations is unified and takes care of all aspects and is described in section "Make translations" below.
- Classes and anonymous functions that do not inherit from the class QObject should use the format :samp:`QCoreApplication.translate('InaSAFE', 'Translations loaded')`
- Classes that inherit from QObject should use the form :samp:`self.tr('foo')`
- String replacement arguments should be provided using the QString :samp:`arg` method. Example: :samp:`self.tr('Error: %1').arg(message)`
-
Import the gettext helper e.g:
from safe.common.utilities import ugettext as tr (Note that you must have the sequence "import ugettext" in the statement. It will not work as part of a multiple import such as import x, y, ugettext as tr)
-
All strings should be wrapped using the tr helper e.g:
tr('Are there enough shelters available for %i people?') % displaced -
The library will use at run-time the :samp:`LANG` environment variable which should be set to the iso code e.g. 'id' for 'Indonesia' of the Locale you wish to use. This is done automatically for you by the QGIS Plugin, but if you are using the InaSAFE library in another context, be sure to set it before using any library functions if you want them to return translated strings e.g.:
os.environ['LANG'] = 'id' # do stuff with InaSAFE lib
This applies e.g. to titles of layers or attribute names in data. The translation system works by scanning the Python code for strings marked as described above. However, it has know way of knowing about titles of layers or names that appear in datasets processed by InaSAFE. However, if such names are known a-priori they can be made visible to the translation system as follows:
-
Edit the file:
common/dynamic_translations.py
and add the name to the dictionary "names". E.g. :samp:`'college' = tr('college')`
-
Update the translation strings as described in the section below
-
Make impact functions refer to the dynamic translations e.g. as in this example:
from common.dynamic_translations import names as internationalised_values if building_type in internationalised_values: building_type = internationalised_values[building_type]
When new strings have been added as described above the procedure to translate them is (example is given for LANG=id):
- run :samp:`make update-translation-strings` to collect all strings marked for translation
- Using either an editor or the tool Qt Linguist provide translations in the
files
- safe/i18n/id/LC_MESSAGES/inasafe.po
- safe_qgis/i18n/inasafe_id.ts
- run :samp:`make compile-translation-strings` to make the translations available to InaSAFE
To add a new language, edit the :samp:`Makefile` file and append the new locale to the bottom of the file. For example, to add South African english as a new locale, change this section:
# LOCALES = space delimited list of iso codes to generate po files for # Please do not remove en here LOCALES = en id
By adding the local identified 'af'
LOCALES = en id af
Save and close the Makefile. Next you need to create the initial translation stringlist for that locale. After the inital creation of your .po files using the above commands, you can update them anytime the strings in the library have been changed by doing
make update-translation-strings
to generate the gettext .po files under :file:`safe\i18n/en_ZA/LC_MESSAGES` the and Qt Linguist .ts files under :file:`safe_qgis.i18n`.
Note
Don't forget to git add the new files to place them under version
control.
To convert the .po file to a binary .mo file (which is used at runtime for the actual translation), follow the :ref:`library-release-label` section above.
Things you need to do once per Client Computer:
- Create a Transifex account on http://www.transifex.org
- :command:`sudo pip install transifex-client`
- go to :file:`/tmp` and write :command:`tx init` to create your :file:`.transifexrc` file
- go back to your :file:`inasafe-doc` folder
Transifex calls files 'resources' and each resource you upload can be translated into any of the locales you have set up in transifex. In InaSAFE we have two resources (and the separate inasafe-doc project has many more). The resource in InaSAFE are:
- safe (gettext based .po file for the safe package)
- safe_qgis (Qt based .ts file for the safe_qgis package)
The methodology for creation of these resources can be reviewed in :file:`scripts/create-transifex-resources.sh`.
Note
You do not need to run this script as it is a once-off activity per project.
This script basically does this:
- makes sure each po source file is registered as a transifex resource
- adds a translation source for each locale (determined by subdirs of i18n dir) for each resource
- pushes the resources and their translation files to transifex
A typical session to pull update and then push strings to transifex looks like this
tx pull -a -f make update-translation-strings git add safe/i18n git add safe_qgis/i18n/ git commit -m "Translation file updates" -a tx push -t -s -l id
Which pushes the Indonesian updated translations files to transifex at the end ready for further input from translators.
You can also push individual files like this
tx push -s -l id -r inasafe-develop.safe_qgis
that will push the source (-s) for language (-l) id for the resource (-r) safe up to the transifex web server.
Note
In most cases you will want to do a source only push to avoid overwriting ongoing translation work on the transifex server.
Or like this (pushing translation too)
tx push -s -t -l id -r inasafe-develop.safe_qgis
that will push the source (-s) and translation file (-t) for language (-l) id for the resource (-r) safe up to the transifex web server.
You can pull individual translations from transifex to incorporate them into your local code tree.:
tx pull -l id -r inasafe-develop.safe_qgis
Notice that there is no (-s) option for pull - you can only get the translation.
The QGIS Plugin uses QtLinguist. This free, open source application can be downloaded and used to translate the Qt translation files. Alternatively the transifex online translation service can be used.
Note
We prefer to do translations in transifex as the process is easier to do collaboratively.
As developer, before a release you should do:
- Run :samp:`make update-translation-strings` to update the translation files.
- Distribute the .ts files under :samp:`gui/i18n` to the translators (i.e. by uploading them to transifex).
- Instruct them to open the .ts file for their locale with QtLinguist (by downloading from transifex), or to use the online tools transifex provides.
- Commit the returned file from the translator when all strings have been translated by downloading it from transifex and replacing the file in the source tree.
- Run :samp:`make compile-translation-strings` to create binary loadable translations.
- Ensure the .qm files are distributed with the release (the .ts files do not need to be released).
Note
Translators using QtLinguist should take heed - when refreshing the .ts file in QtLinguist, the file must be closed (:menuselection:`File --> Close`) and then reopened. Simply loading doing (:menuselection:`File --> Open`) and choosing the same file you already have in the workspace will not refresh the workspace with any new changes that appeared on disk.
Note
make update-translation-strings is non destructive. That is, you can safely run it as many times as you like, new strings will be added to it, deprecated strings will be left in place and already translated strings will remain translated.
Note
This is here for reference only, the :samp:`make update-translation-strings` make target will do all this for you.
Translation is done using gettext.
Create the initial .po file:
xgettext -d id -o i18n/id/LC_MESSAGES/inasafe.po i18ntest.py
After you create the initial .pot, you need to specify the characterset and encoding for that file (by editing it with a text editor). For example
"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n"
If you add strings to the file, update the .pot file by adding -j option
xgettext -j -d id -o i18n/id/LC_MESSAGES/inasafe.po i18ntest.py
Next, you can make the .po files available to translators. Recent versions of QtLinguist support translations of .po files, so you can use a similar process to that described in the gui section above.
When the .po file has been updated, it should be committed to the git repository (e.g. via a pull request from the user's repository clone, or by emailing the .po file to a developer). After receiving an updated .po file, it should be compiled to a :samp:`.mo` file (which is a binary representation of the strings)
msgfmt -o i18n/id/LC_MESSAGES/inasafe.mo i18n/id/LC_MESSAGES/inasafe.po
The :samp:`msgfmt` command accepts one or more input files which can be merged into a single :samp:`.mo`.
Note
These functions are wrapped as make scripts so you should not need to use them on a day to day basis.
As developer, before a release you should do:
- Run :samp:`make update-translation-strings` to update the translation files.
- Upload the translation strings to transifex.
- Instruct your translators to open the .po file for their locale with QtLinguist (by downloading from transifex), or to use the online tools transifex provides.
- Commit the returned file from the translator when all strings have been translated by downloading it from transifex and replacing the file in the source tree.
- Run :samp:`make compile-translation-strings` to create binary loadable translations (.mo files).
- Ensure the .mo files are distributed with the release (the .po files do not need to be released).
Note
Translators should take heed - when refreshing the .po file in QtLinguist, the file must be closed (:menuselection:`File --> Close`) and then reopened. Simply loading doing (:menuselection:`File --> Open`) and choosing the same file you already have in the workspace will not refresh the workspace with any new changes that appeared on disk.
Note
:samp:`make update-translation-strings` is non destructive. That is, you can safely run it as many times as you like, new strings will be added to it, deprecated strings will be left in place and already translated strings will remain translated.
To add a new source file, run
make update-translation-strings`
to generate the updated .po file and make it available to translators. When the translated file is returned from the translators (or via transifex) we will convert the .po file to a binary .mo file (which is used at runtime for the actual translation) then follow the :ref:`library-release-label` section above.