title: i18n summary: Display templates and PHP code in different languages based on the preferences of your website users. # i18n The i18n class (short for "internationalization") in SilverStripe enables you to display templates and PHP code in different languages based on your global settings and the preferences of your website users. This process is also known as l10n (short for "localization"). For translating any content managed through the CMS or stored in the database, please use the [translatable](http://github.com/silverstripe/silverstripe-translatable) module. This page aims to describe the low-level functionality of the i18n API. It targets developers who: * Are involved in creating templates in different languages. * Want to build their own modules with i18n capabilities. * Want to make their PHP-code (e.g. form labels) i18n-ready ## Usage ### Enabling i18n The i18n class is enabled by default. ### Setting the locale To set the locale you just need to call [api:i18n::set_locale()] passing, as a parameter, the name of the locale that you want to set. :::php // mysite/_config.php i18n::set_locale('de_DE'); // Setting the locale to German (Germany) i18n::set_locale('ca_AD'); // Setting to Catalan (Andorra) Once we set a locale, all the calls to the translator function will return strings according to the set locale value, if these translations are available. See [unicode.org](http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html) for a complete listing of available locales. The `i18n` logic doesn't set the PHP locale via [setlocale()](http://php.net/setlocale). Localisation methods in SilverStripe rely on explicit locale settings as documented below. If you rely on PHP's built-in localisation such as [strftime()](http://php.net/strftime), please only change locale information selectively. Setting `LC_ALL` or `LC_NUMERIC` will cause issues with SilverStripe operations such as decimal separators in database queries. ### Getting the locale As you set the locale you can also get the current value, just by calling [api:i18n::get_locale()]. ### Declaring the content language in HTML {#declaring_the_content_language_in_html} To let browsers know which language they're displaying a document in, you can declare a language in your template. :::html //'Page.ss' (HTML) //'Page.ss' (XHTML) Setting the `` attribute is the most commonly used technique. There are other ways to specify content languages (meta tags, HTTP headers), explained in this [w3.org article](http://www.w3.org/International/tutorials/language-decl/). You can also set the [script direction](http://www.w3.org/International/questions/qa-scripts), which is determined by the current locale, in order to indicate the preferred flow of characters and default alignment of paragraphs and tables to browsers. :::html ### Date and time formats Formats can be set globally in the i18n class. You can use these settings for your own view logic. :::php Config::inst()->update('i18n', 'date_format', 'dd.MM.YYYY'); Config::inst()->update('i18n', 'time_format', 'HH:mm'); Localization in SilverStripe uses PHP's [intl extension](http://php.net/intl). Formats for it's [IntlDateFormatter](http://php.net/manual/en/class.intldateformatter.php) are defined in [ICU format](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details), not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php). These settings are not used for CMS presentation. Users can choose their own locale, which determines the date format that gets presented to them. Currently this is a mix of PHP defaults (for readonly `DateField` and `TimeField`), browser defaults (for `DateField` on browsers supporting HTML5), and [Moment.JS](http://momentjs.com/) client-side logic (for `DateField` polyfills and other readonly dates and times). ### Language Names SilverStripe comes with a built-in list of common languages, listed by locale and region. They can be accessed via the `i18n.common_languages` and `i18n.common_locales` [config setting](/developer_guides/configuration). In order to add a value, add the following to your `config.yml`: :::yml i18n: common_locales: de_CGN: name: German (Cologne) native: Kölsch Similarly, to change an existing language label, you can overwrite one of these keys: :::yml i18n: common_locales: en_NZ: native: Niu Zillund ### i18n in URLs By default, URLs for pages in SilverStripe (the `SiteTree->URLSegment` property) are automatically reduced to the allowed allowed subset of ASCII characters. If characters outside this subset are added, they are either removed or (if possible) "transliterated". This describes the process of converting from one character set to another while keeping characters recognizeable. For example, vowels with french accents are replaced with their base characters, `pâté` becomes `pate`. It is advisable to set the `SS_Transliterator.use_iconv` setting to true via config for systems which have `iconv` extension enabled and configured. See [the php documentation on iconv](http://php.net/manual/en/book.iconv.php) for more information. In order to allow for so called "multibyte" characters outside of the ASCII subset, limit the character filtering in the underlying configuration setting, by setting `URLSegmentFilter.default_use_transliterator` to `false` in your YAML configuration. Please refer to [W3C: Introduction to IDN and IRI](http://www.w3.org/International/articles/idn-and-iri/) for more details. ### i18n in Form Fields Date and time related form fields are automatically localised ([api:DateField], [api:TimeField], [api:DatetimeField]). Since they use HTML5 `type=date` and `type=time` fields by default, these fields will present dates in a localised format chosen by the browser and operating system. Fields can be forced to use a certain locale and date/time format by calling `setHTML5(false)`, followed by `setLocale()` or `setDateFormat()`/`setTimeFormat()`. :::php $field = new DateField(); $field->setLocale('de_AT'); // set Austrian/German locale, defaulting format to dd.MM.y $field->setDateFormat('d.M.y'); // set a more specific date format (single digit day/month) ## Translating text Adapting a module to make it localizable is easy with SilverStripe. You just need to avoid hardcoding strings that are language-dependent and use a translator function call instead. :::php // without i18n echo "This is a string"; // with i18n echo _t("Namespace.Entity","This is a string"); All strings passed through the `_t()` function will be collected in a separate language table (see [Collecting text](#collecting-text)), which is the starting point for translations. ### The _t() function The `_t()` function is the main gateway to localized text, and takes four parameters, all but the first being optional. It can be used to translate strings in both PHP files and template files. The usage for each case is described below. * **$entity:** Unique identifier, composed by a namespace and an entity name, with a dot separating them. Both are arbitrary names, although by convention we use the name of the containing class or template. Use this identifier to reference the same translation elsewhere in your code. * **$default:** The original language string to be translated. This should be declared whenever used, and will get picked up the [text collector](#collecting-text). * **$string:** (optional) Natural language comment (particularly short phrases and individual words) are very context dependent. This parameter allows the developer to convey this information to the translator. * **$injection::** (optional) An array of injecting variables into the second parameter ## Pluralisation i18n also supports locale-respective pluralisation rules. Many languages have more than two plural forms, unlike English which has two only; One for the singular, and another for any other number. More information on what forms these plurals can take for various locales can be found on the [CLDR documentation](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) The ability to pluralise strings is provided through the `i18n::_t` method when supplied with a `{count}` argument and `|` pipe-delimiter provided with the default string. Plural forms can also be explicitly declared via the i18nEntityProvider interface in array-format with both a 'one' and 'other' key (as per the CLDR for the default `en` language). For instance, this is an example of how to correctly declare pluralisations for an object :::php class MyObject extends DataObject, implements i18nEntityProvider { public function provideI18nEntities() { return [ 'MyObject.SINGULAR_NAME' => 'object', 'MyObject.PLURAL_NAME' => 'objects', 'MyObject.PLURALS' => [ 'one' => 'An object', 'other' => '{count} objects', ], ]; } } In YML format this will be expressed as the below. This follows the [ruby i18n convention](guides.rubyonrails.org/i18n.html#pluralization) for plural forms. :::yaml en: MyObject: SINGULAR_NAME: 'object' PLURAL_NAME: 'objects' PLURALS: one: 'An object', other: '{count} objects' Note: i18nTextCollector support for pluralisation is not yet available. Please ensure that any required plurals are exposed via provideI18nEntities. #### Usage in PHP Files :::php // Simple string translation _t('LeftAndMain.FILESIMAGES','Files & Images'); // Using injection to add variables into the translated strings. _t('CMSMain.RESTORED', "Restored {value} successfully", array('value' => $itemRestored) ); // Plurals are invoked via a `|` pipe-delimeter with a {count} argument _t('MyObject.PLURALS', 'An object|{count} objects', [ 'count' => '$count ]); #### Usage in Template Files