[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/doc/ -> 13-I18n-and-L10n.txt (source)

   1  Chapter 13 - I18n And L10n
   2  ==========================
   3  
   4  If you ever developed an international application, you know that dealing with every aspect of text translation, local standards, and localized content can be a nightmare. Fortunately, symfony natively automates all the aspects of internationalization.
   5  
   6  As it is a long word, developers often refer to internationalization as i18n (count the letters in the word to know why). Localization is referred to as l10n. They cover two different aspects of multilingual web applications.
   7  
   8  An internationalized application contains several versions of the same content in various languages or formats. For instance, a webmail interface can offer the same service in several languages; only the interface changes.
   9  
  10  A localized application contains distinct information according to the country from which it is browsed. Think about the contents of a news portal: When browsed from the United States, it displays the latest headlines about the United States, but when browsed from France, the headlines concern the French news. So an l10n application not only provides content translation, but the content can be different from one localized version to another.
  11  
  12  All in all, dealing with i18n and l10n means that the application can take care of the following:
  13  
  14    * Text translation (interface, assets, and content)
  15    * Standards and formats (dates, amounts, numbers, and so on)
  16    * Localized content (many versions of a given object according to a country)
  17  
  18  This chapter covers the way symfony deals with those elements and how you can use it to develop internationalized and localized applications.
  19  
  20  User Culture
  21  ------------
  22  
  23  All the built-in i18n features in symfony are based on a parameter of the user session called the culture. The 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. Since it is serialized in the user session, the culture is persistent between pages.
  24  
  25  ### Setting the Default Culture
  26  
  27  By default, the culture of new users is the `default_culture`. You can change this setting in the `i18n.yml` configuration file, as shown in Listing 13-1.
  28  
  29  Listing 13-1 - Setting the Default Culture, in `myapp/config/i18n.yml`
  30  
  31      all:
  32        default_culture:     fr_FR
  33  
  34  >**NOTE**
  35  >During development, you might be surprised that a culture change in the `i18n.yml` file doesn't change the current culture in the browser. That's because the session already has a culture from previous pages. If you want to see the application with the new default culture, you need to clear the domain cookies or restart your browser.
  36  
  37  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).
  38  
  39  ### Changing the Culture for a User
  40  
  41  The user culture can be changed during the browsing session--for instance, when a user decides to switch from the English version to the French version of the application, or when a user logs in to the application and uses the language stored in his preferences. That's why the `sfUser` class offers getter and setter methods for the user culture. Listing 13-2 shows how to use these methods in an action.
  42  
  43  Listing 13-2 - Setting and Retrieving the Culture in an Action
  44  
  45      [php]
  46      // Culture setter
  47      $this->getUser()->setCulture('en_US');
  48  
  49      // Culture getter
  50      $culture = $this->getUser()->getCulture();
  51       => en_US
  52  
  53  >**SIDEBAR**
  54  >Culture in the URL
  55  >
  56  >When using symfony's localization and internationalization features, pages tend to have different versions for a single URL--it all depends on the user session. This prevents you from caching or indexing your pages in a search engine.
  57  >
  58  >One solution is to make the culture appear in every URL, so that translated pages can be seen as different URLs to the outside world. In order to do that, add the `:sf_culture` token in every rule of your application `routing.yml`:
  59  >
  60  >
  61  >     page:
  62  >       url: /:sf_culture/:page
  63  >       requirements: { sf_culture: (?:fr|en|de) }
  64  >       params: ...
  65  >
  66  >     article:
  67  >       url: /:sf_culture/:year/:month/:day/:slug
  68  >       requirements: { sf_culture: (?:fr|en|de) }
  69  >       params: ...
  70  >
  71  >
  72  >To avoid manually setting the sf_culture request parameter in every `link_to()`, symfony automatically adds the user culture to the default routing parameters. It also works inbound because symfony will automatically change the user culture if the `sf_culture` parameter is found in the URL.
  73  
  74  ### Determining the Culture Automatically
  75  
  76  In many applications, the user culture is defined during the first request, based on the browser preferences. Users can define a list of accepted languages in their browser, and this data is sent to the server with each request, in the `Accept-Language` HTTP header. You can retrieve it in symfony through the `sfRequest` object. For instance, to get the list of preferred languages of a user in an action, type this:
  77  
  78      [php]
  79      $languages = $this->getRequest()->getLanguages();
  80  
  81  The HTTP header is a string, but symfony automatically parses it and converts it into an array. So the preferred language of the user is accessible with `$languages[0]` in the preceding example.
  82  
  83  It can be useful to automatically set the user culture to the preferred browser languages in a site home page or in a filter for all pages.
  84  
  85  >**CAUTION**
  86  >The `Accept-Language` HTTP header is not very reliable information, since users rarely know how to modify it in their browser. Most of the time, the preferred browser language is the language of the interface, and browsers are not available in all languages. If you decide to set the culture automatically according to the browser preferred language, make sure you provide a way for the user to choose an alternate language.
  87  
  88  Standards and Formats
  89  ---------------------
  90  
  91  The internals of a web application don't care about cultural particularities. Databases, for instance, use international standards to store dates, amounts, and so on. But when data is sent to or retrieved from users, a conversion needs to be made. Users won't understand timestamps, and they will prefer to declare their mother language as Français instead of French. So you will need assistance to do the conversion automatically, based on the user culture.
  92  
  93  ### Outputting Data in the User's Culture
  94  
  95  Once the culture is defined, the helpers depending on it will automatically have proper output. For instance, the `format_number()` helper automatically displays a number in a format familiar to the user, according to its culture, as shown in Listing 13-3.
  96  
  97  Listing 13-3 - Displaying a Number for the User's Culture
  98  
  99      [php]
 100      <?php use_helper('Number') ?>
 101  
 102      <?php $sf_user->setCulture('en_US') ?>
 103      <?php echo format_number(12000.10) ?>
 104       => '12,000.10'
 105  
 106      <?php $sf_user->setCulture('fr_FR') ?>
 107      <?php echo format_number(12000.10) ?>
 108       => '12 000,10'
 109  
 110  You don't need to explicitly pass the culture to the helpers. They will look for it themselves in the current session object. Listing 13-4 lists helpers that take into account the user culture for their output.
 111  
 112  Listing 13-4 - Culture-Dependent Helpers
 113  
 114      [php]
 115      <?php use_helper('Date') ?>
 116  
 117      <?php echo format_date(time()) ?>
 118       => '9/14/06'
 119  
 120      <?php echo format_datetime(time()) ?>
 121       => 'September 14, 2006 6:11:07 PM CEST'
 122  
 123      <?php use_helper('Number') ?>
 124  
 125      <?php echo format_number(12000.10) ?>
 126       => '12,000.10'
 127  
 128      <?php echo format_currency(1350, 'USD') ?>
 129       => '$1,350.00'
 130  
 131      <?php use_helper('I18N') ?>
 132  
 133      <?php echo format_country('US') ?>
 134       => 'United States'
 135  
 136      <?php format_language('en') ?>
 137       => 'English'
 138  
 139      <?php use_helper('Form') ?>
 140  
 141      <?php echo input_date_tag('birth_date', mktime(0, 0, 0, 9, 14, 2006)) ?>
 142       => input type="text" name="birth_date" id="birth_date" value="9/14/06" size="11" />
 143  
 144      <?php echo select_country_tag('country', 'US') ?>
 145       => <select name="country" id="country"><option value="AF">Afghanistan</option>
 146            ...
 147            <option value="GB">United Kingdom</option>
 148            <option value="US" selected="selected">United States</option>
 149            <option value="UM">United States Minor Outlying Islands</option>
 150            <option value="UY">Uruguay</option>
 151            ...
 152          </select>
 153  
 154  The date helpers can accept an additional format parameter to force a culture-independent display, but you shouldn't use it if your application is internationalized.
 155  
 156  ### Getting Data from a Localized Input
 157  
 158  If it is necessary to show data in the user's culture, as for retrieving data, you should, as much as possible, push users of your application to input already internationalized data. This approach will save you from trying to figure out how to convert data with varying formats and uncertain locality. For instance, who might enter a monetary value with comma separators in an input box?
 159  
 160  You can frame the user input format either by hiding the actual data (as in a `select_country_tag()`) or by separating the different components of complex data into several simple inputs.
 161  
 162  For dates, however, this is often not possible. Users are used to entering dates in their cultural format, and you need to be able to convert such data to an internal (and international) format. This is where the `sfI18N` class applies. Listing 13-5 demonstrates how this class is used.
 163  
 164  Listing 13-5 - Getting a Date from a Localized Format in an Action
 165  
 166      [php]
 167      $date= $this->getRequestParameter('birth_date');
 168      $user_culture = $this->getUser()->getCulture();
 169  
 170      // Getting a timestamp
 171      $timestamp = sfI18N::getTimestampForCulture($date, $user_culture);
 172  
 173      // Getting a structured date
 174      list($d, $m, $y) = sfI18N::getDateForCulture($date, $user_culture);
 175  
 176  Text Information in the Database
 177  --------------------------------
 178  
 179  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.
 180  
 181  ### Creating Localized Schema
 182  
 183  For each table that contains some localized data, you should split the table in two parts: one table that does not have any i18n column, and the other one with only the i18n columns. The two tables are to be linked by a one-to-many relationship. This setup lets you add more languages when required without changing your model. Let's consider an example using a `Product` table.
 184  
 185  First, create tables in the `schema.yml` file, as shown in Listing 13-6.
 186  
 187  Listing 13-6 - Sample Schema for i18n Data, in `config/schema.yml`
 188  
 189      my_connection:
 190        my_product:
 191          _attributes: { phpName: Product, isI18N: true, i18nTable: my_product_i18n }
 192          id:          { type: integer, required: true, primaryKey: true, autoincrement: true }
 193          price:       { type: float }
 194  
 195        my_product_i18n:
 196          _attributes: { phpName: ProductI18n }
 197          id:          { type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id }
 198          culture:     { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
 199          name:        { type: varchar, size: 50 }
 200  
 201  Notice the `isI18N` and `i18nTable` attributes in the first table, and the special `culture` column in the second. All these are symfony-specific Propel enhancements.
 202  
 203  The symfony automations can make this much faster to write. If the table containing internationalized data has the same name as the main table with `_i18n` as a suffix, and they are related with a column named `id` in both tables, you can omit the `id` and `culture` columns in the `_i18n` table as well as the specific i18n attributes for the main table; symfony will infer them. It means that symfony will see the schema in Listing 13-7 as the same as the one in Listing 13-6.
 204  
 205  Listing 13-7 - Sample Schema for i18n Data, Short Version, in `config/schema.yml`
 206  
 207      my_connection:
 208        my_product:
 209          _attributes: { phpName: Product }
 210          id:
 211          price:       float
 212        my_product_i18n:
 213          _attributes: { phpName: ProductI18n }
 214          name:        varchar(50)
 215  
 216  ### Using the Generated I18n Objects
 217  
 218  Once the corresponding object model is built (don't forget to call `symfony` `propel-build-model` and clear the cache with a `symfony cc` after each modification of the `schema.yml`), you can use your `Product` class with i18n support as if there were only one table, as shown in Listing 13-8.
 219  
 220  Listing 13-8 - Dealing with i18n Objects
 221  
 222      [php]
 223      $product = ProductPeer::retrieveByPk(1);
 224      $product->setCulture('fr');
 225      $product->setName('Nom du produit');
 226      $product->save();
 227  
 228      $product->setCulture('en');
 229      $product->setName('Product name');
 230      $product->save();
 231  
 232      echo $product->getName();
 233       => 'Product name'
 234  
 235      $product->setCulture('fr');
 236      echo $product->getName();
 237       => 'Nom du produit'
 238  
 239  If you'd rather not have to remember to change the culture each time you use an i18n object, you can also change the `hydrate()` method in the object class. See an example in Listing 13-9.
 240  
 241  Listing 13-9 - Overriding the `hydrate()` Method to Set the Culture, in `myproject/lib/model/Product.php`
 242  
 243      [php]
 244      public function hydrate(ResultSet $rs, $startcol = 1)
 245      {
 246        parent::hydrate($rs, $startcol);
 247        $this->setCulture(sfContext::getInstance()->getUser()->getCulture());
 248      }
 249  
 250  As for queries with the peer objects, you can restrict the results to objects having a translation for the current culture by using the `doSelectWithI18n` method, instead of the usual `doSelect`, as shown in Listing 13-10. In addition, it will create the related i18n objects at the same time as the regular ones, resulting in a reduced number of queries to get the full content (refer to Chapter 18 for more information about this method's positive impacts on performance).
 251  
 252  Listing 13-10 - Retrieving Objects with an i18n `Criteria`
 253  
 254      [php]
 255      $c = new Criteria();
 256      $c->add(ProductPeer::PRICE, 100, Criteria::LESS_THAN);
 257      $products = ProductPeer::doSelectWithI18n($c, $culture);
 258      // The $culture argument is optional
 259      // The current user culture is used if no culture is given
 260  
 261  So basically, you should never have to deal with the i18n objects directly, but instead pass the culture to the model (or let it guess it) each time you do a query with the regular objects.
 262  
 263  Interface Translation
 264  ---------------------
 265  
 266  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.
 267  
 268  ### Configuring Translation
 269  
 270  The templates are not translated by default, which means that you need to activate the template translation feature in the `settings.yml` file prior to everything else, as shown in Listing 13-11.
 271  
 272  Listing 13-11 - Activating Interface Translation, in `myapp/config/settings.yml`
 273  
 274      all:
 275        .settings:
 276          i18n: on
 277  
 278  ### Using the Translation Helper
 279  
 280  Let's say that you want to create a website in English and French, with English being the default language. Before even thinking about having the site translated, you probably wrote the templates something like the example shown in Listing 13-12.
 281  
 282  Listing 13-12 - A Single-Language Template
 283  
 284      [php]
 285      Welcome to our website. Today's date is <?php echo format_date(date()) ?>
 286  
 287  For symfony to translate the phrases of a template, they must be identified as text to be translated. This is the purpose of the `__()` helper (two underscores), a member of the I18N helper group. So all your templates need to enclose the phrases to translate in such function calls. Listing 13-12, for example, can be modified to look like Listing 13-13 (as you will see in the "Handling Complex Translation Needs" section later in this chapter, there is an even better way to call the translation helper in this example).
 288  
 289  Listing 13-13 - A Multiple-Language-Ready Template
 290  
 291      [php]
 292      <?php use_helper('I18N') ?>
 293  
 294      <?php echo __('Welcome to our website.') ?>
 295      <?php echo __("Today's date is ") ?>
 296      <?php echo format_date(date()) ?>
 297  
 298  >**TIP**
 299  >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.
 300  
 301  ### Using Dictionary Files
 302  
 303  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.
 304  
 305  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.
 306  
 307  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.
 308  
 309  >**TIP**
 310  >In addition to the XLIFF standard, symfony also supports several other translation back-ends for dictionaries: gettext, MySQL, SQLite, and Creole. Refer to the API documentation for more information about configuring these back-ends.
 311  
 312  Listing 13-14 shows an example of the XLIFF syntax with the messages.fr.xml file necessary to translate Listing 13-13 into French.
 313  
 314  Listing 13-14 - An XLIFF Dictionary, in `myapp/i18n/messages.fr.xml`
 315  
 316      [xml]
 317      <?xml version="1.0" ?>
 318      <xliff version="1.0">
 319        <file orginal="global" source-language="en_US" datatype="plaintext">
 320          <body>
 321            <trans-unit id="1">
 322              <source>Welcome to our website.</source>
 323              <target>Bienvenue sur notre site web.</target>
 324            </trans-unit>
 325            <trans-unit id="2">
 326              <source>Today's date is </source>
 327              <target>La date d'aujourd'hui est </target>
 328            </trans-unit>
 329          </body>
 330        </file>
 331      </xliff>
 332  
 333  The `source-language` attribute must always contain the full ISO code of your default culture. Each translation is written in a `trans-unit` tag with a unique `id` attribute.
 334  
 335  With the default user culture (set to en_US), the phrases are not translated and the raw arguments of the `__()` calls are displayed. The result of Listing 13-13 is then similar to Listing 13-12. However, if the culture is changed to `fr_FR` or `fr_BE`, the translations from the `messages.fr.xml` file are displayed instead, and the result looks like Listing 13-15.
 336  
 337  Listing 13-15 - A Translated Template
 338  
 339      [php]
 340      Bienvenue sur notre site web. La date d'aujourd'hui est
 341      <?php echo format_date(date()) ?>
 342  
 343  If additional translations need to be done, simply add a new `messages.``XX``.xml` translation file in the same directory.
 344  
 345  ### Managing Dictionaries
 346  
 347  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:
 348  
 349    * `navigation.fr.xml`
 350    * `terms_of_service.fr.xml`
 351    * `search.fr.xml`
 352  
 353  Note that as soon as a translation is not to be found in the default `messages.XX.xml` file, you must declare which dictionary is to be used each time you call the `__()` helper, using its third argument. For instance, to output a string that is translated in the `navigation.fr.xml` dictionary, write this:
 354  
 355      [php]
 356      <?php echo __('Welcome to our website', null, 'navigation') ?>
 357  
 358  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).
 359  
 360  ### Handling Other Elements Requiring Translation
 361  
 362  The following are other elements that may require translation:
 363  
 364    * 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`:
 365  
 366      [php]
 367      <?php echo image_tag($sf_user->getCulture().'/myText.gif') ?>
 368  
 369    * 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.
 370    * 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.
 371  
 372  ### Handling Complex Translation Needs
 373  
 374  Translation only makes sense if the `__()` argument is a full sentence. However, as you sometimes have formatting or variables mixed with words, you could be tempted to cut sentences into several chunks, thus calling the helper on senseless phrases. Fortunately, the `__()` helper offers a replacement feature based on tokens, which will help you to have a meaningful dictionary that is easier to handle by translators. As with HTML formatting, you can leave it in the helper call as well. Listing 13-16 shows an example.
 375  
 376  Listing 13-16 - Translating Sentences That Contain Code
 377  
 378      [php]
 379      // Base example
 380      Welcome to all the <b>new</b> users.<br />
 381      There are <?php echo count_logged() ?> persons logged.
 382  
 383      // Bad way to enable text translation
 384      <?php echo __('Welcome to all the') ?>
 385      <b><?php echo __('new') ?></b>
 386      <?php echo __('users') ?>.<br />
 387      <?php echo __('There are') ?>
 388      <?php echo count_logged() ?>
 389      <?php echo __('persons logged') ?>
 390  
 391      // Good way to enable text translation
 392      <?php echo __('Welcome to all the <b>new</b> users') ?> <br />
 393      <?php echo __('There are %1% persons logged', array('%1%' => count_logged())) ?>
 394  
 395  In this example, the token is `%1%`, but it can be anything, since the replacement function used by the translation helper is `strtr()`.
 396  
 397  One of the common problems with translation is the use of the plural form. According to the number of results, the text changes but not in the same way according to the language. For instance, the last sentence in Listing 13-16 is not correct if `count_logged()` returns 0 or 1. You could do a test on the return value of this function and choose which sentence to use accordingly, but that would represent a lot of code. Additionally, different languages have different grammar rules, and the declension rules of plural can be quite complex. As this problem is very common, symfony provides a helper to deal with it, called `format_number_choice()`. Listing 13-17 demonstrates how to use this helper.
 398  
 399  Listing 13-17 - Translating Sentences Depending on the Value of Parameters
 400  
 401      [php]
 402      <?php echo format_number_choice(
 403        '[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are%1% persons logged', array('%1%' => count_logged()), count_logged()) ?>
 404  
 405  The first argument is the multiple possibilities of text. The second argument is the replacement pattern (as with the `__()` helper) and is optional. The third argument is the number on which the test is made to determine which text is taken.
 406  
 407  The message/string choices are separated by the pipe (`|`) character followed by an array of acceptable values, using the following syntax:
 408  
 409    * `[1,2]`: Accepts values between 1 and 2, inclusive
 410    * `(1,2)`: Accepts values between 1 and 2, excluding 1 and 2
 411    * `{1,2,3,4}`: Only values defined in the set are accepted
 412    * `[-Inf,0)`: Accepts values greater or equal to negative infinity and strictly less than 0
 413  
 414  Any nonempty combinations of the delimiters of square brackets and parentheses are acceptable.
 415  
 416  The message will need to appear explicitly in the XLIFF file for the translation to work properly. Listing 13-18 shows an example.
 417  
 418  Listing 13-18 - XLIFF Dictionary for a `format_number_choice()` Argument
 419  
 420      ...
 421      <trans-unit id="3">
 422        <source>[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are%1% persons logged</source>
 423        <target>[0]Personne n'est connecté|[1]Une personne est connectée|(1,+Inf]Ily a %1% personnes en ligne</target>
 424      </trans-unit>
 425      ...
 426  
 427  >**SIDEBAR**
 428  >A few words about charsets
 429  >
 430  >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.
 431  >
 432  >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.
 433  >
 434  >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.
 435  >
 436  >     all:
 437  >       .settings:
 438  >         charset: utf-8
 439  
 440  ### Calling the Translation Helper Outside a Template
 441  
 442  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 13-19 shows how to call the helper in an action by retrieving the current instance of the `I18N` object through the context singleton.
 443  
 444  Listing 13-19 - Calling `__()` in an Action
 445  
 446      [php]
 447      $this->getContext()->getI18N()->__($text, $args, 'messages');
 448  
 449  Summary
 450  -------
 451  
 452  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.


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7