"Internationalization" (often abbreviated as i18n) refers to extracting strings and other fragments with regional characteristics from your program and The process of placing users in a layer that can be translated and transformed based on their locale (e.g. language, country). For text, this means stripping away each part of the text with a function that translates it (or the "information") into the language the user wants:
// 文本始终以英语输出echo 'Hello World'; // 文本将以用户指定语言或默认英语输出echo $translator->trans('Hello World');
The meaning of locale is simply the language and country of the user. It can be any string in the program and is used to manage translation and other format information (such as currency). It is recommended to use the ISO 639-1 language code, plus an underscore (_
), followed by a ISO 3166-1 alpha-2 country code (such as fr_FR
This locale refers to "French French" French/France).
In this chapter, you will learn how to use the translation component in the Symfony framework. You can read Translation Component to learn more. Overall, the translation process has the following steps:
Open and configure Symfony's translation service;
Strings are abstracted (such as "xxxx"), which is achieved by calling Translator to strip them; (Refer to Translation Basics)
For each Supported locales, Create translation resources/files, used to translate each string to be translated in the program;
for request (request) and optional Based on the user's entire session process, to determine, set and manage the user's locale information.
Configuration
The translation process is handled through the translator
service, which uses the user-specified locale to find and return translated information. Before using translator, enable it in the configuration file:
PHP:// app/config/config.php$container->loadFromExtension('framework', array('translator' => array('fallbacks' => array('en')),));
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:framework="http://symfony.com/schema/dic/symfony" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config>
<framework:translator>
<framework:fallback>en</framework:fallback>
</framework:translator>
</framework:config></container>
YAML:# app/config/config.ymlframework:translator: { fallbacks: [en] }
Regarding the fallbacks keyword and how Symfony handles it when it cannot find the translation language, please refer to Locales rollback during translation for details.
The locale information used in translation is stored in the request object. Generally set to the _locale
attribute in routing. Please refer to The Locale and the URL.
Translation Basics
translator
The service is responsible for completing the translation of text. To translate a block of text (called a "message", hereafter called "information"), use the trans() method. For example, you want to translate a simple message in the controller:
// ...use Symfony\Component\HttpFoundation\Response; public function indexAction(){$translated = $this->get('translator')->trans('Symfony is great'); return new Response($translated);}
After the above code is executed, Symfony will try to translate the "Symfony is great" message based on the user's locale
. In order for this process to work, you need to tell Symfony how to perform the translation through a "translation resource". Generally speaking, a translation source is a file that contains groups of translation information corresponding to a specified locale. It is like a "dictionary" for translation and can be created in a variety of formats, but it is recommended to use XLIFF (annotation: xml format with different suffixes):
PHP:// messages.fr.phpreturn array('Symfony is great' => 'J\'aime Symfony',);
YAML:# messages.fr.ymlSymfony is great: J'aime Symfony
XML:<!-- messages.fr.xlf --><?xml version="1.0"?><xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="symfony_is_great">
<source>Symfony is great</source>
<target>J'aime Symfony</target>
</trans-unit>
</body>
</file></xliff>
For information about the storage location of such files, refer to Translation source/file name and location
Now, if the user's locale is French (such as fr_FR
or fr_BE
), then the previous message will be translated as J'aime Symfony
. You can also complete the translation in templates.
Translation Process
In order to translate a message, Symfony performs the following concise process:
Determine the request first The locale
information of the current user stored in the object;
The translated information of a certain directory (a large group of messages) will be retrieved from ## The translation source determined by #locale (such as
fr_FR) is loaded. If the locale does not exist, the translation information determined by
fallback locale will also be loaded and merged into the directory. The final result is a "translation dictionary";
- If the information to be translated can be found from the directory, the translation results will be returned. Otherwise, the translator returns the original information.
When using the trans() method, Symfony looks for the exact string from the corresponding message directory and returns it (if it exists).
Information placeholder
¶
Sometimes, an item containing The information of the variable needs to be translated:
use Symfony\Component\HttpFoundation\Response; public function indexAction($name){$translated = $this->get('translator')->trans('Hello '.$name); return new Response($translated);}
However, for such a string, it is impossible to create a corresponding translation, because the translator is always trying to find "deterministic information", including the variable value itself (For example, "Hello Ryan" and "Hello Fabien" are two different messages in the translator's view).
For this case, please refer to
Message Placeholders/Message Placeholders in the component documentation. For how to handle the same situation in templates, refer to Twig Templates.
Plural processing
¶
Another complicated situation is that you have to face "plural situations" based on certain variables during translation:
1
2 | There is one apple.
There are 5 apples. |
To handle this, you should use the transChoice()
method, or use the transchoice
tag/regulator in the template, please refer here.
For more information, refer to the Plural processing chapter of the Translation component documentation.
Translation in templates
In most cases, translation occurs in templates. For Twig and PHP templates, Symfony provides native support.
Twig Template
##Symfony provides special Twig tags (trans and
transchoice) for " Static Text Block" information provides translation assistance.
{% trans %}Hello %name%{% endtrans %} {% transchoice count %}{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples{% endtranschoice %}
transchoice tag automatically gets the
%count% variable from the current context and passes it to the translator. This mechanism only takes effect when you use placeholders in the format
%var%.
When using the trans/transchoice tag for translation in a Twig template, the
%var% placeholder comment is required.
If you need to use the percent sign % in a string, escape it by writing it twice:
1 | {% trans %}Percent: %percent%%%{% endtrans %} |
You can also specify the message domain and pass in some additional variables: {% trans with {'%name%': 'Fabien'} from "app" %}Hello %name%{% endtrans %} {% trans with {'%name%': 'Fabien'} from "app" into "fr" %}Hello %name%{% endtrans %} {% transchoice count with {'%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 modifiers can be used to translate variable text and Complex expressions: {{ message|trans }} {{ message|transchoice(5) }} {{ message|trans({'%name%': 'Fabien'}, "app") }} {{ message|transchoice(5, {'%name%': 'Fabien'}, 'app') }}
Whether using labels or regulators during translation, the effect is the same, but there is a slight difference: the automatic output escaping function only applies to regulators efficient. In other words, if you need the translated information to be "not escaped", you must follow the translation regulator with a raw regulator:
{# 标签中被翻译的文本从不被转义#}{% trans %}<h3>foo</h3>{% endtrans %} {% set message = '<h3>foo</h3>' %} {# 变量调节器翻译的字符串和变量,默认将被转义 #}{{ message|trans|raw }}{{ '<h3>bar</h3>'|trans|raw }}
You can set a translation domain for the entire twig template through a single tag:
##1
| {% trans_default_domain "app" %}
|
Note that this will only affect the current template, not any "included" templates (in order to reduce side effects).
PHP Template
translator can also be used in PHP templates through the translator helper:
<?php echo $view['translator']->trans('Symfony is great') ?> <?php echo $view['translator']->transChoice('{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples',10,array('%count%' => 10)) ?>
Translation source/file naming and location
Symfony looks for information files (i.e. translations/translation information) in the following location:
The overwriting mechanism is performed based on key level: only overwritten keys need to be listed in the high-priority information file. When a key is not found in the message file, the translator will automatically roll back to a lower priority message file.
The file name of the information file is also very important. Each information file must be named according to the following naming path:
domain.locale.loader:
- domain
: This is an optional option for organizing message files into groups (such as admin, navigation or default messages). SeeUsing Message Domains;
- locale
: This is the locale of the translated message (such as en_GB, en, etc. );
- loader
: This is how Symfony loads and parses information files (that is, xlf, php
, yml
and other file suffixes).
Loader (loader) can be the name of any registered loader. Symfony provides many loaders by default, including:
- xlf
: loads XLIFF files;
- php
: Load PHP files;
- yml
: Load YAML files;
Which loader to use The choice is entirely yours, as you like. It is recommended to use xlf as the translated information file. For more options, refer to
Loading Message Catalogs.
You can also store translation information in the database, or any other medium, as long as you provide a custom class to implement the
LoaderInterface interface That’s it. Refer to the
translation.loader tag to learn more.
You can add a directory via the paths
option in the configuration file:
PHP:// app/config/config.php$container->loadFromExtension('framework', array('translator' => array('paths' => array('%kernel.root_dir%/../translations',),),));
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:framework="http://symfony.com/schema/dic/symfony" xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config>
<framework:translator>
<framework:path>%kernel.root_dir%/../translations</framework:path>
</framework:translator>
</framework:config></container>
YAML:# app/config/config.ymlframework:translator:paths:- '%kernel.root_dir%/../translations'
Every time you create a new translation resource (translation resource) or install a bundle containing a translation resource, be sure to clear the cache so that Symfony can discover the new translation source.
##1 | $ php app/console cache:clear |
Locale rollback during translation
Assume that a user’s locale information is fr_FR
, And the key you are translating is Symfony is great
. To find French messages, Symfony actually checks several locale translation sources:
First, Symfony checks a fr_FR
translation source (e.g. messages.fr_FR.xlf) Search for translation information;
If not found, Symfony continues to search for translation information in a fr
translation source (such as messages.fr.xlf);
If it is still not found, Symfony uses the fallbacks configuration parameter, which is set to en
by default (see FrameworkBundle configuration information).
Version 2.6 of Symfony introduced the ability to write missing translation information to the log.
When Symfony cannot find translation information for a given locale, it will add the missing translation information to the log file. See logging.
Translate database content
When translating database content, you need to use the Translatable Extension or ## in the Doctrine extension #TranslatableBehavior(PHP 5.4). Please refer to the corresponding documentation for more information.
Translate constraint messages
Refer to How to translate validation constraint messages to learn more.
Processing the user's Locale
The translation process depends on the user's locale. Read How to Manipulate User's Locale to learn how to handle this.
Debug translation
debug:translation command line statement introduced from Symfony 2.5.
Before Symfony 2.6, this command was translation:debug.
When you are working with large amounts of translated information in different languages, it can be difficult to keep track of which pieces of information are missing and which pieces of information are not being used. Read How to find missing or unused translations to learn how to find such translations.
Summary
Creating an internationalized application using Symfony's translation component will no longer be a "painful process" but comes down to the following simple steps:
Abstract the information to be translated from the program, and replace each piece of information with the trans()
or transChoice()
method (via Use Translator to learn more);
Translate the information to be translated into multiple locale languages by creating a translation message file. Symfony can find and process each file because the names of these files follow the specified naming convention;
Manage the user's locale, it can be stored in the request, but it can also be stored in the user's in session.