diff --git a/book/translation.rst b/book/translation.rst
index b99720f5169..aea1fc6e3d3 100644
--- a/book/translation.rst
+++ b/book/translation.rst
@@ -4,12 +4,12 @@
Translations
============
-The term "internationalization" (often abbreviated `i18n`_) refers to the process
-of abstracting strings and other locale-specific pieces out of your application
-and 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::
+The term "internationalization" (often abbreviated `i18n`_) refers to the
+process of abstracting strings and other locale-specific pieces out of your
+application and 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::
// text will *always* print out in English
echo 'Hello World';
@@ -21,31 +21,30 @@ the user::
.. 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
- `ISO639-1`_ *language* code, an underscore (``_``), then the `ISO3166 Alpha-2`_ *country*
- code (e.g. ``fr_FR`` for French/France) is recommended.
+ can be any string that your application uses to manage translations and
+ other format differences (e.g. currency format). The `ISO639-1`_
+ *language* code, an underscore (``_``), then the `ISO3166 Alpha-2`_
+ *country* code (e.g. ``fr_FR`` for French/France) is recommended.
-In this chapter, you'll learn how to prepare an application to support multiple
-locales and then how to create translations for multiple locales. Overall,
-the process has several common steps:
+In this chapter, you'll learn how to use the Translation component in the
+Symfony2 framework. Read the
+:doc:`components documentation ` to learn how to use
+the Translator. Overall, the process has several common steps:
-#. Enable and configure Symfony's ``Translation`` component;
+#. Enable and configure Symfony's Translation component;
-#. Abstract strings (i.e. "messages") by wrapping them in calls to the ``Translator``;
+#. Abstract strings (i.e. "messages") by wrapping them in calls to the
+ ``Translator`` (learn about this in ":doc:`/components/translation/usage`");
#. Create translation resources for each supported locale that translate
each message in the application;
#. Determine, set and manage the user's locale in the session.
-.. index::
- single: Translations; Configuration
-
Configuration
-------------
-Translations are handled by a ``Translator`` :term:`service` that uses the
+Translations are handled by a ``translator`` :term:`service` that uses the
user's locale to lookup and return translated messages. Before using it,
enable the ``Translator`` in your configuration:
@@ -74,218 +73,66 @@ enable the ``Translator`` in your configuration:
The ``fallback`` option defines the fallback locale when a translation does
not exist in the user's locale.
-.. tip::
-
- When a translation does not exist for a locale, the translator first tries
- to find the translation for the language (``fr`` if the locale is
- ``fr_FR`` for instance). If this also fails, it looks for a translation
- using the fallback locale.
-
The locale used in translations is the one stored in the user session.
-.. index::
- single: Translations; Basic translation
-
-Basic Translation
------------------
-
-Translation of text is done through the ``translator`` service
-(:class:`Symfony\\Component\\Translation\\Translator`). To translate a block
-of text (called a *message*), use the
-:method:`Symfony\\Component\\Translation\\Translator::trans` method. Suppose,
-for example, that you're translating a simple message from inside a controller::
-
- // ...
- use Symfony\Component\HttpFoundation\Response;
-
- public function indexAction()
- {
- $t = $this->get('translator')->trans('Symfony2 is great');
+Fallback and Default Locale
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
- return new Response($t);
- }
+If the locale hasn't been set, the ``fallback`` configuration parameter will
+be used by the ``Translator``. The parameter defaults to ``en`` (see
+`Configuration`_).
-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 a collection of message translations for a given locale.
-This "dictionary" of translations can be created in several different formats,
-XLIFF being the recommended format:
+Alternatively, you can guarantee that a locale is set on the user's session
+by defining a ``default_locale`` for the session service:
.. configuration-block::
- .. code-block:: xml
-
-
-
-
-
-
-
- Symfony2 is great
- J'aime Symfony2
-
-
-
-
-
- .. code-block:: php
-
- // messages.fr.php
- return array(
- 'Symfony2 is great' => 'J\'aime Symfony2',
- );
-
.. code-block:: yaml
- # messages.fr.yml
- Symfony2 is great: J'aime Symfony2
-
-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 Symfony2``.
-
-The Translation Process
-~~~~~~~~~~~~~~~~~~~~~~~
+ # app/config/config.yml
+ framework:
+ session: { default_locale: en }
-To actually translate the message, Symfony2 uses a simple process:
+ .. code-block:: xml
-* The ``locale`` of the current user, which is stored in the session, is determined;
+
+
+
+
-* A catalog 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. See `Message Catalogues`_
- for more details;
+ .. code-block:: php
-* If the message is located in the catalog, the translation is returned. If
- not, the translator returns the original message.
+ // app/config/config.php
+ $container->loadFromExtension('framework', array(
+ 'session' => array('default_locale' => 'en'),
+ ));
-When using the ``trans()`` method, Symfony2 looks for the exact string inside
-the appropriate message catalog and returns it (if it exists).
+Using the Translation inside Controllers
+----------------------------------------
-.. index::
- single: Translations; Message placeholders
+When you want to use translation inside controllers, you need to get the
+``translator`` service and use
+:method:`Symfony\\Component\\Translation\\Translator::trans` or
+:method:`Symfony\\Component\\Translation\\Translator::transChoice`::
-Message Placeholders
-~~~~~~~~~~~~~~~~~~~~
-
-Sometimes, a message containing a variable needs to be translated::
+ // src/Acme/DemoBundle/Controller/DemoController.php
+ namespace Amce\DemoBundle\Controller;
// ...
- use Symfony\Component\HttpFoundation\Response;
-
- public function indexAction($name)
+ class DemoController extends Controller
{
- $t = $this->get('translator')->trans('Hello '.$name);
-
- return new Response($t);
- }
-
-However, creating a translation for this string is impossible since the translator
-will try to look up the exact message, including the variable portions
-(e.g. "Hello Ryan" or "Hello Fabien"). Instead of writing a translation
-for every possible iteration of the ``$name`` variable, you can replace the
-variable with a "placeholder"::
-
- // ...
- use Symfony\Component\HttpFoundation\Response;
+ public function indexAction()
+ {
+ $translator = $this->get('translator');
- public function indexAction($name)
- {
- $t = $this->get('translator')->trans(
- 'Hello %name%',
- array('%name%' => $name)
- );
+ $translated = $translator->trans('Symfony2 is great!');
- return new Response($t);
+ return new Response($translated);
+ }
}
-Symfony2 will now look for a translation of the raw message (``Hello %name%``)
-and *then* replace the placeholders with their values. Creating a translation
-is done just as before:
-
-.. configuration-block::
-
- .. code-block:: xml
-
-
-
-
-
-
-
- Hello %name%
- Bonjour %name%
-
-
-
-
-
- .. code-block:: php
-
- // messages.fr.php
- return array(
- 'Hello %name%' => 'Bonjour %name%',
- );
-
- .. code-block:: yaml
-
- # messages.fr.yml
- 'Hello %name%': Bonjour %name%
-
-.. note::
-
- The placeholders can take on any form as the full message is reconstructed
- using the PHP `strtr function`_. However, the ``%var%`` notation is
- required when translating in Twig templates, and is overall a sensible
- convention to follow.
-
-As you've seen, creating a translation is a two-step process:
-
-#. Abstract the message that needs to be translated by processing it through
- the ``Translator``.
-
-#. Create a translation for the message in each locale that you choose to
- support.
-
-The second step is done by creating message catalogues that define the translations
-for any number of different locales.
-
-.. index::
- single: Translations; Message catalogues
-
-Message Catalogues
-------------------
-
-When a message is translated, Symfony2 compiles a message catalogue for the
-user's locale and looks in it for a translation of the message. A message
-catalogue is like a dictionary of translations for a specific locale. For
-example, the catalogue for the ``fr_FR`` locale might contain the following
-translation:
-
-.. code-block:: text
-
- Symfony2 is Great => J'aime Symfony2
-
-It's the responsibility of the developer (or translator) of an internationalized
-application to create these translations. Translations are stored on the
-filesystem and discovered by Symfony, thanks to some conventions.
-
-.. tip::
-
- Each time you create a *new* translation resource (or install a bundle
- that includes a translation resource), be sure to clear your cache so
- that Symfony can discover the new translation resource:
-
- .. code-block:: bash
-
- $ php app/console cache:clear
-
-.. index::
- single: Translations; Translation resource locations
-
Translation Locations and Naming Conventions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------------
Symfony2 looks for message files (i.e. translations) in two locations:
@@ -300,7 +147,7 @@ to determine details about the translations. Each message file must be named
according to the following pattern: ``domain.locale.loader``:
* **domain**: An optional way to organize messages into groups (e.g. ``admin``,
- ``navigation`` or the default ``messages``) - see `Using Message Domains`_;
+ ``navigation`` or the default ``messages``) - see ":ref:`using-message-domains`";
* **locale**: The locale that the translations are for (e.g. ``en_GB``, ``en``, etc);
@@ -311,8 +158,8 @@ The loader can be the name of any registered loader. By default, Symfony
provides the following loaders:
* ``xliff``: XLIFF file;
-* ``php``: PHP file;
-* ``yml``: YAML file.
+* ``php``: PHP file;
+* ``yml``: YAML file.
The choice of which loader to use is entirely up to you and is a matter of
taste.
@@ -323,167 +170,15 @@ taste.
providing a custom class implementing the
:class:`Symfony\\Component\\Translation\\Loader\\LoaderInterface` interface.
-.. index::
- single: Translations; Creating translation resources
-
-Creating Translations
-~~~~~~~~~~~~~~~~~~~~~
-
-The act of creating translation files is an important part of "localization"
-(often abbreviated `L10n`_). Translation files consist of a series of
-id-translation pairs for the given domain and locale. The source is the identifier
-for the individual translation, and can be the message in the main locale (e.g.
-"Symfony is great") of your application or a unique identifier (e.g.
-"symfony2.great" - see the sidebar below):
-
-.. configuration-block::
-
- .. code-block:: xml
-
-
-
-
-
-
-
- Symfony2 is great
- J'aime Symfony2
-
-
- symfony2.great
- J'aime Symfony2
-
-
-
-
-
- .. code-block:: php
-
- // src/Acme/DemoBundle/Resources/translations/messages.fr.php
- return array(
- 'Symfony2 is great' => 'J\'aime Symfony2',
- 'symfony2.great' => 'J\'aime Symfony2',
- );
-
- .. code-block:: yaml
-
- # src/Acme/DemoBundle/Resources/translations/messages.fr.yml
- Symfony2 is great: J'aime Symfony2
- symfony2.great: J'aime Symfony2
-
-Symfony2 will discover these files and use them when translating either
-"Symfony2 is great" or "symfony2.great" into a French language locale (e.g.
-``fr_FR`` or ``fr_BE``).
-
-.. sidebar:: Using Real or Keyword Messages
-
- This example illustrates the two different philosophies when creating
- messages to be translated::
-
- $t = $translator->trans('Symfony2 is great');
-
- $t = $translator->trans('symfony2.great');
-
- In the first method, messages are written in the language of the default
- locale (English in this case). That message is then used as the "id"
- when creating translations.
-
- In the second method, messages are actually "keywords" that convey the
- idea of the message. The keyword message is then used as the "id" for
- any translations. In this case, translations must be made for the default
- locale (i.e. to translate ``symfony2.great`` to ``Symfony2 is great``).
-
- The second method is handy because the message key won't need to be changed
- in every translation file if you decide that the message should actually
- read "Symfony2 is really great" in the default locale.
-
- The choice of which method to use is entirely up to you, but the "keyword"
- format is often recommended.
-
- Additionally, the ``php`` and ``yaml`` file formats support nested ids to
- avoid repeating yourself if you use keywords instead of real text for your
- ids:
-
- .. configuration-block::
-
- .. code-block:: yaml
+.. caution::
- symfony2:
- is:
- great: Symfony2 is great
- amazing: Symfony2 is amazing
- has:
- bundles: Symfony2 has bundles
- user:
- login: Login
-
- .. code-block:: php
-
- return array(
- 'symfony2' => array(
- 'is' => array(
- 'great' => 'Symfony2 is great',
- 'amazing' => 'Symfony2 is amazing',
- ),
- 'has' => array(
- 'bundles' => 'Symfony2 has bundles',
- ),
- ),
- 'user' => array(
- 'login' => 'Login',
- ),
- );
-
- The multiple levels are flattened into single id/translation pairs by
- adding a dot (.) between every level, therefore the above examples are
- equivalent to the following:
-
- .. configuration-block::
-
- .. code-block:: yaml
-
- symfony2.is.great: Symfony2 is great
- symfony2.is.amazing: Symfony2 is amazing
- symfony2.has.bundles: Symfony2 has bundles
- user.login: Login
-
- .. code-block:: php
-
- return array(
- 'symfony2.is.great' => 'Symfony2 is great',
- 'symfony2.is.amazing' => 'Symfony2 is amazing',
- 'symfony2.has.bundles' => 'Symfony2 has bundles',
- 'user.login' => 'Login',
- );
-
-.. index::
- single: Translations; Message domains
-
-Using Message Domains
----------------------
-
-As you've seen, message files are organized into the different locales that
-they translate. The message files can also be organized further into "domains".
-When creating message files, the domain is the first portion of the filename.
-The default domain is ``messages``. For example, suppose that, for organization,
-translations were split into three different domains: ``messages``, ``admin``
-and ``navigation``. The French translation would have the following message
-files:
-
-* ``messages.fr.xliff``
-* ``admin.fr.xliff``
-* ``navigation.fr.xliff``
-
-When translating strings that are not in the default domain (``messages``),
-you must specify the domain as the third argument of ``trans()``::
-
- $this->get('translator')->trans('Symfony2 is great', array(), 'admin');
+ Each time you create a *new* translation resource (or install a bundle
+ that includes a translation resource), be sure to clear your cache so
+ that Symfony can discover the new translation resource:
-Symfony2 will now look for the message in the ``admin`` domain of the user's
-locale.
+ .. code-block:: bash
-.. index::
- single: Translations; User's locale
+ $ php app/console cache:clear
Handling the User's Locale
--------------------------
@@ -495,41 +190,6 @@ via the ``session`` service::
$this->get('session')->setLocale('en_US');
-.. index::
- single: Translations; Fallback and default locale
-
-Fallback and Default Locale
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If the locale hasn't been set explicitly in the session, the ``fallback_locale``
-configuration parameter will be used by the ``Translator``. The parameter
-defaults to ``en`` (see `Configuration`_).
-
-Alternatively, you can guarantee that a locale is set on the user's session
-by defining a ``default_locale`` for the session service:
-
-.. configuration-block::
-
- .. code-block:: yaml
-
- # app/config/config.yml
- framework:
- session: { default_locale: en }
-
- .. code-block:: xml
-
-
-
-
-
-
- .. code-block:: php
-
- // app/config/config.php
- $container->loadFromExtension('framework', array(
- 'session' => array('default_locale' => 'en'),
- ));
-
.. _book-translation-locale-url:
The Locale and the URL
@@ -587,125 +247,6 @@ as the locale for the user's session.
You can now use the user's locale to create routes to other translated pages
in your application.
-.. index::
- single: Translations; Pluralization
-
-Pluralization
--------------
-
-Message pluralization is a tough topic as the rules can be quite complex. For
-instance, here is the mathematic representation of the Russian pluralization
-rules::
-
- (($number % 10 == 1) && ($number % 100 != 11))
- ? 0
- : ((($number % 10 >= 2)
- && ($number % 10 <= 4)
- && (($number % 100 < 10)
- || ($number % 100 >= 20)))
- ? 1
- : 2
- );
-
-As you can see, in Russian, you can have three different plural forms, each
-given an index of 0, 1 or 2. For each form, the plural is different, and
-so the translation is also different.
-
-When a translation has different forms due to pluralization, you can provide
-all the forms as a string separated by a pipe (``|``)::
-
- 'There is one apple|There are %count% apples'
-
-To translate pluralized messages, use the
-:method:`Symfony\\Component\\Translation\\Translator::transChoice` method::
-
- $t = $this->get('translator')->transChoice(
- 'There is one apple|There are %count% apples',
- 10,
- array('%count%' => 10)
- );
-
-The second argument (``10`` in this example), is the *number* of objects being
-described and is used to determine which translation to use and also to populate
-the ``%count%`` placeholder.
-
-Based on the given number, the translator chooses the right plural form.
-In English, most words have a singular form when there is exactly one object
-and a plural form for all other numbers (0, 2, 3...). So, if ``count`` is
-``1``, the translator will use the first string (``There is one apple``)
-as the translation. Otherwise it will use ``There are %count% apples``.
-
-Here is the French translation::
-
- 'Il y a %count% pomme|Il y a %count% pommes'
-
-Even if the string looks similar (it is made of two sub-strings separated by a
-pipe), the French rules are different: the first form (no plural) is used when
-``count`` is ``0`` or ``1``. So, the translator will automatically use the
-first string (``Il y a %count% pomme``) when ``count`` is ``0`` or ``1``.
-
-Each locale has its own set of rules, with some having as many as six different
-plural forms with complex rules behind which numbers map to which plural form.
-The rules are quite simple for English and French, but for Russian, you'd
-may want a hint to know which rule matches which string. To help translators,
-you can optionally "tag" each string::
-
- 'one: There is one apple|some: There are %count% apples'
-
- 'none_or_one: Il y a %count% pomme|some: Il y a %count% pommes'
-
-The tags are really only hints for translators and don't affect the logic
-used to determine which plural form to use. The tags can be any descriptive
-string that ends with a colon (``:``). The tags also do not need to be the
-same in the original message as in the translated one.
-
-.. tip::
-
- As tags are optional, the translator doesn't use them (the translator will
- only get a string based on its position in the string).
-
-Explicit Interval Pluralization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The easiest way to pluralize a message is to let Symfony2 use internal logic
-to choose which string to use based on a given number. Sometimes, you'll
-need more control or want a different translation for specific cases (for
-``0``, or when the count is negative, for example). For such cases, you can
-use explicit math intervals::
-
- '{0} There are no apples|{1} There is one apple|]1,19] There are %count% apples|[20,Inf] There are many apples'
-
-The intervals follow the `ISO 31-11`_ notation. The above string specifies
-four different intervals: exactly ``0``, exactly ``1``, ``2-19``, and ``20``
-and higher.
-
-You can also mix explicit math rules and standard rules. In this case, if
-the count is not matched by a specific interval, the standard rules take
-effect after removing the explicit rules::
-
- '{0} There are no apples|[20,Inf] There are many apples|There is one apple|a_few: There are %count% apples'
-
-For example, for ``1`` apple, the standard rule ``There is one apple`` will
-be used. For ``2-19`` apples, the second standard rule ``There are %count%
-apples`` will be selected.
-
-An :class:`Symfony\\Component\\Translation\\Interval` can represent a finite set
-of numbers::
-
- {1,2,3,4}
-
-Or numbers between two other numbers::
-
- [1, +Inf[
- ]-1,2[
-
-The left delimiter can be ``[`` (inclusive) or ``]`` (exclusive). The right
-delimiter can be ``[`` (exclusive) or ``]`` (inclusive). Beside numbers, you
-can use ``-Inf`` and ``+Inf`` for the infinite.
-
-.. index::
- single: Translations; In templates
-
Translations in Templates
-------------------------
@@ -732,6 +273,11 @@ 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
@@ -799,35 +345,6 @@ The translator service is accessible in PHP templates through the
array('%count%' => 10)
) ?>
-Forcing the Translator Locale
------------------------------
-
-When translating a message, Symfony2 uses the locale from the user's session
-or the ``fallback`` locale if necessary. You can also manually specify the
-locale to use for translation::
-
- $this->get('translator')->trans(
- 'Symfony2 is great',
- array(),
- 'messages',
- 'fr_FR'
- );
-
- $this->get('translator')->transChoice(
- '{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
- 10,
- array('%count%' => 10),
- 'messages',
- 'fr_FR'
- );
-
-Translating Database Content
-----------------------------
-
-The translation of database content should be handled by Doctrine through
-the `Translatable Extension`_. For more information, see the documentation
-for that library.
-
.. _book-translation-constraint-messages:
Translating Constraint Messages
@@ -909,7 +426,9 @@ empty, add the following:
}
}
-Create a translation file under the ``validators`` catalog for the constraint messages, typically in the ``Resources/translations/`` directory of the bundle. See `Message Catalogues`_ for more details.
+Create a translation file under the ``validators`` catalog for the constraint
+messages, typically in the ``Resources/translations/`` directory of the
+bundle.
.. configuration-block::
@@ -940,6 +459,13 @@ Create a translation file under the ``validators`` catalog for the constraint me
# validators.en.yml
author.name.not_blank: Please enter an author name.
+Translating Database Content
+----------------------------
+
+The translation of database content should be handled by Doctrine through
+the `Translatable Extension`_. For more information, see the documentation
+for that library.
+
Summary
-------
@@ -949,7 +475,8 @@ steps:
* Abstract messages in your application by wrapping each in either the
:method:`Symfony\\Component\\Translation\\Translator::trans` or
- :method:`Symfony\\Component\\Translation\\Translator::transChoice` methods;
+ :method:`Symfony\\Component\\Translation\\Translator::transChoice` methods
+ (learn about this in ":doc:`/components/translation/usage`");
* Translate each message into multiple locales by creating translation message
files. Symfony2 discovers and processes each file because its name follows
@@ -958,9 +485,6 @@ steps:
* Manage the user's locale, which is stored in the session.
.. _`i18n`: http://en.wikipedia.org/wiki/Internationalization_and_localization
-.. _`L10n`: http://en.wikipedia.org/wiki/Internationalization_and_localization
-.. _`strtr function`: http://www.php.net/manual/en/function.strtr.php
-.. _`ISO 31-11`: http://en.wikipedia.org/wiki/Interval_(mathematics)#Notations_for_intervals
-.. _`Translatable Extension`: https://github.com/l3pp4rd/DoctrineExtensions
.. _`ISO3166 Alpha-2`: http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes
.. _`ISO639-1`: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+.. _`Translatable Extension`: https://github.com/l3pp4rd/DoctrineExtensions
diff --git a/components/index.rst b/components/index.rst
index 14e73dddf1a..d3437cb5db3 100644
--- a/components/index.rst
+++ b/components/index.rst
@@ -21,6 +21,7 @@ The Components
security/index
serializer
templating
+ translation
yaml/index
.. include:: /components/map.rst.inc
diff --git a/components/map.rst.inc b/components/map.rst.inc
index e8427932fbe..1375612b63f 100644
--- a/components/map.rst.inc
+++ b/components/map.rst.inc
@@ -84,6 +84,11 @@
* :doc:`/components/templating`
+* :doc:`/components/translation/index`
+
+ * :doc:`/components/translation/introduction`
+ * :doc:`/components/translation/usage`
+
* :doc:`/components/yaml/index`
* :doc:`/components/yaml/introduction`
diff --git a/components/translation/index.rst b/components/translation/index.rst
new file mode 100644
index 00000000000..3f87cbc1425
--- /dev/null
+++ b/components/translation/index.rst
@@ -0,0 +1,8 @@
+Translation
+===========
+
+.. toctree::
+ :maxdepth: 2
+
+ introduction
+ usage
diff --git a/components/translation/introduction.rst b/components/translation/introduction.rst
new file mode 100644
index 00000000000..f4469cd475b
--- /dev/null
+++ b/components/translation/introduction.rst
@@ -0,0 +1,187 @@
+.. index::
+ single: Translation
+ single: Components; Translation
+
+The Translation Component
+=========================
+
+ The Translation component provides tools to internationalize your
+ application.
+
+Installation
+------------
+
+You can install the component in 2 different ways:
+
+* Use the official Git repository (https://github.com/symfony/Translation);
+* :doc:`Install it via Composer` (``symfony/translation`` on `Packagist`_).
+
+Constructing the Translator
+---------------------------
+
+The main access point of the Translation Component is
+:class:`Symfony\\Component\\Translation\\Translator`. Before you can use it,
+you need to configure it and load the messages to translate (called *message
+catalogues*).
+
+Configuration
+~~~~~~~~~~~~~
+
+The constructor of the ``Translator`` class needs two arguments: The locale
+and the :class:`Symfony\\Component\\Translation\\MessageSelector` to use when
+using pluralization (more about that later)::
+
+ use Symfony\Component\Translation\Translator;
+ use Symfony\Component\Translation\MessageSelector;
+
+ $translator = new Translator('fr_FR', new MessageSelector());
+
+.. note::
+
+ The locale set here is the default locale to use. You can override this
+ locale when translating strings.
+
+.. 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 `ISO639-1`_
+ *language* code, an underscore (``_``), then the `ISO3166 Alpha-2`_
+ *country* code (e.g. ``fr_FR`` for French/France) is recommended.
+
+Loading Message Catalogues
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The messages are stored in message catalogues inside the ``Translator``
+class. A message catalogue is like a dictionary of translations for a specific
+locale.
+
+The Translation component uses Loader classes to load catalogues. You can load
+multiple resources for the same locale, it will be combined into one
+catalogue.
+
+The component comes with some default Loaders and you can create your own
+Loader too. The default loaders are:
+
+* :class:`Symfony\\Component\\Translation\\Loader\\ArrayLoader` - to load
+ catalogues from PHP arrays.
+* :class:`Symfony\\Component\\Translation\\Loader\\CsvFileLoader` - to load
+ catalogues from CSV files.
+* :class:`Symfony\\Component\\Translation\\Loader\\PhpFileLoader` - to load
+ catalogues from PHP files.
+* :class:`Symfony\\Component\\Translation\\Loader\\XliffFileLoader` - to load
+ catalogues from Xliff files.
+* :class:`Symfony\\Component\\Translation\\Loader\\YamlFileLoader` - to load
+ catalogues from Yaml files (requires the :doc:`Yaml component`).
+
+All loaders, except the ``ArrayLoader``, requires the
+:doc:`Config component`.
+
+At first, you should add one or more loaders to the ``Translator``::
+
+ // ...
+ $translator->addLoader('array', new ArrayLoader());
+
+The first argument is the name to which you can refer the loader in the
+translator and the second argument is an instance of the loader itself. After
+this, you can add your resources using the correct loader.
+
+Loading Messages with the ``ArrayLoader``
+.........................................
+
+Loading messages can be done by calling
+:method:`Symfony\\Component\\Translation\\Translator::addResource`. The first
+argument is the loader name (this was the first argument of the ``addLoader``
+method), the second is the resource and the third argument is the locale::
+
+ // ...
+ $translator->addResource('array', array(
+ 'Hello World!' => 'Bonjour',
+ ), 'fr_FR');
+
+Loading Messages with the File Loaders
+......................................
+
+If you use one of the file loaders, you also use the ``addResource`` method.
+The only difference is that you put the file name as the second argument,
+instead of an array::
+
+ // ...
+ $translator->addLoader('yaml', new YamlFileLoader());
+ $translator->addResource('yaml', 'path/to/messages.fr.yml', 'fr_FR');
+
+The Translation Process
+-----------------------
+
+To actually translate the message, the Translator uses a simple process:
+
+* A catalog of translated messages is loaded from translation resources defined
+ for the ``locale`` (e.g. ``fr_FR``). Messages from the
+ :ref:`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.
+
+You start this process by calling
+:method:`Symfony\\Component\\Translation\\Translator::trans` or
+:method:`Symfony\\Component\\Translation\\Translator::transChoice`. Then, the
+Translator looks for the exact string inside the appropriate message catalog
+and returns it (if it exists).
+
+.. tip::
+
+ When a translation does not exist for a locale, the translator first tries
+ to find the translation for the language (e.g. ``fr`` if the locale is
+ ``fr_FR``). If this also fails, it looks for a translation using the
+ fallback locale.
+
+Fallback Locale
+~~~~~~~~~~~~~~~
+
+If the message is not located in the catalogue of the specific locale, the
+translator will look into the catalogue of the fallback locale. You can set
+this fallback locale by calling
+:method:`Symfony\\Component\\Translation\\Translator::setFallbackLocale`::
+
+ // ...
+ $translator->setFallbackLocale('en_EN');
+
+.. _using-message-domains:
+
+Using Message Domains
+---------------------
+
+As you've seen, message files are organized into the different locales that
+they translate. The message files can also be organized further into "domains".
+
+The domain is specified in the fourth argument of the ``addResource()``
+method. The default domain is ``messages``. For example, suppose that, for
+organization, translations were split into three different domains:
+``messages``, ``admin`` and ``navigation``. The French translation would be
+loaded like this::
+
+ // ...
+ $translator->addLoader('xliff', new XliffLoader());
+
+ $translator->addResource('xliff', 'messages.fr.xliff', 'fr_FR');
+ $translator->addResource('xliff', 'admin.fr.xliff', 'fr_FR', 'admin');
+ $translator->addResource('xliff', 'navigation.fr.xliff', 'fr_FR', 'navigation');
+
+When translating strings that are not in the default domain (``messages``),
+you must specify the domain as the third argument of ``trans()``::
+
+ $translator->trans('Symfony2 is great', array(), 'admin');
+
+Symfony2 will now look for the message in the ``admin`` domain of the
+specified locale.
+
+Usage
+-----
+
+Read how to use the Translation component in ":doc:`/components/translation/usage`".
+
+.. _Packagist: https://packagist.org/packages/symfony/translation
+.. _`ISO3166 Alpha-2`: http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes
+.. _`ISO639-1`: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
diff --git a/components/translation/usage.rst b/components/translation/usage.rst
new file mode 100644
index 00000000000..f5ff77a2c98
--- /dev/null
+++ b/components/translation/usage.rst
@@ -0,0 +1,370 @@
+.. index::
+ single: Translation; Usage
+
+Using the Translator
+====================
+
+Imagine you want to translate the string *"Symfony2 is great"* into French::
+
+ use Symfony\Component\Translation\Translator;
+ use Symfony\Component\Translation\MessageSelector;
+ use Symfony\Component\Translation\Loader\ArrayLoader;
+
+ $translator = new Translator('fr_FR', new MessageSelector());
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', array(
+ 'Symfony2 is great!' => 'J'aime Symfony2!',
+ ), 'fr_FR');
+
+ echo $translator->trans('Symfony2 is great!');
+
+In this example, the message *"Symfony2 is great!"* will be translated into
+the locale set in the constructor (``fr_FR``) if the message exists in one of
+the message catalogues.
+
+Message Placeholders
+--------------------
+
+Sometimes, a message containing a variable needs to be translated::
+
+ // ...
+ $translated = $translator->trans('Hello '.$name);
+
+ echo $translated;
+
+However, creating a translation for this string is impossible since the translator
+will try to look up the exact message, including the variable portions
+(e.g. *"Hello Ryan"* or *"Hello Fabien"*). Instead of writing a translation
+for every possible iteration of the ``$name`` variable, you can replace the
+variable with a "placeholder"::
+
+ // ...
+ $translated = $translator->trans(
+ 'Hello %name%',
+ array('%name%' => $name)
+ );
+
+ echo $translated;
+
+Symfony2 will now look for a translation of the raw message (``Hello %name%``)
+and *then* replace the placeholders with their values. Creating a translation
+is done just as before:
+
+.. configuration-block::
+
+ .. code-block:: xml
+
+
+
+
+
+
+ Hello %name%
+ Bonjour %name%
+
+
+
+
+
+ .. code-block:: php
+
+ return array(
+ 'Hello %name%' => 'Bonjour %name%',
+ );
+
+ .. code-block:: yaml
+
+ 'Hello %name%': Bonjour %name%
+
+.. note::
+
+ The placeholders can take on any form as the full message is reconstructed
+ using the PHP :phpfunction:`strtr function`. But the ``%...%`` form
+ is recommend, to avoid problems when using Twig.
+
+As you've seen, creating a translation is a two-step process:
+
+#. Abstract the message that needs to be translated by processing it through
+ the ``Translator``.
+
+#. Create a translation for the message in each locale that you choose to
+ support.
+
+The second step is done by creating message catalogues that define the translations
+for any number of different locales.
+
+Creating Translations
+=====================
+
+The act of creating translation files is an important part of "localization"
+(often abbreviated `L10n`_). Translation files consist of a series of
+id-translation pairs for the given domain and locale. The source is the identifier
+for the individual translation, and can be the message in the main locale (e.g.
+*"Symfony is great"*) of your application or a unique identifier (e.g.
+``symfony2.great`` - see the sidebar below).
+
+Translation files can be created in several different formats, XLIFF being the
+recommended format. These files are parsed by one of the loader classes.
+
+.. configuration-block::
+
+ .. code-block:: xml
+
+
+
+
+
+
+ Symfony2 is great
+ J'aime Symfony2
+
+
+ symfony2.great
+ J'aime Symfony2
+
+
+
+
+
+ .. code-block:: php
+
+ return array(
+ 'Symfony2 is great' => 'J\'aime Symfony2',
+ 'symfony2.great' => 'J\'aime Symfony2',
+ );
+
+ .. code-block:: yaml
+
+ Symfony2 is great: J'aime Symfony2
+ symfony2.great: J'aime Symfony2
+
+.. sidebar:: Using Real or Keyword Messages
+
+ This example illustrates the two different philosophies when creating
+ messages to be translated::
+
+ $translator->trans('Symfony2 is great');
+
+ $translator->trans('symfony2.great');
+
+ In the first method, messages are written in the language of the default
+ locale (English in this case). That message is then used as the "id"
+ when creating translations.
+
+ In the second method, messages are actually "keywords" that convey the
+ idea of the message. The keyword message is then used as the "id" for
+ any translations. In this case, translations must be made for the default
+ locale (i.e. to translate ``symfony2.great`` to ``Symfony2 is great``).
+
+ The second method is handy because the message key won't need to be changed
+ in every translation file if you decide that the message should actually
+ read "Symfony2 is really great" in the default locale.
+
+ The choice of which method to use is entirely up to you, but the "keyword"
+ format is often recommended.
+
+ Additionally, the ``php`` and ``yaml`` file formats support nested ids to
+ avoid repeating yourself if you use keywords instead of real text for your
+ ids:
+
+ .. configuration-block::
+
+ .. code-block:: yaml
+
+ symfony2:
+ is:
+ great: Symfony2 is great
+ amazing: Symfony2 is amazing
+ has:
+ bundles: Symfony2 has bundles
+ user:
+ login: Login
+
+ .. code-block:: php
+
+ array(
+ 'symfony2' => array(
+ 'is' => array(
+ 'great' => 'Symfony2 is great',
+ 'amazing' => 'Symfony2 is amazing',
+ ),
+ 'has' => array(
+ 'bundles' => 'Symfony2 has bundles',
+ ),
+ ),
+ 'user' => array(
+ 'login' => 'Login',
+ ),
+ );
+
+ The multiple levels are flattened into single id/translation pairs by
+ adding a dot (``.``) between every level, therefore the above examples are
+ equivalent to the following:
+
+ .. configuration-block::
+
+ .. code-block:: yaml
+
+ symfony2.is.great: Symfony2 is great
+ symfony2.is.amazing: Symfony2 is amazing
+ symfony2.has.bundles: Symfony2 has bundles
+ user.login: Login
+
+ .. code-block:: php
+
+ return array(
+ 'symfony2.is.great' => 'Symfony2 is great',
+ 'symfony2.is.amazing' => 'Symfony2 is amazing',
+ 'symfony2.has.bundles' => 'Symfony2 has bundles',
+ 'user.login' => 'Login',
+ );
+
+Pluralization
+-------------
+
+Message pluralization is a tough topic as the rules can be quite complex. For
+instance, here is the mathematic representation of the Russian pluralization
+rules::
+
+ (($number % 10 == 1) && ($number % 100 != 11))
+ ? 0
+ : ((($number % 10 >= 2)
+ && ($number % 10 <= 4)
+ && (($number % 100 < 10)
+ || ($number % 100 >= 20)))
+ ? 1
+ : 2
+ );
+
+As you can see, in Russian, you can have three different plural forms, each
+given an index of 0, 1 or 2. For each form, the plural is different, and
+so the translation is also different.
+
+When a translation has different forms due to pluralization, you can provide
+all the forms as a string separated by a pipe (``|``)::
+
+ 'There is one apple|There are %count% apples'
+
+To translate pluralized messages, use the
+:method:`Symfony\\Component\\Translation\\Translator::transChoice` method::
+
+ $translator->transChoice(
+ 'There is one apple|There are %count% apples',
+ 10,
+ array('%count%' => 10)
+ );
+
+The second argument (``10`` in this example), is the *number* of objects being
+described and is used to determine which translation to use and also to populate
+the ``%count%`` placeholder.
+
+Based on the given number, the translator chooses the right plural form.
+In English, most words have a singular form when there is exactly one object
+and a plural form for all other numbers (0, 2, 3...). So, if ``count`` is
+``1``, the translator will use the first string (``There is one apple``)
+as the translation. Otherwise it will use ``There are %count% apples``.
+
+Here is the French translation:
+
+.. code-block:: text
+
+ 'Il y a %count% pomme|Il y a %count% pommes'
+
+Even if the string looks similar (it is made of two sub-strings separated by a
+pipe), the French rules are different: the first form (no plural) is used when
+``count`` is ``0`` or ``1``. So, the translator will automatically use the
+first string (``Il y a %count% pomme``) when ``count`` is ``0`` or ``1``.
+
+Each locale has its own set of rules, with some having as many as six different
+plural forms with complex rules behind which numbers map to which plural form.
+The rules are quite simple for English and French, but for Russian, you'd
+may want a hint to know which rule matches which string. To help translators,
+you can optionally "tag" each string:
+
+.. code-block:: text
+
+ 'one: There is one apple|some: There are %count% apples'
+
+ 'none_or_one: Il y a %count% pomme|some: Il y a %count% pommes'
+
+The tags are really only hints for translators and don't affect the logic
+used to determine which plural form to use. The tags can be any descriptive
+string that ends with a colon (``:``). The tags also do not need to be the
+same in the original message as in the translated one.
+
+.. tip::
+
+ As tags are optional, the translator doesn't use them (the translator will
+ only get a string based on its position in the string).
+
+Explicit Interval Pluralization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The easiest way to pluralize a message is to let the Translator use internal
+logic to choose which string to use based on a given number. Sometimes, you'll
+need more control or want a different translation for specific cases (for
+``0``, or when the count is negative, for example). For such cases, you can
+use explicit math intervals:
+
+.. code-block:: text
+
+ '{0} There are no apples|{1} There is one apple|]1,19] There are %count% apples|[20,Inf] There are many apples'
+
+The intervals follow the `ISO 31-11`_ notation. The above string specifies
+four different intervals: exactly ``0``, exactly ``1``, ``2-19``, and ``20``
+and higher.
+
+You can also mix explicit math rules and standard rules. In this case, if
+the count is not matched by a specific interval, the standard rules take
+effect after removing the explicit rules:
+
+.. code-block:: text
+
+ '{0} There are no apples|[20,Inf] There are many apples|There is one apple|a_few: There are %count% apples'
+
+For example, for ``1`` apple, the standard rule ``There is one apple`` will
+be used. For ``2-19`` apples, the second standard rule ``There are %count%
+apples`` will be selected.
+
+An :class:`Symfony\\Component\\Translation\\Interval` can represent a finite set
+of numbers:
+
+.. code-block:: text
+
+ {1,2,3,4}
+
+Or numbers between two other numbers:
+
+.. code-block:: text
+
+ [1, +Inf[
+ ]-1,2[
+
+The left delimiter can be ``[`` (inclusive) or ``]`` (exclusive). The right
+delimiter can be ``[`` (exclusive) or ``]`` (inclusive). Beside numbers, you
+can use ``-Inf`` and ``+Inf`` for the infinite.
+
+Forcing the Translator Locale
+-----------------------------
+
+When translating a message, the Translator uses the specified locale or the
+``fallback`` locale if necessary. You can also manually specify the locale to
+use for translation::
+
+ $translator->trans(
+ 'Symfony2 is great',
+ array(),
+ 'messages',
+ 'fr_FR'
+ );
+
+ $translator->transChoice(
+ '{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
+ 10,
+ array('%count%' => 10),
+ 'messages',
+ 'fr_FR'
+ );
+
+.. _`L10n`: http://en.wikipedia.org/wiki/Internationalization_and_localization
+.. _`ISO 31-11`: http://en.wikipedia.org/wiki/Interval_(mathematics)#Notations_for_intervals