"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
The Definitive Guide to symfony I18n And L10n
1. #13
The Definitive Guide to symfony
I18n And L10n
Doc. v. 0.1 - 15/05/09
Wildan Maulana | wildan [at] tobethink.com
2. TOC User Culture
•
Setting the Default Culture
–
Changing the Culture for a User
–
Determining the Culture Automatically
–
Standards and Formats
•
Outputting Data in the User's Culture
–
Getting Data from a Localized Input
–
Text Information in the Database
•
Creating Localized Schema
–
Using the Generated I18n Objects
–
Interface Translation
•
Configuring Translation
–
Using the Translation Helper
–
Using Dictionary Files
–
Managing Dictionaries
–
New in symfony 1.1
–
Handling Other Elements Requiring Translation
•
Handling Complex Translation Needs
•
Calling the Translation Helper Outside a Template
•
Summary
•
3. User Culture
• All the built-in i18n features in symfony are based on a
parameter of the user session called the culture.
• he culture is the combination of the country and the
language of the user, and it determines how the text and
culture-dependent information are displayed
4. Setting the Default Culture
Setting the Default Culture, in frontend/config/settings.yml
•
all:
.settings:
default_culture: fr_FR
Keeping both the language and the country in the culture is
•
necessary because you may have a different French translation
for users from France, Belgium, or Canada, and a different
Spanish content for users from Spain or Mexico. The language is
coded in two lowercase characters, according to the ISO 639-1
standard (for instance, en for English). The country is coded in
two uppercase characters, according to the ISO 3166-1 standard
(for instance, GB for Great Britain).
5. Changing the Culture for a User
// Culture setter
$this->getUser()->setCulture('en_US');
// Culture getter
$culture = $this->getUser()->getCulture();
=> en_US
Culture in the URL
page:
url: /:sf_culture/:page
requirements: { sf_culture: (?:fr|en|de) }
params: ...
article:
url: /:sf_culture/:year/:month/:day/:slug
requirements: { sf_culture: (?:fr|en|de) }
params: ...
6. Determining the Culture Automatically
$language = $request->getPreferredCulture(array('en', 'fr'));
// the website is available in English and French
9. Getting Data from a Localized Input
Getting a Date from a Localized Format in an Action
$date= $request->getParameter('birth_date');
$user_culture = $this->getUser()->getCulture();
// Getting a timestamp
$timestamp = $this->getContext()->getI18N()->getTimestampForCulture($date, $user_culture);
// Getting a structured date
list($d, $m, $y) = $this->getContext()->getI18N()->getDateForCulture($date, $user_culture);
10. Text Information in the Database
• A localized application offers different content
according to the user's culture. For instance, an
online shop can offer products worldwide at the same
price, but with a custom description for every
country. This means that the database must be able
to store different versions of a given piece of data,
and for that, you need to design your schema in a
particular way and use culture each time you
manipulate localized model objects.
12. Using the Generated I18n Objects
Dealing with i18n Objects
$product = ProductPeer::retrieveByPk(1);
$product->setName('Nom du produit'); // By default, the culture is the current user culture
$product->save();
echo $product->getName();
=> 'Nom du produit'
$product->setName('Product name', 'en'); // change the value for the 'en' culture
$product->save();
echo $product->getName('en');
=> 'Product name'
Retrieving Objects with an i18n Criteria
$c = new Criteria();
$c->add(ProductPeer::PRICE, 100, Criteria::LESS_THAN);
$products = ProductPeer::doSelectWithI18n($c, $culture);
// The $culture argument is optional
// The current user culture is used if no culture is given
13. Interface Translation
• The user interface needs to be adapted for i18n
applications. Templates must be able to display labels,
messages, and navigation in several languages but with
the same presentation. Symfony recommends that you
build your templates with the default language, and that
you provide a translation for the phrases used in your
templates in a dictionary file. That way, you don't need to
change your templates each time you modify, add, or
remove a translation.
15. Using the Translation Helper
A Multiple-Language-Ready Template
<?php use_helper('I18N') ?>
<?php echo __('Welcome to our website.') ?>
<?php echo __(quot;Today's date is quot;) ?>
<?php echo format_date(date()) ?>
If your application uses the I18N helper group for every page,
it is probably a good idea to include it in the standard_helpers setting in
the settings.yml file, so that you avoid repeating use_helper('I18N') for each template.
16. Using Dictionary Files
Each time the __() function is called, symfony looks for a translation of its
•
argument in the dictionary of the current user's culture. If it finds a
corresponding phrase, the translation is sent back and displayed in the
response. So the user interface translation relies on a dictionary file.
The dictionary files are written in the XML Localization Interchange File
•
Format (XLIFF), named according to the pattern messages.[language
code].xml, and stored in the application i18n/ directory.
XLIFF is a standard format based on XML. As it is well known, you can use
•
third-party translation tools to reference all text in your website and
translate it. Translation firms know how to handle such files and to
translate an entire site just by adding a new XLIFF translation.
17. An XLIFF Dictionary, in
frontend/i18n/messages.fr.xml
<?xml version=quot;1.0quot; ?>
<xliff version=quot;1.0quot;>
<file original=quot;globalquot; source-language=quot;en_USquot; datatype=quot;plaintextquot;>
<body>
<trans-unit id=quot;1quot;>
<source>Welcome to our website.</source>
<target>Bienvenue sur notre site web.</target>
</trans-unit>
<trans-unit id=quot;2quot;>
<source>Today's date is </source>
<target>La date d'aujourd'hui est </target>
</trans-unit>
</body>
</file>
</xliff>
As looking for dictionary files, parsing them, and finding the correct translation for
a given string takes some time, symfony uses an internal cache to speedup the process.
By default, this cache uses the filesystem. You can configure how the i18N
cache works (for instance, to share the cache between several servers) in
the factories.yml (see Chapter 19).
18. Managing Dictionaries
If your messages.XX.xml file becomes too long to be readable, you can always
split the translations into several dictionary files, named by theme. For instance,
you can split the messages.fr.xml file into these three files in the application
i18n/ directory:
navigation.fr.xml
•
terms_of_service.fr.xml
•
search.fr.xml
•
<?php echo __('Welcome to our website', null, 'navigation') ?>
Another way to organize translation dictionaries is
to split them by module. Instead of writing a single
messages.XX.xml file for the whole application,
you can write one in each modules/[module_name]/i18n/ directory.
It makes modules more independent from the application,
which is necessary if you want to reuse them,
such as in plug-ins (see Chapter 17).
19. Handling Other Elements Requiring Translation
The following are other elements that may require translation:
Images, text documents, or any other type of assets can also
•
vary according to the user culture. The best example is a piece
of text with a special typography that is actually an image. For
these, you can create subdirectories named after the user
culture:
<?php echo image_tag($sf_user->getCulture().'/myText.gif') ?>
Error messages from validation files are automatically output by
•
a __(), so you just need to add their translation to a dictionary to
have them translated.
The default symfony pages (page not found, internal server
•
error, restricted access, and so on) are in English and must be
rewritten in an i18n application. You should probably create your
own default module in your application and use __() in its
templates. Refer to Chapter 19 to see how to customize these
pages.
20. Handling Complex Translation Needs
Translating Sentences That Contain Code
// Base example
Welcome to all the <b>new</b> users.<br />
There are <?php echo count_logged() ?> persons logged.
// Bad way to enable text translation
<?php echo __('Welcome to all the') ?>
<b><?php echo __('new') ?></b>
<?php echo __('users') ?>.<br />
<?php echo __('There are') ?>
<?php echo count_logged() ?>
<?php echo __('persons logged') ?>
// Good way to enable text translation
<?php echo __('Welcome to all the <b>new</b> users') ?> <br />
<?php echo __('There are %1% persons logged', array('%1%' => count_logged())) ?>
21. Handling Complex Translation Needs #2
Translating Sentences Depending on the Value of Parameters
<?php echo format_number_choice(
'[0]Nobody is logged|[1]There is 1 person logged|
(1,+Inf]There are %1% persons logged',
array('%1%' => count_logged()), count_logged()) ?>
The message/string choices are separated by the pipe (|) character followed by an array of
acceptable values, using the following syntax:
[1,2]: Accepts values between 1 and 2, inclusive
–
(1,2): Accepts values between 1 and 2, excluding 1 and 2
–
{1,2,3,4}: Only values defined in the set are accepted
–
[-Inf,0): Accepts values greater or equal to negative infinity and strictly less than 0
–
{n: n % 10 > 1 && n % 10 < 5} pliki: Matches numbers like 2, 3, 4, 22, 23, 24 (useful
–
for languages like polish or russian)
XLIFF Dictionary for a format_number_choice() Argument
...
<trans-unit id=quot;3quot;>
<source>[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are %1% persons logged</source>
<target>[0]Personne n'est connecté|[1]Une personne est connectée|(1,+Inf]Il y a %1% personnes en ligne</target>
</trans-unit>
...
22. A few words about charsets
Dealing with internationalized content in templates often leads to problems with
charsets. If you use a localized charset, you will need to change it each time
the user changes culture. In addition, the templates written in a given charset will
not display the characters of another charset properly.
This is why, as soon as you deal with more than one culture, all your templates
must be saved in UTF-8, and the layout must declare the content with this charset.
You won't have any unpleasant surprises if you always work with UTF-8,
and you will save yourself from a big headache.
Symfony applications rely on one central setting for the charset,
in the settings.yml file. Changing this parameter will change the
content-type header of all responses.
all:
.settings:
charset: utf-8
23. Calling the Translation Helper Outside a Template
Not all the text that is displayed in a page comes from templates.
That's why you often need to call the __() helper in other parts of your application:
actions, filters, model classes, and so on. Listing below shows how to call
the helper in an action by retrieving the current instance of the I18N object
through the context singleton.
$this->getContext()->getI18N()->__($text, $args, 'messages');
24. Summary
Handling internationalization and localization in web applications
is painless if you know how to deal with the user culture.
The helpers automatically take it into account to output correctly
formatted data, and the localized content from the database
is seen as if it were part of a simple table.
As for the interface translation, the __() helper and XLIFF dictionary
ensure that you will have maximum versatility with minimum work.