TimeTrex Message Internationalization(i18n) README by Open Source Consulting, S.A. = OVERVIEW = TimeTrex contains english strings embedded throughout the PHP code and smarty templates. The GNU Gettext suite of tools has been chosen to aid with the tasks of: - marking and extracting english strings from the source files - translating english strings into other languages - displaying the foreign language translations of the strings - merging in new english strings from the source files - merging in new translations from the translators It is a very good idea for anyone working in this area to read up more about gettext here: http://www.gnu.org/software/gettext/ Below, we will explain more about how gettext is integrated with TimeTrex, how to properly code strings for translation, and how the translation maintenance tools work. = TTi18n Class = TimeTrex now includes a class for handling all i18n related matters. Methods related to message translation include: - chooseBestLocale() -- determines which locale to use for messages. - gettext() -- returns a translated version of given input string. This class works basically like the standard setlocale(), bindtextdomain(), gettext() combination but it allows us to abstract the implementation a bit. For example, we may use PEAR's Translation2 class to parse the gettext files, instead of using PHP's native gettext() function. For this reason, it is important that all translation calls in the system go through TTi18n::gettext() instead of calling gettext() directly. = Smarty Template Files = We are using a slightly modified version of the gettext plugin for smarty. This plugin allows us to mark strings for translation with the following syntax: {t}Here is some text that needs to be translated.{/t} The only modification to this plugin is that we call TTi18n::gettext() (when defined) instead of gettext(). = PHP Source Code Files = Any strings within the source code that... a) contain words and b) are intended for an end-user to see ...must be embedded within a call to TTi18n::gettext( "my string" ). There are two reasons for this: 1) gettext() must be called in order to perform the translation at runtime. This should be obvious. 2) The string extractor looks for "gettext( ... )" to know which strings to extract. Therefore, the following code is to be avoided: $myvar = 'Please enter a value below'; $myvar = TTi18n::gettext( $myvar ); While the above would do the right thing at runtime, the extractor would not know that this string represents english, so the above string would probably never get translated. Instead, this should be coded as: $myvar = TTi18n::gettext('Please enter a value below'); Be careful to ensure that gettext() is only called once on a given string. Calling multiple times will probably not cause display problems, but each call adds some performance overhead. = The locale directories and messages.po files = The locale directory exists at timetrex/interface/locale This directory contains: - the messages.pot master string dictionary with all english strings. - a sub-directory for each locale, eg es_ES for spanish/Spain. - the locale_stats.txt file which contains statistics about translations. Each locale sub-directory contains another sub-directory LC_MESSAGES which in turn contains messages.po and (possibly) messages.mo. messages.po will contain the translations for that particular locale. messages.mo is a compiled form of the .po file that is necessary for GNU gettext to function -- however, it is not always required when using the Translation2 library. *** IMPORTANT *** In the interest of avoiding possible encoding headaches, we are standardizing on the use UTF-8 encoded messages.po files. That is, all messages.po should be saved as UTF-8 before they are placed/updated into the tree. Why? It has been observed that the Translation2 library does not properly convert encodings. While it may be possible to work around this, UTF-8 makes things simple all around. = The Translation helper tools = These files live in tools/i18n. ( Though they could be anywhere. ) Each of these should be run from the directory in which it is saved. mklocales.php This script creates and initializes the locale directories beneath the interface/locale directory. Edit the script and re-run to add a new locale directory and associated messages.po file. gen_master_pot.sh This file generates a master messages.pot file in the interface/locale directory. This file is then used as the source when merging to individual locales. mergelocale.sh This script merges new strings from messages.pot master file into a messages.po file for a single locale. It also generates the binary messages.mo file. Typically, this script is only called by mergelocales.sh mergelocales.php This script merges new strings from message.pot master file into the messages.po files for all existings locale directories, creates the binary messages.mo files, and updates the translation stats. calc_l10n_stats.php This script calculates the percentage of the application that has been translated for each available locale. It writes out a csv file that can be read by a PHP script to display the stats on a web page. notify_translator.php This file notifies the translator by e-mail when new source strings are available for TimeTrex. Be careful not to run this by accident, as you may end up spamming people unnecessarily. tsmarty2c.php This script is part of the smarty gettext plugin, and is used to extract the strings that can be translated from the smarty templates. This script is called by the gen_master_pot.sh script. updatetranslation.sh This script is used to merge a single messages.po file provided by a translator with the corresponding messages.po files within TimeTrex. = Using the translation helper tools on a daily basis = These are the typical events that happen during application development: 1) New strings get added into the PHP source or smarty templates. 2) A translator sent in new translations. 3) We need to add a new locale (language) for translation. Let's look at them individually: 1) New strings get added into the PHP source or smarty templates. In this case, we need to a) update the master .pot file, b) merge those changes into the indvidual messages.po files, c) generate the binary messages.mo files and d) update the locale stats. It is as simple as: $ ./gen_master_pot.sh $ ./mergelocales.php 2) A translator sent in new translations. Here, we just need to merge the translator's changes into a single messages.po file for a single locale. Then we want to update the binary message.mo file and the locale stats. Let's suppose we have just received spanish translations ( es_ES ) and have saved them in /tmp/messages.po. $ ./update_translation.sh es_ES /tmp/messages.po $ ./calc_l10n_stats.php 3) We need to add a new locale (language) for translation. Let's suppose we have found an Italian translator, and now we want to add an it_IT locale. All we do is: $ vi mklocales.php # Now uncomment the line with // 'it_IT'. $ ./mklocales.php We could also make all the known locales by uncommenting all the locale lines in this script, and then re-running it.