Translations

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

  1. // text will *always* print out in English
  2. echo 'Hello World';
  3.  
  4. // text can be translated into the end-user's language or
  5. // default to English
  6. echo $translator->trans('Hello World');

Note

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

In this article, you'll learn how to use the Translation component in theSymfony Framework. You can read theTranslation component documentationto learn even more. Overall, the process has several steps:

Installation

First, run this command to install the translator before using it:

  1. $ composer require symfony/translation

Configuration

The previous command creates an initial config file where you can define thedefault locale of the app and the fallback localesthat will be used if Symfony can't find some translation:

  • YAML
  1. # config/packages/translation.yaml
  2. framework:
  3. default_locale: 'en'
  4. translator:
  5. fallbacks: ['en']
  6. # ...
  • XML
  1. <!-- config/packages/translation.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd
  8. http://symfony.com/schema/dic/symfony
  9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
  10.  
  11. <framework:config default-locale="en">
  12. <framework:translator>
  13. <framework:fallback>en</framework:fallback>
  14. <!-- ... -->
  15. </framework:translator>
  16. </framework:config>
  17. </container>
  • PHP
  1. // config/packages/translation.php
  2. $container->loadFromExtension('framework', [
  3. 'default_locale' => 'en',
  4. 'translator' => ['fallbacks' => ['en']],
  5. // ...
  6. ]);

The locale used in translations is the one stored on the request. This istypically set via a _locale attribute on your routes (see The Locale and the URL).

Basic Translation

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

  1. // ...
  2. use Symfony\Contracts\Translation\TranslatorInterface;
  3.  
  4. public function index(TranslatorInterface $translator)
  5. {
  6. $translated = $translator->trans('Symfony is great');
  7.  
  8. // ...
  9. }

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

  • XML
  1. <!-- translations/messages.fr.xlf -->
  2. <?xml version="1.0"?>
  3. <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  4. <file source-language="en" datatype="plaintext" original="file.ext">
  5. <body>
  6. <trans-unit id="symfony_is_great">
  7. <source>Symfony is great</source>
  8. <target>J'aime Symfony</target>
  9. </trans-unit>
  10. </body>
  11. </file>
  12. </xliff>
  • YAML
  1. # translations/messages.fr.yaml
  2. Symfony is great: J'aime Symfony
  • PHP
  1. // translations/messages.fr.php
  2. return [
  3. 'Symfony is great' => "J'aime Symfony",
  4. ];

For information on where these files should be located, seeTranslation Resource/File Names and Locations.

Now, if the language of the user's locale is French (e.g. fr_FR or fr_BE),the message will be translated into J'aime Symfony. You can also translatethe message inside your templates.

The Translation Process

To actually translate the message, Symfony uses the following process whenusing the trans() method:

  • 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 translationresources defined for the locale (e.g. fr_FR). Messages from thefallback locale are also loaded andadded to the catalog if they don't already exist. The end result is a large"dictionary" of translations. This catalog is cached in production tominimize performance impact.
  • If the message is located in the catalog, the translation is returned. Ifnot, the translator returns the original message.

Message Format

Sometimes, a message containing a variable needs to be translated:

  1. // ...
  2. $translated = $translator->trans('Hello '.$name);

However, creating a translation for this string is impossible since thetranslator will try to look up the message including the variable portions(e.g. "Hello Ryan" or "Hello Fabien").

Another complication is when you have translations that may or may not beplural, based on some variable:

  1. There is one apple.
  2. There are 5 apples.

To manage these situations, Symfony follows the ICU MessageFormat syntax byusing PHP's MessageFormatter class. Read more about this inHow to Translate Messages using the ICU MessageFormat.

New in version 4.2: Support for ICU MessageFormat was introduced in Symfony 4.2. Prior to this,pluralization was managed by thetransChoice() method.

Translations in Templates

Most of the time, translation occurs in templates. Symfony provides nativesupport for both Twig and PHP templates:

  1. <h1>{% trans %}Symfony is great!{% endtrans %}</h1>

Read Using Translation in Templates for more information about the Twig tags andfilters for translation.

Extracting Translation Contents and Updating Catalogs Automatically

The most time-consuming tasks when translating an application is to extract allthe template contents to be translated and to keep all the translation files insync. Symfony includes a command called translation:update that helps youwith these tasks:

  1. # shows all the messages that should be translated for the French language
  2. $ php bin/console translation:update --dump-messages fr
  3.  
  4. # updates the French translation files with the missing strings for that locale
  5. $ php bin/console translation:update --force fr
  6.  
  7. # check out the command help to see its options (prefix, output format, domain, etc.)
  8. $ php bin/console translation:update --help

The translation:update command looks for missing translations in:

  • Templates stored in the templates/ directory (or any other directorydefined in the twig.default_path andtwig.paths config options);
  • Any PHP file/class that injects or autowiresthe translator service and makes calls to the trans() function.

New in version 4.3: The extraction of missing translation strings from PHP files was introducedin Symfony 4.3.

Translation Resource/File Names and Locations

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

  • the translations/ directory (at the root of the project);
  • the src/Resources/<bundle name>/translations/ directory;
  • the Resources/translations/ directory inside of any bundle.

Deprecated since version 4.2: Using the src/Resources/<bundle name>/translations/ directory to storetranslations was deprecated in Symfony 4.2. Use instead the directorydefined in the default_path option (which is translations/ by default).

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

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

The filename of the translation files is also important: each message filemust 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);
  • loader: How Symfony should load and parse the file (e.g. xlf,php, yaml, etc).The loader can be the name of any registered loader. By default, Symfonyprovides many loaders, including:

  • xlf: XLIFF file;

  • php: PHP file;
  • yaml: YAML file.The choice of which loader to use is entirely up to you and is a matter oftaste. The recommended option is to use xlf for translations.For more options, see Loading Message Catalogs.

Note

You can add other directories with the pathsoption in the configuration:

  • YAML
  1. # config/packages/translation.yaml
  2. framework:
  3. translator:
  4. paths:
  5. - '%kernel.project_dir%/custom/path/to/translations'
  • XML
  1. <!-- config/packages/translation.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:framework="http://symfony.com/schema/dic/symfony"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd
  8. http://symfony.com/schema/dic/symfony
  9. https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
  10. >
  11.  
  12. <framework:config>
  13. <framework:translator>
  14. <framework:path>%kernel.project_dir%/custom/path/to/translations</framework:path>
  15. </framework:translator>
  16. </framework:config>
  17. </container>
  • PHP
  1. // config/packages/translation.php
  2. $container->loadFromExtension('framework', [
  3. 'translator' => [
  4. 'paths' => [
  5. '%kernel.project_dir%/custom/path/to/translations',
  6. ],
  7. ],
  8. ]);

Note

You can also store translations in a database, or any other storage byproviding a custom class implementing theLoaderInterface interface.See the translation.loader tag for more information.

New in version 4.3: Starting from Symfony 4.3, when you create a new translation file (orinstall a bundle that includes translation files), you don't have to clearthe cache with the command php bin/console cache:clear as you had to doin previous Symfony versions.

Handling the User's Locale

Translating happens based on the user's locale. Read How to Work with the User's Localeto learn more about how to handle it.

Fallback Translation Locales

Imagine that the user's locale is fr_FR and that you're translating thekey Symfony is great. To find the French translation, Symfony actuallychecks translation resources for several locales:

  • First, Symfony looks for the translation in a fr_FR translation resource(e.g. messages.fr_FR.xlf);
  • If it wasn't found, Symfony looks for the translation in a fr translationresource (e.g. messages.fr.xlf);
  • If the translation still isn't found, Symfony uses the fallbacks configurationparameter, which defaults to en (see Configuration).

Note

When Symfony can't find a translation in the given locale, it willadd the missing translation to the log file. For details,see logging.

Translating Database Content

The translation of database content should be handled by Doctrine throughthe Translatable Extension or the Translatable Behavior (PHP 5.4+).For more information, see the documentation for these libraries.

Debugging Translations

When you work with many translation messages in different languages, it canbe hard to keep track which translations are missing and which are not usedanymore. Read How to Find Missing or Unused Translation Messages to find out how to identify thesemessages.

Summary

With the Symfony Translation component, creating an internationalized applicationno longer needs to be a painful process and boils down to these steps:

  • Abstract messages in your application by wrapping each in thetrans() method;
  • Translate each message into multiple locales by creating translation messagefiles. Symfony discovers and processes each file because its name followsa specific convention;
  • Manage the user's locale, which is stored on the request, but can alsobe set on the user's session.

Learn more