Skip to content

Translation custom loaders #4166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/map.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@

* :doc:`/components/translation/introduction`
* :doc:`/components/translation/usage`
* :doc:`/components/translation/custom_formats`

* :doc:`/components/yaml/index`

Expand Down
114 changes: 114 additions & 0 deletions components/translation/custom_formats.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
.. index::
single: Translation; Adding Custom Format Support

Adding Custom Format Support
============================

Sometimes, you need to deal with custom formats for translation files. The
Translation component is flexible enough to support this. Just create a
loader (to load translations) and, optionally, a dumper (to dump translations).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and what about an extractor?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totally unrelated. The extractor does not care about the format of your translation files. It relies on the loader and dumper for it (it would be great to add a cookbook about adding extractors though)


Imagine that you have a custom format where translation messages are defined
using one line for each translation and parentheses to wrap the key and the
message. A translation file would look like this:

.. code-block:: text

(welcome)(accueil)
(goodbye)(au revoir)
(hello)(bonjour)

Creating a Custom Loader
------------------------

To define a custom loader that is able to read this kind of files, you must create a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... these kind of files ...

new class that implements the
:class:`Symfony\\Component\\Translation\\Loader\\LoaderInterface`. The
:method:`Symfony\\Component\\Translation\\Loader\\LoaderInterface::load`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think listing the methods of the interface is needed in this paragraph. Implementing an inteface involves implementing all its methods.

method will get a filename and parse it into an array. Then, it will
create the catalog that will be returned::

use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Loader\LoaderInterface;

class MyFormatLoader implements LoaderInterface
{
public function load($resource, $locale, $domain = 'messages')
{
$messages = array();
$lines = file($resource);

foreach ($lines as $line) {
if (preg_match('/\(([^\)]+)\)\(([^\)]+)\)/', $line, $matches)) {
$messages[$matches[1]] = $matches[2];
}
}

$catalogue = new MessageCatalogue($locale);
$catalogue->add($messages, $domain);

return $catalogue;
}

}

Once created, it can be used as any other loader::

use Symfony\Component\Translation\Translator;

$translator = new Translator('fr_FR');
$translator->addLoader('my_format', new MyFormatLoader());

$translator->addResource('my_format', __DIR__.'/translations/messages.txt', 'fr_FR');

echo $translator->trans('welcome');

It will print *"accueil"*.

Creating a Custom Dumper
------------------------

It is also possible to create a custom dumper for your format, which is
useful when using the extraction commands. To do so, a new class
implementing the
:class:`Symfony\\Component\\Translation\\Dumper\\DumperInterface`
must be created. To write the dump contents into a file, extending the
:class:`Symfony\\Component\\Translation\\Dumper\\FileDumper` class
will save a few lines::

use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Dumper\FileDumper;

class MyFormatDumper extends FileDumper
{
protected function format(MessageCatalogue $messages, $domain = 'messages')
{
$output = '';

foreach ($messages->all($domain) as $source => $target) {
$output .= sprintf("(%s)(%s)\n", $source, $target);
}

return $output;
}

protected function getExtension()
{
return 'txt';
}
}

The :method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::format`
method creates the output string, that will be used by the
:method:`Symfony\\Component\\Translation\\Dumper\\FileDumper::dump` method
of the FileDumper class to create the file. The dumper can be used like any other
built-in dumper. In the following example, the translation messages defined in the
YAML file are dumped into a text file with the custom format::

use Symfony\Component\Translation\Loader\YamlFileLoader;

$loader = new YamlFileLoader();
$catalogue = $loader->load(__DIR__ . '/translations/messages.fr_FR.yml' , 'fr_FR');

$dumper = new MyFormatDumper();
$dumper->dump($catalogue, array('path' => __DIR__.'/dumps'));
1 change: 1 addition & 0 deletions components/translation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Translation

introduction
usage
custom_formats
6 changes: 4 additions & 2 deletions components/translation/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ The Translation component uses Loader classes to load catalogs. You can load
multiple resources for the same locale, which will then be combined into one
catalog.

The component comes with some default Loaders and you can create your own
Loader too. The default loaders are:
The component comes with some default loaders:

* :class:`Symfony\\Component\\Translation\\Loader\\ArrayLoader` - to load
catalogs from PHP arrays.
Expand Down Expand Up @@ -95,6 +94,9 @@ Loader too. The default loaders are:

All file loaders require the :doc:`Config component </components/config/index>`.

You can also :doc:`create your own Loader </components/translation/custom_formats>`,
in case the format is not already supported by one of the default loaders.

At first, you should add one or more loaders to the ``Translator``::

// ...
Expand Down