From d18e7583fec63165821f21c0c30ef7d790303144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 18 May 2014 16:06:37 +0200 Subject: [PATCH] [Translation] [Xliff] Support for --- .../Translation/Catalogue/DiffOperation.php | 6 ++ .../Translation/Catalogue/MergeOperation.php | 6 ++ .../Translation/Dumper/XliffFileDumper.php | 20 +++++++ .../Translation/Loader/XliffFileLoader.php | 56 +++++++++++++++---- .../Tests/Catalogue/DiffOperationTest.php | 22 ++++++++ .../Tests/Catalogue/MergeOperationTest.php | 23 ++++++++ .../Tests/Dumper/XliffFileDumperTest.php | 2 + .../Tests/Loader/XliffFileLoaderTest.php | 12 ++++ .../Translation/Tests/fixtures/encoding.xlf | 1 + .../Tests/fixtures/resources-clean.xlf | 3 + .../Translation/Tests/fixtures/withnote.xlf | 22 ++++++++ 11 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf diff --git a/src/Symfony/Component/Translation/Catalogue/DiffOperation.php b/src/Symfony/Component/Translation/Catalogue/DiffOperation.php index 1672d121da..5a153e207b 100644 --- a/src/Symfony/Component/Translation/Catalogue/DiffOperation.php +++ b/src/Symfony/Component/Translation/Catalogue/DiffOperation.php @@ -33,6 +33,9 @@ class DiffOperation extends AbstractOperation if ($this->target->has($id, $domain)) { $this->messages[$domain]['all'][$id] = $message; $this->result->add(array($id => $message), $domain); + if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) { + $this->result->setMetadata($id, $keyMetadata, $domain); + } } else { $this->messages[$domain]['obsolete'][$id] = $message; } @@ -43,6 +46,9 @@ class DiffOperation extends AbstractOperation $this->messages[$domain]['all'][$id] = $message; $this->messages[$domain]['new'][$id] = $message; $this->result->add(array($id => $message), $domain); + if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) { + $this->result->setMetadata($id, $keyMetadata, $domain); + } } } } diff --git a/src/Symfony/Component/Translation/Catalogue/MergeOperation.php b/src/Symfony/Component/Translation/Catalogue/MergeOperation.php index 0052363efe..a91124433d 100644 --- a/src/Symfony/Component/Translation/Catalogue/MergeOperation.php +++ b/src/Symfony/Component/Translation/Catalogue/MergeOperation.php @@ -32,6 +32,9 @@ class MergeOperation extends AbstractOperation foreach ($this->source->all($domain) as $id => $message) { $this->messages[$domain]['all'][$id] = $message; $this->result->add(array($id => $message), $domain); + if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) { + $this->result->setMetadata($id, $keyMetadata, $domain); + } } foreach ($this->target->all($domain) as $id => $message) { @@ -39,6 +42,9 @@ class MergeOperation extends AbstractOperation $this->messages[$domain]['all'][$id] = $message; $this->messages[$domain]['new'][$id] = $message; $this->result->add(array($id => $message), $domain); + if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) { + $this->result->setMetadata($id, $keyMetadata, $domain); + } } } } diff --git a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php index 96c0c8a387..bd9b01255e 100644 --- a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php @@ -50,6 +50,26 @@ class XliffFileDumper extends FileDumper $t = $translation->appendChild($dom->createElement('target')); $t->appendChild($dom->createTextNode($target)); + $metadata = $messages->getMetadata($source, $domain); + if (null !== $metadata && array_key_exists('notes', $metadata) && is_array($metadata['notes'])) { + foreach ($metadata['notes'] as $note) { + if (!isset($note['content'])) { + continue; + } + + $n = $translation->appendChild($dom->createElement('note')); + $n->appendChild($dom->createTextNode($note['content'])); + + if (isset($note['priority'])) { + $n->setAttribute('priority', $note['priority']); + } + + if (isset($note['from'])) { + $n->setAttribute('from', $note['from']); + } + } + } + $xliffBody->appendChild($translation); } diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index a86b02c2ee..18cd291d41 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -53,27 +53,61 @@ class XliffFileLoader implements LoaderInterface } $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; - $target = (string) $translation->target; - // If the xlf file has another encoding specified, try to convert it because // simple_xml will always return utf-8 encoded values - if ('UTF-8' !== $encoding && !empty($encoding)) { - if (function_exists('mb_convert_encoding')) { - $target = mb_convert_encoding($target, $encoding, 'UTF-8'); - } elseif (function_exists('iconv')) { - $target = iconv('UTF-8', $encoding, $target); - } else { - throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); - } - } + $target = $this->utf8ToCharset((string) $translation->target, $encoding); $catalogue->set((string) $source, $target, $domain); + + if (isset($translation->note)) { + $notes = array(); + foreach ($translation->note as $xmlNote) { + $noteAttributes = $xmlNote->attributes(); + $note = array('content' => $this->utf8ToCharset((string) $xmlNote, $encoding)); + if (isset($noteAttributes['priority'])) { + $note['priority'] = (int) $noteAttributes['priority']; + } + + if (isset($noteAttributes['from'])) { + $note['from'] = (string) $noteAttributes['from']; + } + + $notes[] = $note; + } + + $catalogue->setMetadata((string) $source, array('notes' => $notes), $domain); + } } $catalogue->addResource(new FileResource($resource)); return $catalogue; } + /** + * Convert a UTF8 string to the specified encoding + * + * @param string $content String to decode + * @param string $encoding Target encoding + * + * @return string + */ + private function utf8ToCharset($content, $encoding=null) + { + if ('UTF-8' !== $encoding && !empty($encoding)) { + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($content, $encoding, 'UTF-8'); + } + + if (function_exists('iconv')) { + return iconv('UTF-8', $encoding, $content); + } + + throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); + } + + return $content; + } + /** * Validates and parses the given file into a SimpleXMLElement * diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php index b70324285e..28808ded8a 100644 --- a/src/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php +++ b/src/Symfony/Component/Translation/Tests/Catalogue/DiffOperationTest.php @@ -53,6 +53,28 @@ class DiffOperationTest extends AbstractOperationTest ); } + public function testGetResultWithMetadata() + { + $leftCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))); + $leftCatalogue->setMetadata('a', 'foo', 'messages'); + $leftCatalogue->setMetadata('b', 'bar', 'messages'); + $rightCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'new_b', 'c' => 'new_c'))); + $rightCatalogue->setMetadata('b', 'baz', 'messages'); + $rightCatalogue->setMetadata('c', 'qux', 'messages'); + + $diffCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'old_b', 'c' => 'new_c'))); + $diffCatalogue->setMetadata('b', 'bar', 'messages'); + $diffCatalogue->setMetadata('c', 'qux', 'messages'); + + $this->assertEquals( + $diffCatalogue, + $this->createOperation( + $leftCatalogue, + $rightCatalogue + )->getResult() + ); + } + protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target) { return new DiffOperation($source, $target); diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php index 6f463b9a02..22b53fcc8f 100644 --- a/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php +++ b/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php @@ -53,6 +53,29 @@ class MergeOperationTest extends AbstractOperationTest ); } + public function testGetResultWithMetadata() + { + $leftCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))); + $leftCatalogue->setMetadata('a', 'foo', 'messages'); + $leftCatalogue->setMetadata('b', 'bar', 'messages'); + $rightCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'new_b', 'c' => 'new_c'))); + $rightCatalogue->setMetadata('b', 'baz', 'messages'); + $rightCatalogue->setMetadata('c', 'qux', 'messages'); + + $mergedCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'))); + $mergedCatalogue->setMetadata('a', 'foo', 'messages'); + $mergedCatalogue->setMetadata('b', 'bar', 'messages'); + $mergedCatalogue->setMetadata('c', 'qux', 'messages'); + + $this->assertEquals( + $mergedCatalogue, + $this->createOperation( + $leftCatalogue, + $rightCatalogue + )->getResult() + ); + } + protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target) { return new MergeOperation($source, $target); diff --git a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php index bef31358c5..daf0f7a37d 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php @@ -20,6 +20,8 @@ class XliffFileDumperTest extends \PHPUnit_Framework_TestCase { $catalogue = new MessageCatalogue('en'); $catalogue->add(array('foo' => 'bar', 'key' => '')); + $catalogue->setMetadata('foo', array('notes' => array(array('priority' => 1, 'from' => 'bar', 'content' => 'baz')))); + $catalogue->setMetadata('key', array('notes' => array(array('content' => 'baz'), array('content' => 'qux')))); $tempDir = sys_get_temp_dir(); $dumper = new XliffFileDumper(); diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index 49a6265dc2..02b80ec7ef 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -54,6 +54,7 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1')); $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); + $this->assertEquals(array('notes' => array(array('content' => utf8_decode('bäz')))), $catalogue->getMetadata('foo', 'domain1')); } /** @@ -111,4 +112,15 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $this->setExpectedException('Symfony\Component\Translation\Exception\InvalidResourceException', sprintf('Unable to load "%s":', $resource)); $loader->load($resource, 'en', 'domain1'); } + + public function testLoadNotes() + { + $loader = new XliffFileLoader(); + $catalogue = $loader->load(__DIR__.'/../fixtures/withnote.xlf', 'en', 'domain1'); + + $this->assertEquals(array('notes' => array(array('priority' => 1, 'content' => 'foo'))), $catalogue->getMetadata('foo', 'domain1')); + // message without target + $this->assertNull($catalogue->getMetadata('extra', 'domain1')); + $this->assertEquals(array('notes' => array(array('content' => 'baz'), array('priority' => 2, 'from' => 'bar', 'content' => 'qux'))), $catalogue->getMetadata('key', 'domain1')); + } } diff --git a/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf b/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf index 6be901bd75..0a88f92650 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf +++ b/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf @@ -5,6 +5,7 @@ foo bär + bäz bar diff --git a/src/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf b/src/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf index 464b079200..3c38d3d19a 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf +++ b/src/Symfony/Component/Translation/Tests/fixtures/resources-clean.xlf @@ -5,10 +5,13 @@ foo bar + baz key + baz + qux diff --git a/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf b/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf new file mode 100644 index 0000000000..b1d3f83a0c --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf @@ -0,0 +1,22 @@ + + + + + + foo + bar + foo + + + extra + bar + + + key + + baz + qux + + + +