Community wiki

Community wiki

How to create eGW applications for easy translation into other languages

The most important is to use variables for all labels, messages or any text which will appear on the user interface. When the programm finds such a variable it will pass it to the lang function which retrieves the correct translation according to the users lang settings:

echo lang('Hello World !!!');

How does the translation-process works in eGW ?

The lang function is defined in phpgwapi/inc/ which is executet by
function lang($phrase,$p1='',$p2='',...,$p9='')
   return $GLOBALS['phpgw']->translation->translate($phrase,$p1,$p2,...,$p9);

On every page-request, the user settings are loaded from the database into the array $GLOBALS['phpgw_info']['user']. One of this preferences is the desired language. The translation class loads then the corresponding translated text into an (associative) array. On each lang-call the translation-class look if it has the label in the array and returns it, if it's there, else the original (hopefully complete and english) phrase is returned with an asterix '*' attached at the end.

The following definition of the lang-function shows that it can called with parameters. The syntax is: '%<n>' where <n> is a digit from 1 to 9 (in that order):

lang('Hello %1 !!!',$user ? $user : lang('all'));

Each application provides the translations of its labels on a per-language basis in the file phpgw_<language-id>.lang in its setup-directory. The exact format of theses files (eg. fields, ordering and case of the labels) is descriped , but I would recommend to use the TranslationTools to work with the files instead of a simple text editor. setup loads the language-files into the database, whenever I install a new app or language. Since the eGW checks for new translation (eg. updated lang-files via cvs) on each login.

There is a lot more to keep into your mind, here are some common pitfalls

  • dont: lang('please confirm ').($time).lang(' if you want to delete ').$object . '.';
better: lang('please confirm %1, if you want to delete %2.',$time,$object);
  • word-ordering is very different in different languages
  • leading and trailing spaces are removed by the translation functions

  • dont:
$messages = array(
   'cant' => 'Can\'t do this!!!',
   'love' => 'Love to do it!!!'
echo lang($messages[$reason]);
$messages = array(
   'cant' => lang('Can\'t do this!!!'),
   'love' => lang('Love to do it!!!')
echo $messages[$reason];
  • no automatic tools (like eg. the TranslationTools) will find the labels, you have to add them manualy to the english lang-file, which is error prown, as we all tend to forgot it ;-)

  • dont: lang('warn_about_this');
better: lang('Warning: This can be a XYZ, be aware !!!');
  • You might say as long as the label is unique and its in the lang-file it should lead to the same result. But this is only half of the story, not all foreign translations have all the phrases and in this case the user would just get warn_about_this* and the translator or an other developer has to guess or look in the english file what is meant with the label.

  • dont: lang("x not found while trying to x",$n,$pattern);
better: lang("%1 not found while trying to '%2'",$n,$pattern);
  • same story as above, if the label is missing, the message of the message gets lost. Dont just append the 2 parameters to the string without them, as this does not nicely translate to other word-orders

  • dont: echo $first . ' ' . lang('to') . ' ' . $last;
  • better: echo lang('%1 to %2',$first,$last);
    • unfortunaly there is no 1 - 1 relationship between words in different languages and specialy this small words tend to have several meanings. By includeing the 2 parameters, you put it more into a context, and make more likely to have a 1 - 1 translation. To give an example you can use 'to' in this numerical range, but it can also be the receipient of eg. an email, which does not translate to the same word in all other languages.

If you have more questions or additions to this page please add them here or mail them to RalfBecker

Back to: eGroupWare / DeveloperDocs
You are here