-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Changes from 5 commits
8b6c584
dee7fb2
e2fd5fa
105a168
bfd78b3
629a008
c0f3b0a
69491ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
.. index:: | ||
single: Translation; Custom formats | ||
|
||
Custom Formats | ||
============== | ||
|
||
Sometimes, you need to deal with custom formats for translation files. The | ||
Translation component is flexible enough to support this, just creating a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] to support this. Just create a [...] |
||
loader (to load translations) and, optionally, a dumper (to dump translations). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and what about an extractor? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) |
||
|
||
Let's imagine you have a custom format where translation messages are defined | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We always avoid the first person perspective. So, I'd write something like "Image that you have a custom format [...]". |
||
using one line for each translation and parenthesis to wrap the key and the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be "parentheses", shouldn't it? |
||
message. A translation file would look like this: | ||
|
||
.. code-block:: text | ||
|
||
(welcome)(Bienvenido) | ||
(goodbye)(Adios) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Little type: adiós ;) |
||
(hello)(Hola) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since Symfony is french, I would prefer to have a french translation in here :) |
||
|
||
Custom Loader | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here I would prefer "Creating a Custom Loader" |
||
------------- | ||
|
||
To define a custom loader able to read this kind of files, you must create a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] loader that is able to read [...] |
||
new class that implements the | ||
:class:`Symfony\\Component\\Translation\\Loader\\LoaderInterface`. The | ||
:method:`Symfony\\Component\\Translation\\Loader\\LoaderInterface::load` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 catalogue that will be returned:: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. catalog |
||
|
||
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:: | ||
|
||
$translator = new Translator('es_ES'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should add a |
||
$translator->addLoader('my_format', new MyFormatLoader()); | ||
|
||
$translator->addResource('my_format', __DIR__.'/translations/messages.txt', 'es_ES'); | ||
|
||
echo $translator->trans('welcome'); | ||
|
||
It will print *"Bienvenido"*. | ||
|
||
Custom Dumper | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And following the same guidelines, this would be "Creating a Custom Dumper" |
||
------------- | ||
|
||
It is also possible to create a custom dumper for your format, useful when using | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] for your format which is useful [...] |
||
the extraction commands. To do so, a new class implementing the | ||
:class:`Symfony\\Component\\Translation\\Dumper\\DumperInterface` | ||
interface must be created. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "interface" is also part of the interface name. So, it should be removed here. |
||
To write the dump contents into a file, extending the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this new line will not be detected by Sphinx. You either have to add an empty line between the 2 sentences to create 2 paragraphs, or you can simply remove the line break. |
||
: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 | ||
{ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The blank line can be removed. |
||
public function format(MessageCatalogue $messages, $domain = 'messages') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be |
||
{ | ||
$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 :class:`Symfony\\Component\\Translation\\Dumper\\FileDumper` class to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need for this |
||
create the file. The dumper can be used like any other | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to break the line so early. |
||
built-in dumper. In this example, the translation messages defined in the YAML file | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the following example, [...] |
||
are dumped into a text file with the custom format:: | ||
|
||
use Symfony\Component\Translation\Loader\YamlFileLoader; | ||
|
||
include_once __DIR__. '/vendor/autoload.php'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove this line. We never include the autoloader explicitly in any example. |
||
|
||
$loader = new YamlFileLoader(); | ||
$catalogue = $loader->load(__DIR__ . '/translations/messages.es_ES.yml' , 'es_ES'); | ||
|
||
$dumper = new MyFormatDumper(); | ||
$dumper->dump($catalogue, array('path' => __DIR__.'/dumps')); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ Translation | |
|
||
introduction | ||
usage | ||
custom_formats |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,8 +62,9 @@ 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 and you can | ||
:doc:`create your own Loader too </components/translation/custom_formats>`. The | ||
default loaders are: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not mention the custom loaders here, but add a sentence after the list of default loaders instead. |
||
|
||
* :class:`Symfony\\Component\\Translation\\Loader\\ArrayLoader` - to load | ||
catalogs from PHP arrays. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer a title that tells more about the problem that's described, something like "Adding Custom Format Support to the Translator"