Tuesday 22 July 2008 2:16:56 pm
ezPublish ships with a nice mechanism for translating text in templates. However, it is pretty undocumented too. There is an article here http://ez.no/ezpublish/documentation/configuration/configuration/language_and_charset/creating_a_new_translation
----------------------------
The basics are as follows: ---------------------------- Whenever your templates or php call i18n('foo'), once you look at your website in a browser, ezpublish will try to translate the word 'foo' into the language you are currently viewing. To do this, it uses dictionary files located in /share/translations. So to setup a multilingual site, you create different siteaccesses in different languages, you start using i18n() in your templates and php, and you put some dictionaries in /share/translations. To create those dictionaries, you can use ezlupdate from the command line. If anywhere in your code it says
i18n('foo')
and, in the root of the site, you run the command
bin/linux/ezlupdate ger-DE
a file will be updated here:
share/translations/ger-DE/translation.ts
containing
<message>
<source>foo</source>
<translation type="unfinished"></translation>
</message>
if you change this to
<message>
<source>foo</source>
<translation>bar</translation>
</message>
delete all caches, and look at the german version of your site, you will see
bar
there. Et voila.
----------------------------
ezlupdate, linguist and addicted ---------------------------- To manage the dictionary files in a gui environment, there is a program called Linguist from Trolltech. It is indeed very neat and usefull for professional translators too. And I love the way it prints.
You can download ezlupdate and Linguist in one package here: http://ez.no/download/translations/ezlupdate_and_linguist (NB, when forwarding this url to your translators, ask them to ignore the README and just doubleclick the Linguist icon...) (NB, I've noticed ezlupdate to have some bugs. You may have to play with your command line parameters a bit )
Additional to editing your dictionaries by hand or using Linguist, you can
either use the Addicted extension, which allows you to edit your dictionaries through a webbrowser, or use xslt to transform them. there are some examples of xslt transformations in the Addicted distro. Addicted and the xslt goodies can be downloaded here: http://ez.no/developer/contribs/applications/addicted
----------------------------
usage issues ---------------------------- So far so good. Now for the real usage. This mechanism has a lot of power, but you have to decide how to use it. For example:
1) if you run ezlupdate as described, it will translate /lib/, /kernel/ and all folders in /design/. This will generate one dictionary of ~1Mb containg the whole ezPublish kernel, admin, everything. But all you wanted was the word 'foo'. You can't send this big file to a translator, too. Or should you ?
2) After a year, you read "foo" in the dictionary, and obviously that is a typo, since it should be "phou". But in which templates is this word used ? It could be all over your site.
3) You finally found the template, and you change the word "foo" into "phou". When you look at the german site, it doesn't say "bar" anymore, it says "phou", which is clearly not german. These may seem minors issues, but if you have a site with >100 templates in x languages, they become annoying.
----------------------------
how I do these things ----------------------------
1) I run ezlupdate as follows, in the root of the site:
bin/linux/ezlupdate -e share ger-DE -d design/mysite
This is a bit of a hack, but it translates *only* design/mysite into share/translations/ger-DE/translation.ts. Option -e sets ezlupdate in 'extension mode', making it ignore /lib, /kernel etc, and only translating everything in 'share'. luckily, there is nothing to be translated in /share. The -d option adds the directory design/mysite to scan. And this contains 1 template with the word foo. So the dictionary file will only contain the word 'foo'. Now beware. Most ezpublish sites actually do display content from kernel, lib, base etc. If you have a 100% hebrew site, you'll probably have to send your translator the full ~1Mb file ... and explain him/her what 'Module not found' and 'You have no permission to %1' means. Unless you think you've caught all errors and exceptions in your own templates. But you're never sure. For all my extensions, I create dictionaries inside the extension, like this:
bin/linux/ezlupdate -e extension/myextension ger-DE
This will update the file extension/myextension/translations/ger-DE/translation.ts
2) the i18n method requires you to specify a 'context' for your word, like
i18n('foo','/design/mysite/test')
this will return in the dictionary file as
<context>
<name>/design/mysite/test</name>
<message>
<source>foo</source>
<translation type="unfinished"></translation>
</message>
</context>
after long confusion of what policy to use for contexts, i finally decided to simply use the path of the template or php file in which the word appears. so the above example would be inside /design/mysite/test.tpl. this does not make much sense to the translators, but all the words will still be chucked together nicely, and translators will recognize the clusters from the front end. there may be a bit of duplication, but since most of your duplicate code will end up in include files anyway, not much. And as a big plus, whenever I see the word foo in the dictionary, I know where to find it in the templates or php, and vice versa, quickly and efficiently !
3) ezp assumes english is the base language of your site; this is hardcoded in the kernel. If you are viewing the english version of your site, no dictionary will be applied. But if you change your english, you have to adjust all your dictionaries. This more or less freezes all your development. Imagine problems with ï or ø, or ’. Imagine telling your client 'adding a space before the questionmark there will take me 30 minutes'. no way. So I've recently decided to stop using english in my templates. I use *tokens* now: instead of saying
{"foo"|i18n('/design/mysite/test')}
I say
{"test-message"|i18n('/design/mysite/test')}
and in the english dictionary, i write
<context>
<name>/design/mysite/test</name>
<message>
<source>test-message</source>
<translation>foo</translation>
</message>
</context>
And something similar in the german dictionary file. I personally like the sight of a 'tokenized' webpage - not containing human texts yet. Once the design is done, I can take it to an english editor or interaction designer, and finetune the actual wordings. I can easily see on the front end what hasn't been translated yet (or where the dictionary went wrong), just by looking at the english. Later, I can easily change the english, without breaking the german. This is much like the use of "entities" in XUL. Note, I had to have the kernel hacked enable the eng-GB dictionary... However, if I send this file to the translator, he/she wants some idea of what "test-message" should be. So I add this to the comment:
{"test-message"|i18n('/design/mysite/test','foo')}
which ends up in the dictionary as
<context>
<name>/design/mysite/test</name>
<message>
<source>test-message</source>
<translation type="unfinished"></translation>
<comment>foo</comment>
</message>
</context>
The comment shows up nicely in Linguist - especially if you print, btw. So that's the way I do it. I'm curious what other people do .. $2c!
---------------
The class eZContentObjectTreeNode does.
|