symfony : I18n And L10n


Published on

The Definitive Guide to symfony
I18n And L10n

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

symfony : I18n And L10n

  1. 1. #13 The Definitive Guide to symfony I18n And L10n Doc. v. 0.1 - 15/05/09 Wildan Maulana | wildan [at]
  2. 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. 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. 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. 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. 6. Determining the Culture Automatically $language = $request->getPreferredCulture(array('en', 'fr')); // the website is available in English and French
  7. 7. Standards and Formats • Outputting Data in the User's Culture •
  8. 8. Culture-Dependent Helpers Outputting Data in <?php use_helper('Date') ?> <?php echo format_date(time()) ?> the User's Culture => '9/14/06' <?php echo format_datetime(time()) ?> => 'September 14, 2006 6:11:07 PM CEST' <?php use_helper('Number') ?> <?php echo format_number(12000.10) ?> => '12,000.10' <?php echo format_currency(1350, 'USD') ?> => '$1,350.00' Displaying a Number for the User's Culture <?php use_helper('Number') ?> <?php use_helper('I18N') ?> <?php $sf_user->setCulture('en_US') ?> <?php echo format_country('US') ?> => 'United States' <?php echo format_number(12000.10) ?> => '12,000.10' <?php format_language('en') ?> => 'English' <?php $sf_user->setCulture('fr_FR') ?> <?php echo format_number(12000.10) ?> <?php use_helper('Form') ?> => '12 000,10' <?php echo input_date_tag('birth_date', mktime(0, 0, 0, 9, 14, 2006)) ?> => input type=quot;textquot; name=quot;birth_datequot; id=quot;birth_datequot; value=quot;9/14/06quot; size=quot;11quot; /> <?php echo select_country_tag('country', 'US') ?> => <select name=quot;countryquot; id=quot;countryquot;><option value=quot;AFquot;>Afghanistan</option> ... <option value=quot;GBquot;>United Kingdom</option> <option value=quot;USquot; selected=quot;selectedquot;>United States</option> <option value=quot;UMquot;>United States Minor Outlying Islands</option> <option value=quot;UYquot;>Uruguay</option> ... </select>
  9. 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. 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.
  11. 11. Creating Localized Schema Sample Schema for i18n Data, in config/schema.yml my_connection: my_product: _attributes: { phpName: Product, isI18N: true, i18nTable: my_product_i18n } id: { type: integer, required: true, primaryKey: true, autoincrement: true } price: { type: float } my_product_i18n: _attributes: { phpName: ProductI18n } id: { type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id } culture: { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true } name: { type: varchar, size: 50 } Sample Schema for i18n Data, Short Version, in config/schema.yml my_connection: my_product: _attributes: { phpName: Product } id: price: float my_product_i18n: _attributes: { phpName: ProductI18n } name: varchar(50)
  12. 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. 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.
  14. 14. Configuring Translation Activating Interface Translation, in frontend/config/settings.yml all: .settings: i18n: on
  15. 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. 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. 17. An XLIFF Dictionary, in frontend/i18n/ <?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. 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 file into these three files in the application i18n/ directory: • • • <?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. 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. 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. 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. 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. 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. 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.
  25. 25. Reference • The Definitive Guide to symfony,Fabien Potencier, Apress