Translations

The term "internationalization" (often abbreviated i18n) refers to the
process of abstracting strings and other locale-specific pieces out of your
application into a layer where they can be translated and converted based
on the user's locale (i.e. language and country). For text, this means
wrapping each with a function capable of translating the text (or "message")
into the language of the user:

1
2
3
4
5
6

// text will *always* print out in Englishecho'Hello World';// text can be translated into the end-user's language or// default to Englishecho$translator->trans('Hello World');

Note

The term locale refers roughly to the user's language and country. It
can be any string that your application uses to manage translations and
other format differences (e.g. currency format). The ISO 639-1language code, an underscore (_), then the ISO 3166-1 alpha-2country code (e.g. fr_FR for French/France) is recommended.

In this chapter, you'll learn how to use the Translation component in the
Symfony2 framework. You can read the
Translation component documentation
to learn even more. Overall, the process has several steps:

Translation of text is done through the translator service
(Translator). To translate a block
of text (called a message), use the
trans() method. Suppose,
for example, that you're translating a simple message from inside a controller:

When this code is executed, Symfony2 will attempt to translate the message
"Symfony2 is great" based on the locale of the user. For this to work,
you need to tell Symfony2 how to translate the message via a "translation
resource", which is usually a file that contains a collection of translations
for a given locale. This "dictionary" of translations can be created in several
different formats, XLIFF being the recommended format:

The locale of the current user, which is stored on the request is determined;

A catalog (e.g. big collection) of translated messages is loaded from translation
resources defined for the locale (e.g. fr_FR). Messages from the
fallback locale are also loaded and
added to the catalog if they don't already exist. The end result is a large
"dictionary" of translations.

If the message is located in the catalog, the translation is returned. If
not, the translator returns the original message.

When using the trans() method, Symfony2 looks for the exact string inside
the appropriate message catalog and returns it (if it exists).

Symfony2 provides specialized Twig tags (trans and transchoice) to
help with message translation of static blocks of text:

1
2
3
4
5

{%trans%}Hello %name%{%endtrans%}{%transchoicecount%} {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples{%endtranschoice%}

The transchoice tag automatically gets the %count% variable from
the current context and passes it to the translator. This mechanism only
works when you use a placeholder following the %var% pattern.

Caution

The %var% notation of placeholders is required when translating in
Twig templates using the tag.

Tip

If you need to use the percent character (%) in a string, escape it by
doubling it: {% trans %}Percent: %percent%%%{% endtrans %}

You can also specify the message domain and pass some additional variables:

1
2
3
4
5
6
7

{%transwith{'%name%':'Fabien'}from"app"%}Hello %name%{%endtrans%}{%transwith{'%name%':'Fabien'}from"app"into"fr"%}Hello %name%{%endtrans%}{%transchoicecountwith{'%name%':'Fabien'}from"app"%} {0} %name%, there are no apples|{1} %name%, there is one apple|]1,Inf] %name%, there are %count% apples{%endtranschoice%}

The trans and transchoice filters can be used to translate variable
texts and complex expressions:

Using the translation tags or filters have the same effect, but with
one subtle difference: automatic output escaping is only applied to
translations using a filter. In other words, if you need to be sure
that your translated message is not output escaped, you must apply
the raw filter after the translation filter:

1
2
3
4
5
6
7
8
9
10

{# text translated between tags is never escaped #}{%trans%} <h3>foo</h3>{%endtrans%}{%setmessage='<h3>foo</h3>'%}{# strings and variables translated via a filter are escaped by default #}{{message|trans|raw}}{{'<h3>bar</h3>'|trans|raw}}

Tip

You can set the translation domain for an entire Twig template with a single tag:

1

{%trans_default_domain"app"%}

Note that this only influences the current template, not any "included"
template (in order to avoid side effects).

New in version 2.1: The trans_default_domain tag is new in Symfony 2.1

The translator service is accessible in PHP templates through the
translator helper:

1
2
3
4
5
6
7

<?phpecho$view['translator']->trans('Symfony2 is great')?><?phpecho$view['translator']->transChoice('{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',10,array('%count%'=>10))?>

Symfony2 looks for message files (i.e. translations) in the following locations:

the app/Resources/translations directory;

the app/Resources/<bundle name>/translations directory;

the Resources/translations/ directory inside of any bundle.

The locations are listed here with the highest priority first. That is, you can
override the translation messages of a bundle in any of the top 2 directories.

The override mechanism works at a key level: only the overridden keys need
to be listed in a higher priority message file. When a key is not found
in a message file, the translator will automatically fall back to the lower
priority message files.

The filename of the translation files is also important: each message file
must be named according to the following path: domain.locale.loader:

domain: An optional way to organize messages into groups (e.g. admin,
navigation or the default messages) - see Using Message Domains;

locale: The locale that the translations are for (e.g. en_GB, en, etc);

Imagine that the user's locale is fr_FR and that you're translating the
key Symfony2 is great. To find the French translation, Symfony actually
checks translation resources for several different locales:

First, Symfony looks for the translation in a fr_FR translation resource
(e.g. messages.fr_FR.xfliff);

If it wasn't found, Symfony looks for the translation in a fr translation
resource (e.g. messages.fr.xliff);

If the translation still isn't found, Symfony uses the fallback configuration
parameter, which defaults to en (see Configuration).

Since you can store the locale of the user in the session, it may be tempting
to use the same URL to display a resource in many different languages based
on the user's locale. For example, http://www.example.com/contact could
show content in English for one user and French for another user. Unfortunately,
this violates a fundamental rule of the Web: that a particular URL returns
the same resource regardless of the user. To further muddy the problem, which
version of the content would be indexed by search engines?

A better policy is to include the locale in the URL. This is fully-supported
by the routing system using the special _locale parameter:

When using the special _locale parameter in a route, the matched locale
will automatically be set on the Request and can be retrieved via the
getLocale() method.
In other words, if a user
visits the URI /fr/contact, the locale fr will automatically be set
as the locale for the current request.

You can now use the locale to create routes to other translated pages
in your application.

New in version 2.1: The default_locale parameter was defined under the session key
originally, however, as of 2.1 this has been moved. This is because the
locale is now set on the request instead of the session.