Setting the '<html>' 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/).
### Date and time formats
Formats can be set globally in the i18n class. These settings are currently only picked up by the CMS, you'll need
to write your own logic for any frontend output.
:::php
i18n::set_date_format('dd.MM.YYYY');
i18n::set_time_format('HH:mm');
Most localization routines in SilverStripe use the [http://framework.zend.com/manual/en/zend.date.html](Zend_Date API).
This means all formats are defined in
[http://framework.zend.com/manual/en/zend.date.constants.html#zend.date.constants.selfdefinedformats](ISO date format),
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
### i18n in Form Fields
Date- and time related form fields support i18n ([api:DateField], [api:TimeField], [api:DatetimeField]).
:::php
i18n::set_locale('ca_AD');
$field = new DateField(); // will automatically set date format defaults for 'ca_AD'
$field->setLocale('de_DE'); // will not update the date formats
$field->setConfig('dateformat', 'dd.MM.YYYY'); // sets typical 'de_DE' date format
Form fields in the CMS are automatically set according to the profile settings for the logged-in user (`Member->DateFormat` and `Member->TimeFormat`).
## Adapting modules for i18n
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 entities"
below), which is the starting point for translations.
### The _t() function
Here is the function prototype of this translator function
:::php
function _t(string $entity [, string $string [, int $priority [, string $context]]]) {
**$entity:** The first parameter is the identifier, and is composed by a namespace and an entity name, with a dot separating them.
The main class name (i.e. the same one that the php name file) should usually be used as the namespace. This means that
if we are coding in the file LeftAndMain.php, the namespace should be 'LeftAndMain', and therefore the complete first
parameter would be 'LeftAndMain.ENTITY'. There is an exception to this rule. If you are using the same exactly string in two different files, for example in
A.php and B.php, and the string in B.php will always be the same string that in A.php, then you can 'declare' this
string in A.php with `_t('A.ENTITY','String that is used in A and B');`{php} and then in B.php simply write:
`_t('A.ENTITY');`{php} In this way if somewhere in the future you need to modify this string, you just need to edit it
in one file (A.php). Translators will also have to translate this string just once. Entity names are by convention written in uppercase. They have to be unique within their namespace, and its purpose is
to serve as an identificator to this string, together with the namespace. Having an unique identificator for each string
allows some features like change tracking. Therefore, a meaningful name is always welcomed, although not required. And
also, that's why you shouldn't change an existing entity name in the code, unless you have a good reason to do it.
**$string:** The second parameter is the string itself. It's not mandatory if you have set this same string in another place before
(using the same class and entity). So you could write `_t('ClassName.HELLO',"Hello")` and later `_t('ClassName.HELLO')`.
In fact, if you write the string in this second case, a warning will be issued when text-collecting to alert that you
are redeclaring an entity.
**$priority:** Priority parameter is an optional parameter and it can be used to set a translation priority. If a string is widely
used, it should have a high priority (PR_HIGH), in this way translators will be able to prioritise the translation of
this strings. If a string is extremely rarely shown, use PR_LOW. You can use PR_MEDIUM as well. Leaving this field blank
will be interpretated as a "normal" priority (some less than PR_MEDIUM). Using priorities allows translators to benefit from the 80/20 rule when translating, since typically there is a reduced
set of strings that are widely displayed, and a lot of more specific strings. Therefore, in a module with a considerable
amount of strings, where partial translations can be expected, priorities will help to have translated the most
displayed strings. If a string is in a class is inheritable, it's not recommended to establish a priority (we don't know about child
behavior a priori).
### Context
Last parameter is context, it's also optional. Sometimes short phrases or words can have several translations depending
upon where they are used, and Context serves as a way to tell translators more information about the string in these
cases where translating can be difficult, due to lack of context or ambiguity.
This context param can also be used with other situations where translation may need to know more than the original
string, for example with sprintf '%' params inside the string, since you can tell translators about the meaning of this
parameters.
:::php
//Example 4: Using context to hint information about a parameter
sprintf(
_t('CMSMain.RESTORED',
"Restored '%s' successfully",
PR_MEDIUM,
'Param %s is a title'
),
$title
)
### Usage
There're two types of files in a module where you can use this _t() function: code files (under code folder) and
template files (under templates)
* In code files, in order to ask for a translated string, we have to write a normal php call to this function.