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.
