Skip to content

Commit 47c6f09

Browse files
authored
Using xliff version 2.0 as default (#12)
* 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
1 parent 17b09c5 commit 47c6f09

File tree

5 files changed

+254
-15
lines changed

5 files changed

+254
-15
lines changed

src/Dumper/XliffDumper.php

Lines changed: 197 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,218 @@
1111

1212
namespace Translation\SymfonyStorage\Dumper;
1313

14-
use Symfony\Component\Translation\Dumper\XliffFileDumper;
14+
use Symfony\Component\Translation\Dumper\FileDumper;
1515
use Symfony\Component\Translation\MessageCatalogue;
16+
use Symfony\Component\Translation\Exception\InvalidArgumentException;
1617

1718
/**
19+
* XliffFileDumper generates xliff files from a message catalogue.
20+
* Mostly borrowed from Symfony.
21+
*
1822
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
23+
* @author Michel Salib <michelsalib@hotmail.com>
1924
*/
20-
final class XliffDumper extends XliffFileDumper
25+
final class XliffDumper extends FileDumper
2126
{
2227
/**
23-
* Alias for formatCatalogue to provide a BC bridge.
28+
* {@inheritdoc}
29+
*/
30+
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
31+
{
32+
$xliffVersion = '1.2';
33+
if (array_key_exists('xliff_version', $options)) {
34+
$xliffVersion = $options['xliff_version'];
35+
}
36+
37+
if (array_key_exists('default_locale', $options)) {
38+
$defaultLocale = $options['default_locale'];
39+
} else {
40+
$defaultLocale = \Locale::getDefault();
41+
}
42+
43+
if ('1.2' === $xliffVersion) {
44+
return $this->dumpXliff1($defaultLocale, $messages, $domain, $options);
45+
}
46+
if ('2.0' === $xliffVersion) {
47+
return $this->dumpXliff2($defaultLocale, $messages, $domain, $options);
48+
}
49+
50+
throw new InvalidArgumentException(
51+
sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)
52+
);
53+
}
54+
55+
/**
56+
* Symfony 2.7 support.
2457
*
2558
* @param MessageCatalogue $messages
2659
* @param string $domain
27-
* @param array $options
2860
*
2961
* @return string
3062
*/
31-
public function getFormattedCatalogue(MessageCatalogue $messages, $domain, array $options = [])
63+
protected function format(MessageCatalogue $messages, $domain)
64+
{
65+
return $this->dumpXliff2(\Locale::getDefault(), $messages, $domain);
66+
}
67+
68+
/**
69+
* {@inheritdoc}
70+
*/
71+
protected function getExtension()
72+
{
73+
return 'xlf';
74+
}
75+
76+
private function dumpXliff1($defaultLocale, MessageCatalogue $messages, $domain, array $options = [])
3277
{
33-
if (method_exists($this, 'formatCatalogue')) {
34-
return parent::formatCatalogue($messages, $domain, $options);
78+
$toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];
79+
if (array_key_exists('tool_info', $options)) {
80+
$toolInfo = array_merge($toolInfo, $options['tool_info']);
3581
}
3682

37-
return $this->format($messages, $domain);
83+
$dom = new \DOMDocument('1.0', 'utf-8');
84+
$dom->formatOutput = true;
85+
86+
$xliff = $dom->appendChild($dom->createElement('xliff'));
87+
$xliff->setAttribute('version', '1.2');
88+
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
89+
90+
$xliffFile = $xliff->appendChild($dom->createElement('file'));
91+
$xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale));
92+
$xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));
93+
$xliffFile->setAttribute('datatype', 'plaintext');
94+
$xliffFile->setAttribute('original', 'file.ext');
95+
96+
$xliffHead = $xliffFile->appendChild($dom->createElement('header'));
97+
$xliffTool = $xliffHead->appendChild($dom->createElement('tool'));
98+
foreach ($toolInfo as $id => $value) {
99+
$xliffTool->setAttribute($id, $value);
100+
}
101+
102+
$xliffBody = $xliffFile->appendChild($dom->createElement('body'));
103+
foreach ($messages->all($domain) as $source => $target) {
104+
$translation = $dom->createElement('trans-unit');
105+
106+
$translation->setAttribute(
107+
'id',
108+
strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')
109+
);
110+
$translation->setAttribute('resname', $source);
111+
112+
$s = $translation->appendChild($dom->createElement('source'));
113+
$s->appendChild($dom->createTextNode($source));
114+
115+
// Does the target contain characters requiring a CDATA section?
116+
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode(
117+
$target
118+
);
119+
120+
$targetElement = $dom->createElement('target');
121+
$metadata = $messages->getMetadata($source, $domain);
122+
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
123+
foreach ($metadata['target-attributes'] as $name => $value) {
124+
$targetElement->setAttribute($name, $value);
125+
}
126+
}
127+
$t = $translation->appendChild($targetElement);
128+
$t->appendChild($text);
129+
130+
if ($this->hasMetadataArrayInfo('notes', $metadata)) {
131+
foreach ($metadata['notes'] as $note) {
132+
if (!isset($note['content'])) {
133+
continue;
134+
}
135+
136+
$n = $translation->appendChild($dom->createElement('note'));
137+
$n->appendChild($dom->createTextNode($note['content']));
138+
139+
if (isset($note['priority'])) {
140+
$n->setAttribute('priority', $note['priority']);
141+
}
142+
143+
if (isset($note['from'])) {
144+
$n->setAttribute('from', $note['from']);
145+
}
146+
}
147+
}
148+
149+
$xliffBody->appendChild($translation);
150+
}
151+
152+
return $dom->saveXML();
153+
}
154+
155+
private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, array $options = [])
156+
{
157+
$dom = new \DOMDocument('1.0', 'utf-8');
158+
$dom->formatOutput = true;
159+
160+
$xliff = $dom->appendChild($dom->createElement('xliff'));
161+
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0');
162+
$xliff->setAttribute('version', '2.0');
163+
$xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale));
164+
$xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));
165+
166+
$xliffFile = $xliff->appendChild($dom->createElement('file'));
167+
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
168+
169+
foreach ($messages->all($domain) as $source => $target) {
170+
$translation = $dom->createElement('unit');
171+
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
172+
$metadata = $messages->getMetadata($source, $domain);
173+
174+
// Add notes section
175+
if ($this->hasMetadataArrayInfo('notes', $metadata)) {
176+
$notesElement = $dom->createElement('notes');
177+
foreach ($metadata['notes'] as $note) {
178+
$n = $dom->createElement('note');
179+
$n->appendChild($dom->createTextNode(isset($note['content']) ? $note['content'] : ''));
180+
unset($note['content']);
181+
182+
foreach ($note as $name => $value) {
183+
$n->setAttribute($name, $value);
184+
}
185+
$notesElement->appendChild($n);
186+
}
187+
$translation->appendChild($notesElement);
188+
}
189+
190+
$segment = $translation->appendChild($dom->createElement('segment'));
191+
192+
$s = $segment->appendChild($dom->createElement('source'));
193+
$s->appendChild($dom->createTextNode($source));
194+
195+
// Does the target contain characters requiring a CDATA section?
196+
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode(
197+
$target
198+
);
199+
200+
$targetElement = $dom->createElement('target');
201+
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
202+
foreach ($metadata['target-attributes'] as $name => $value) {
203+
$targetElement->setAttribute($name, $value);
204+
}
205+
}
206+
207+
$t = $segment->appendChild($targetElement);
208+
$t->appendChild($text);
209+
210+
$xliffFile->appendChild($translation);
211+
}
212+
213+
return $dom->saveXML();
214+
}
215+
216+
/**
217+
* @param string $key
218+
* @param array|null $metadata
219+
*
220+
* @return bool
221+
*/
222+
private function hasMetadataArrayInfo($key, $metadata = null)
223+
{
224+
return null !== $metadata &&
225+
array_key_exists($key, $metadata) &&
226+
($metadata[$key] instanceof \Traversable || is_array($metadata[$key]));
38227
}
39228
}

src/FileStorage.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public function __construct(TranslationWriter $writer, $loader, array $dir, arra
6767
throw new \LogicException('Third parameter of FileStorage cannot be empty');
6868
}
6969

70+
if (!array_key_exists('xliff_version', $options)) {
71+
// Set default value for xliff version.
72+
$options['xliff_version'] = '2.0';
73+
}
74+
7075
$this->writer = $writer;
7176
$this->loader = $loader;
7277
$this->dir = $dir;

src/XliffConverter.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public static function catalogueToContent(MessageCatalogue $catalogue, $domain,
5151
{
5252
$dumper = new XliffDumper();
5353

54-
return $dumper->getFormattedCatalogue($catalogue, $domain, $options);
54+
if (!array_key_exists('xliff_version', $options)) {
55+
// Set default value for xliff version.
56+
$options['xliff_version'] = '2.0';
57+
}
58+
59+
return $dumper->formatCatalogue($catalogue, $domain, $options);
5560
}
5661
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHP Translation package.
5+
*
6+
* (c) PHP Translation team <tobias.nyholm@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Translation\SymfonyStorage\Tests\Unit\Dumper;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Translation\MessageCatalogue;
16+
use Translation\SymfonyStorage\Dumper\XliffDumper;
17+
18+
class XliffDumperTest extends TestCase
19+
{
20+
public function testDumpXliff2Meta()
21+
{
22+
$catalogue = new MessageCatalogue('en');
23+
$catalogue->set('key0', 'trans0');
24+
$catalogue->setMetadata('key0', ['notes' => [
25+
['content' => 'yes', 'category' => 'approved'],
26+
['content' => 'new', 'category' => 'state'],
27+
]]);
28+
29+
$catalogue->set('key1', 'trans1');
30+
$catalogue->setMetadata('key1', ['notes' => [
31+
['content' => 'cnt', 'priority' => '2'],
32+
]]);
33+
34+
$dumper = new XliffDumper();
35+
$output = $dumper->formatCatalogue($catalogue, 'messages', ['xliff_version' => '2.0']);
36+
37+
$this->assertContains('<note category="approved">yes</note>', $output);
38+
$this->assertContains('<note category="state">new</note>', $output);
39+
}
40+
}

tests/Unit/FileStorageTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function testCreateNewCatalogue()
5858
->with(
5959
$this->isInstanceOf(MessageCatalogueInterface::class),
6060
'xlf',
61-
['path' => 'foo']
61+
['path' => 'foo', 'xliff_version' => '2.0']
6262
);
6363

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

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

9797
$loader = new TranslationLoader();
@@ -134,7 +134,7 @@ public function testUpdate()
134134
->with(
135135
$this->isInstanceOf(MessageCatalogueInterface::class),
136136
'xlf',
137-
['path' => $this->getFixturePath()]
137+
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
138138
);
139139

140140
$loader = new TranslationLoader();
@@ -159,7 +159,7 @@ public function testDelete()
159159
return !$catalogue->defines('test_0', 'messages');
160160
}),
161161
'xlf',
162-
['path' => $this->getFixturePath()]
162+
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
163163
);
164164

165165
$loader = new TranslationLoader();
@@ -183,7 +183,7 @@ public function testImport()
183183
return $catalogue->defines('test_4711', 'messages');
184184
}),
185185
'xlf',
186-
['path' => $this->getFixturePath()]
186+
['path' => $this->getFixturePath(), 'xliff_version' => '2.0']
187187
);
188188

189189
$loader = new TranslationLoader();

0 commit comments

Comments
 (0)