[Translation] add options 'as_tree', 'inline' to YamlFileDumper to dump messages as tree instead of simple list.
Dump messages as tree based on '.' character as a delimeter in path. For example this rray('foo.bar' => 'value') will be converted to array('foo' => array('bar' => 'value')). Correctly process cases like this ['foo.bar' => 'test1', 'foo' => 'test2'].
This commit is contained in:
parent
791e583b40
commit
29ec5caf8a
@ -5,6 +5,7 @@ CHANGELOG
|
||||
-----
|
||||
|
||||
* deprecated Translator::getMessages(), use TranslatorBagInterface::getCatalogue() instead.
|
||||
* added options 'as_tree', 'inline' to YamlFileDumper
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
@ -82,10 +82,26 @@ abstract class FileDumper implements DumperInterface
|
||||
}
|
||||
}
|
||||
// save file
|
||||
file_put_contents($fullpath, $this->format($messages, $domain));
|
||||
file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a domain of a message catalogue to its string representation.
|
||||
*
|
||||
* Override this function in child class if $options is used for message formatting.
|
||||
*
|
||||
* @param MessageCatalogue $messages
|
||||
* @param string $domain
|
||||
* @param array $options
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
protected function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
{
|
||||
return $this->format($messages, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a domain of a message catalogue to its string representation.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Util\ArrayConverter;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
@ -24,13 +25,31 @@ class YamlFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
protected function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Yaml\Yaml')) {
|
||||
throw new \LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');
|
||||
}
|
||||
|
||||
return Yaml::dump($messages->all($domain));
|
||||
$data = $messages->all($domain);
|
||||
|
||||
if (isset($options['as_tree']) && $options['as_tree']) {
|
||||
$data = ArrayConverter::expandToTree($data);
|
||||
}
|
||||
|
||||
if (isset($options['inline']) && ($inline = (int) $options['inline']) > 0) {
|
||||
return Yaml::dump($data, $inline);
|
||||
}
|
||||
|
||||
return Yaml::dump($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
return $this->formatCatalogue($messages, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,16 +16,38 @@ use Symfony\Component\Translation\Dumper\YamlFileDumper;
|
||||
|
||||
class YamlFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
public function testTreeDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
$catalogue->add(
|
||||
array(
|
||||
'foo.bar1' => 'value1',
|
||||
'foo.bar2' => 'value2',
|
||||
));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new YamlFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir, 'as_tree' => true, 'inline' => 999));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/messages.yml'), file_get_contents($tempDir.'/messages.en.yml'));
|
||||
|
||||
unlink($tempDir.'/messages.en.yml');
|
||||
}
|
||||
|
||||
public function testLinearDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(
|
||||
array(
|
||||
'foo.bar1' => 'value1',
|
||||
'foo.bar2' => 'value2',
|
||||
));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new YamlFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.yml'), file_get_contents($tempDir.'/messages.en.yml'));
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/messages_linear.yml'), file_get_contents($tempDir.'/messages.en.yml'));
|
||||
|
||||
unlink($tempDir.'/messages.en.yml');
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Util;
|
||||
|
||||
use Symfony\Component\Translation\Util\ArrayConverter;
|
||||
|
||||
class ArrayConverterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider messsagesData
|
||||
*/
|
||||
public function testDump($input, $expectedOutput)
|
||||
{
|
||||
$this->assertEquals($expectedOutput, ArrayConverter::expandToTree($input));
|
||||
}
|
||||
|
||||
public function messsagesData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo1' => 'bar',
|
||||
'foo.bar' => 'value',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo1' => 'bar',
|
||||
'foo' => array('bar' => 'value'),
|
||||
),
|
||||
),
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo.bar' => 'value1',
|
||||
'foo.bar.test' => 'value2',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo' => array(
|
||||
'bar' => 'value1',
|
||||
'bar.test' => 'value2',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo.level2.level3.level4' => 'value1',
|
||||
'foo.level2' => 'value2',
|
||||
'foo.bar' => 'value3',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo' => array(
|
||||
'level2' => 'value2',
|
||||
'level2.level3.level4' => 'value1',
|
||||
'bar' => 'value3',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
3
src/Symfony/Component/Translation/Tests/fixtures/messages.yml
vendored
Normal file
3
src/Symfony/Component/Translation/Tests/fixtures/messages.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
foo:
|
||||
bar1: value1
|
||||
bar2: value2
|
2
src/Symfony/Component/Translation/Tests/fixtures/messages_linear.yml
vendored
Normal file
2
src/Symfony/Component/Translation/Tests/fixtures/messages_linear.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
foo.bar1: value1
|
||||
foo.bar2: value2
|
99
src/Symfony/Component/Translation/Util/ArrayConverter.php
Normal file
99
src/Symfony/Component/Translation/Util/ArrayConverter.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Util;
|
||||
|
||||
/**
|
||||
* ArrayConverter generates tree like structure from a message catalogue.
|
||||
* e.g. this
|
||||
* 'foo.bar1' => 'test1',
|
||||
* 'foo.bar2' => 'test2'
|
||||
* converts to follows:
|
||||
* foo:
|
||||
* bar1: test1
|
||||
* bar2: test2.
|
||||
*
|
||||
* @author Gennady Telegin <gtelegin@gmail.com>
|
||||
*/
|
||||
class ArrayConverter
|
||||
{
|
||||
/**
|
||||
* Converts linear messages array to tree-like array.
|
||||
* For example this rray('foo.bar' => 'value') will be converted to array('foo' => array('bar' => 'value')).
|
||||
*
|
||||
* @param array $messages Linear messages array
|
||||
*
|
||||
* @return array Tree-like messages array
|
||||
*/
|
||||
public static function expandToTree(array $messages)
|
||||
{
|
||||
$tree = array();
|
||||
|
||||
foreach ($messages as $id => $value) {
|
||||
$referenceToElement = &self::getElementByPath($tree, explode('.', $id));
|
||||
|
||||
$referenceToElement = $value;
|
||||
|
||||
unset($referenceToElement);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
private static function &getElementByPath(array &$tree, array $parts)
|
||||
{
|
||||
$elem = &$tree;
|
||||
$parentOfElem = null;
|
||||
|
||||
foreach ($parts as $i => $part) {
|
||||
if (isset($elem[$part]) && is_string($elem[$part])) {
|
||||
/* Process next case:
|
||||
* 'foo': 'test1',
|
||||
* 'foo.bar': 'test2'
|
||||
*
|
||||
* $tree['foo'] was string before we found array {bar: test2}.
|
||||
* Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2';
|
||||
*/
|
||||
$elem = &$elem[ implode('.', array_slice($parts, $i)) ];
|
||||
break;
|
||||
}
|
||||
$parentOfElem = &$elem;
|
||||
$elem = &$elem[$part];
|
||||
}
|
||||
|
||||
if (is_array($elem) && count($elem) > 0 && $parentOfElem) {
|
||||
/* Process next case:
|
||||
* 'foo.bar': 'test1'
|
||||
* 'foo': 'test2'
|
||||
*
|
||||
* $tree['foo'] was array = {bar: 'test1'} before we found string constant `foo`.
|
||||
* Cancel treating $tree['foo'] as array and cancel back it expansion,
|
||||
* e.g. make it $tree['foo.bar'] = 'test1' again.
|
||||
*/
|
||||
self::cancelExpand($parentOfElem, $part, $elem);
|
||||
}
|
||||
|
||||
return $elem;
|
||||
}
|
||||
|
||||
private static function cancelExpand(array &$tree, $prefix, array $node)
|
||||
{
|
||||
$prefix .= '.';
|
||||
|
||||
foreach ($node as $id => $value) {
|
||||
if (is_string($value)) {
|
||||
$tree[$prefix.$id] = $value;
|
||||
} else {
|
||||
self::cancelExpand($tree, $prefix.$id, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user