Skip to content

Commit

Permalink
Using xliff version 2.0 as default (#12)
Browse files Browse the repository at this point in the history
* Using xliff version 2.0 as default

* Applied changes from StyleCI

* Removed PHP7 code

* Removed PHP 7 code

* Fixed SF2.7

* Applied changes from StyleCI
  • Loading branch information
Nyholm committed Aug 19, 2017
1 parent 17b09c5 commit 47c6f09
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 15 deletions.
205 changes: 197 additions & 8 deletions src/Dumper/XliffDumper.php
Expand Up @@ -11,29 +11,218 @@

namespace Translation\SymfonyStorage\Dumper;

use Symfony\Component\Translation\Dumper\XliffFileDumper;
use Symfony\Component\Translation\Dumper\FileDumper;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Exception\InvalidArgumentException;

/**
* XliffFileDumper generates xliff files from a message catalogue.
* Mostly borrowed from Symfony.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
* @author Michel Salib <michelsalib@hotmail.com>
*/
final class XliffDumper extends XliffFileDumper
final class XliffDumper extends FileDumper
{
/**
* Alias for formatCatalogue to provide a BC bridge.
* {@inheritdoc}
*/
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
{
$xliffVersion = '1.2';
if (array_key_exists('xliff_version', $options)) {
$xliffVersion = $options['xliff_version'];
}

if (array_key_exists('default_locale', $options)) {
$defaultLocale = $options['default_locale'];
} else {
$defaultLocale = \Locale::getDefault();
}

if ('1.2' === $xliffVersion) {
return $this->dumpXliff1($defaultLocale, $messages, $domain, $options);
}
if ('2.0' === $xliffVersion) {
return $this->dumpXliff2($defaultLocale, $messages, $domain, $options);
}

throw new InvalidArgumentException(
sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)
);
}

/**
* Symfony 2.7 support.
*
* @param MessageCatalogue $messages
* @param string $domain
* @param array $options
*
* @return string
*/
public function getFormattedCatalogue(MessageCatalogue $messages, $domain, array $options = [])
protected function format(MessageCatalogue $messages, $domain)
{
return $this->dumpXliff2(\Locale::getDefault(), $messages, $domain);
}

/**
* {@inheritdoc}
*/
protected function getExtension()
{
return 'xlf';
}

private function dumpXliff1($defaultLocale, MessageCatalogue $messages, $domain, array $options = [])
{
if (method_exists($this, 'formatCatalogue')) {
return parent::formatCatalogue($messages, $domain, $options);
$toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];
if (array_key_exists('tool_info', $options)) {
$toolInfo = array_merge($toolInfo, $options['tool_info']);
}

return $this->format($messages, $domain);
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->formatOutput = true;

$xliff = $dom->appendChild($dom->createElement('xliff'));
$xliff->setAttribute('version', '1.2');
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');

$xliffFile = $xliff->appendChild($dom->createElement('file'));
$xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale));
$xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));
$xliffFile->setAttribute('datatype', 'plaintext');
$xliffFile->setAttribute('original', 'file.ext');

$xliffHead = $xliffFile->appendChild($dom->createElement('header'));
$xliffTool = $xliffHead->appendChild($dom->createElement('tool'));
foreach ($toolInfo as $id => $value) {
$xliffTool->setAttribute($id, $value);
}

$xliffBody = $xliffFile->appendChild($dom->createElement('body'));
foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('trans-unit');

$translation->setAttribute(
'id',
strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')
);
$translation->setAttribute('resname', $source);

$s = $translation->appendChild($dom->createElement('source'));
$s->appendChild($dom->createTextNode($source));

// Does the target contain characters requiring a CDATA section?
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode(
$target
);

$targetElement = $dom->createElement('target');
$metadata = $messages->getMetadata($source, $domain);
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
foreach ($metadata['target-attributes'] as $name => $value) {
$targetElement->setAttribute($name, $value);
}
}
$t = $translation->appendChild($targetElement);
$t->appendChild($text);

if ($this->hasMetadataArrayInfo('notes', $metadata)) {
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);
}

return $dom->saveXML();
}

private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, array $options = [])
{
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->formatOutput = true;

$xliff = $dom->appendChild($dom->createElement('xliff'));
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0');
$xliff->setAttribute('version', '2.0');
$xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale));
$xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));

$xliffFile = $xliff->appendChild($dom->createElement('file'));
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());

foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('unit');
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
$metadata = $messages->getMetadata($source, $domain);

// Add notes section
if ($this->hasMetadataArrayInfo('notes', $metadata)) {
$notesElement = $dom->createElement('notes');
foreach ($metadata['notes'] as $note) {
$n = $dom->createElement('note');
$n->appendChild($dom->createTextNode(isset($note['content']) ? $note['content'] : ''));
unset($note['content']);

foreach ($note as $name => $value) {
$n->setAttribute($name, $value);
}
$notesElement->appendChild($n);
}
$translation->appendChild($notesElement);
}

$segment = $translation->appendChild($dom->createElement('segment'));

$s = $segment->appendChild($dom->createElement('source'));
$s->appendChild($dom->createTextNode($source));

// Does the target contain characters requiring a CDATA section?
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode(
$target
);

$targetElement = $dom->createElement('target');
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
foreach ($metadata['target-attributes'] as $name => $value) {
$targetElement->setAttribute($name, $value);
}
}

$t = $segment->appendChild($targetElement);
$t->appendChild($text);

$xliffFile->appendChild($translation);
}

return $dom->saveXML();
}

/**
* @param string $key
* @param array|null $metadata
*
* @return bool
*/
private function hasMetadataArrayInfo($key, $metadata = null)
{
return null !== $metadata &&
array_key_exists($key, $metadata) &&
($metadata[$key] instanceof \Traversable || is_array($metadata[$key]));
}
}
5 changes: 5 additions & 0 deletions src/FileStorage.php
Expand Up @@ -67,6 +67,11 @@ public function __construct(TranslationWriter $writer, $loader, array $dir, arra
throw new \LogicException('Third parameter of FileStorage cannot be empty');
}

if (!array_key_exists('xliff_version', $options)) {
// Set default value for xliff version.
$options['xliff_version'] = '2.0';
}

$this->writer = $writer;
$this->loader = $loader;
$this->dir = $dir;
Expand Down
7 changes: 6 additions & 1 deletion src/XliffConverter.php
Expand Up @@ -51,6 +51,11 @@ public static function catalogueToContent(MessageCatalogue $catalogue, $domain,
{
$dumper = new XliffDumper();

return $dumper->getFormattedCatalogue($catalogue, $domain, $options);
if (!array_key_exists('xliff_version', $options)) {
// Set default value for xliff version.
$options['xliff_version'] = '2.0';
}

return $dumper->formatCatalogue($catalogue, $domain, $options);
}
}
40 changes: 40 additions & 0 deletions tests/Unit/Dumper/XliffDumperTest.php
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Translation\SymfonyStorage\Tests\Unit\Dumper;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\MessageCatalogue;
use Translation\SymfonyStorage\Dumper\XliffDumper;

class XliffDumperTest extends TestCase
{
public function testDumpXliff2Meta()
{
$catalogue = new MessageCatalogue('en');
$catalogue->set('key0', 'trans0');
$catalogue->setMetadata('key0', ['notes' => [
['content' => 'yes', 'category' => 'approved'],
['content' => 'new', 'category' => 'state'],
]]);

$catalogue->set('key1', 'trans1');
$catalogue->setMetadata('key1', ['notes' => [
['content' => 'cnt', 'priority' => '2'],
]]);

$dumper = new XliffDumper();
$output = $dumper->formatCatalogue($catalogue, 'messages', ['xliff_version' => '2.0']);

$this->assertContains('<note category="approved">yes</note>', $output);
$this->assertContains('<note category="state">new</note>', $output);
}
}
12 changes: 6 additions & 6 deletions tests/Unit/FileStorageTest.php
Expand Up @@ -58,7 +58,7 @@ public function testCreateNewCatalogue()
->with(
$this->isInstanceOf(MessageCatalogueInterface::class),
'xlf',
['path' => 'foo']
['path' => 'foo', 'xliff_version' => '2.0']
);

$storage = new FileStorage($writer, new TranslationLoader(), ['foo']);
Expand All @@ -73,7 +73,7 @@ public function testCreateNewCatalogue()
->with(
$this->isInstanceOf(MessageCatalogueInterface::class),
'format',
['path' => 'bar', 'default_output_format' => 'format']
['path' => 'bar', 'default_output_format' => 'format', 'xliff_version' => '2.0']
);

$storage = new FileStorage($writer, new TranslationLoader(), ['bar'], ['default_output_format' => 'format']);
Expand All @@ -91,7 +91,7 @@ public function testCreateExistingCatalogue()
->with(
$this->isInstanceOf(MessageCatalogueInterface::class),
'xlf',
['path' => $this->getFixturePath()]
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
);

$loader = new TranslationLoader();
Expand Down Expand Up @@ -134,7 +134,7 @@ public function testUpdate()
->with(
$this->isInstanceOf(MessageCatalogueInterface::class),
'xlf',
['path' => $this->getFixturePath()]
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
);

$loader = new TranslationLoader();
Expand All @@ -159,7 +159,7 @@ public function testDelete()
return !$catalogue->defines('test_0', 'messages');
}),
'xlf',
['path' => $this->getFixturePath()]
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
);

$loader = new TranslationLoader();
Expand All @@ -183,7 +183,7 @@ public function testImport()
return $catalogue->defines('test_4711', 'messages');
}),
'xlf',
['path' => $this->getFixturePath()]
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
);

$loader = new TranslationLoader();
Expand Down

0 comments on commit 47c6f09

Please sign in to comment.