Download |
Bug Tracking |
Source |
Documentation |
Forum |
Latest Changes |
Home
The internationalization (also known as i18n) and localization are an easy step with Pluf as long as you start from the beginning to think about it.
Learn more about internationalization on Wikipedia.
What is really important to note, is that you can already apply all the following steps to make your code translation ready and translate only later. In fact, you should definitely have a code translation ready.
You need to provide the list of languages supported by your
application and load the translation middleware. The translation
middleware Pluf_Middleware_Translation must be loaded just after the
session middleware if you are using it.
For example:
$cfg['languages'] = array('en', 'fr', 'fr_QC', 'es');
$cfg['middleware_classes'] = array(
'Pluf_Middleware_Session',
'Pluf_Middleware_Translation',
);
The translation middleware can use session data to find which language is to be returned to the user, that is why you need to put it after the session middleware.
You only need to use one function or one block to translate your templates. The function is used when you need only to translate one line without substitution of variables and the block is used when you need either or both of substitution variables and plural forms.
Consider the following template fragment which is not translated:
<h1>Pluf internationalization</h1>
<p>To translate your code, use one of
the {$methods.count()} method(s):</p>
<ul>
{foreach $methods as $method}
<li>Name: {$method.name},
Description: {$method.description}.</li>
{/foreach}
</ul>
</html>
Now the version ready for translation:
<h1>{trans "Pluf internationalization"}</h1>
{assign $n_methods = $methods.count()}
<p>{blocktrans $n_methods}To translate your code, use
the following method:{plural}To translate your code, use
one of the {$n_methods} methods:{/blocktrans}</p>
<ul>
{foreach $methods as $method}
<li>{blocktrans}Name: {$method.name},
Description: {$method.description}.{/blocktrans}</li>
{/foreach}
</ul>
</html>
The simple translation function: trans is used the following way:
{trans "My string to translate"}
or
{trans 'My string to translate'}
You cannot use variables within the string. This is perfect for small strings in your templates.
The block has two different ways to be called, one for the plural form and one normal form.
A simple example without variable subsitution:
{blocktrans}This is a long text
that can be over multiple lines and that
can be translated later.{/blocktrans}
You can also substitute variables within the string, but you cannot call another function or block.
{blocktrans}I like {$fruit}, {$vegetable}
and {$place}.{/blocktrans}
{$fruit}, {$vegetable} and {$place} will be replaced with their
corresponding value as in the rest of your template.
Example of use without substitution of variables:
{blocktrans $counter}This is the singular
form.{plural}This is the plural form.
{/blocktrans}
Depending of the value of $counter, the first and unique parameter
given to the block, the singular or the plural form will be selected.
In exactly the same way as the normal form, you can substitute variables like that:
{blocktrans $counter}I have one {$pcbrand}.
{plural}I have {$counter} computers from several brands
including {$pcbrand}.
{/blocktrans}
As you can see, this is pretty flexible.
In your code, you can use two function to translation your code:
__: For example __('My simple string')_n: For example _n('Singular form.', 'Plural form.', $counter)The first function is to handle simple normal cases and the second one
to handle plural cases. If you want to perform variable substitution,
you can use the sprintf function like that:
$place = 'Berlin';
echo sprintf(__('I like %s.'), $place);
echo sprintf(__('I like %s.'), 'Berlin');
See the documentation of sprintf.
If you have a key indexed array of values you want to substitute in a
string, you can use the special Pluf_Translation::sprintf function.
For example:
$values = array('place' => 'Berlin',
'fruit' => 'apple',
'computer' => 'IBM');
echo Pluf_Translation::sprintf(__('I have one %%fruit%%, one %%computer%% in %%place%%.'), $values);
This will display:
I have one apple, one IBM in Berlin.
Or if you have translated the string 'I have one %%fruit%%, one %%computer%% in %%place%%.' in French:
J'ai une apple, un IBM à Berlin.
The translations are store in GNU Gettext PO files. This storage format allows to take benefit of all the set of utilities to parse the code to extract the strings and to perform the translations.
The .po files are stored as YourApp/locale/LANG/yourapp.po. For
example, the French translation of Pluf is in
Pluf/locale/fr/pluf.po. The particular form of a language, for
example the British English is stored in the en_GB folder.
The search order of the .po file is so that it will first try to find the corresponding territory version, for example fr_QC and if it is not available, it will default to use the main version fr. If none are available, it will not load any language file.
The templates are not using a standard gettext format, so the first
step is to convert your templates into a version ready to be consumed
by the gettext extract tool xgettext.
Go in your application folder, for example:
$ cd ~/myprojects/web/MyApp
Then run the following command:
$ php /path/to/pluf/extracttemplates.php ./conf/myapp.php ./gettexttemplates
You will see that a list of files is extracted. Looking into the newly
created gettexttemplates folder, you will see all your templates
with a .php extension and inside them, only the strings from the
trans function and the blocktrans blocks.
These files can now be parsed by xgettext.
The .pot file is the template .po file used as a basis for the
other languages. This is basically a .po file without
translations. This is the only file you should create automatically
with xgettext.
Create first a MyApp/locale folder. Your template file will be
MyApp/locale/myapp.pot.
Go in your application folder:
$ cd ~/myprojects/web/MyApp
And run the following commands, each command must be on a single line, the backslash (\) is here only for the presentation at the exception of the one just before the (;) which is needed:
$ xgettext -o myapp.pot -p ./MyApp/locale --force-po --from-code=UTF-8 \
--keyword --keyword=__ --keyword=_n:1,2 -L PHP *.php
$ find ./ -iname "*.php" -exec xgettext -o myapp.pot -p ./MyApp/locale \
--from-code=UTF-8 -j --keyword --keyword=__ --keyword=_n:1,2 \
-L PHP {} \;
You can learn more about xgettext by typing $ man xgettext on
your system.
Now consider you want to make the base French translation. Create a
folder MyApp/locale/fr and open Poedit.
In the file menu, select New catalog from POT file and select the
MyApp/locale/myapp.pot file.
Then go in the Catalog > Settings... menu and in the Project Info tab, input the followings:
Then in the Paths tab, input ../../ and click on Ok and in the
file menu save the file as /MyApp/locale/fr/myapp.po
If you wonder what are the plural forms, the plural forms manual is available.
Now, if you update your code, you need to have the new strings in your
.po file. What you have to do is first, update or recreate the
.pot file by first extracting the strings from the templates and
then running the xgettext utility.
Afterwards, open you .po file in Poedit and click on Catalog >
Update from POT file.... You will have some info, if everything looks
in order, for example that you do not have suddenly a lot less
strings, click on Ok. It is always good to make a backup of your .po file before updating it from a .pot file.
Now you can translate the new strings and update the old ones.
Report issues in the documentation
If you find errors or issues in the documentation, report a bug. We will update the documentation accordingly.
Pluf © 2005-2008 Loïc d'Anterroches, supported by Céondo Ltd.