|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.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 Symfony\Component\Translation\Loader; |
|
13 |
|
14 use Symfony\Component\Translation\MessageCatalogue; |
|
15 use Symfony\Component\Config\Resource\FileResource; |
|
16 |
|
17 /** |
|
18 * XliffFileLoader loads translations from XLIFF files. |
|
19 * |
|
20 * @author Fabien Potencier <fabien@symfony.com> |
|
21 * |
|
22 * @api |
|
23 */ |
|
24 class XliffFileLoader implements LoaderInterface |
|
25 { |
|
26 /** |
|
27 * {@inheritdoc} |
|
28 * |
|
29 * @api |
|
30 */ |
|
31 public function load($resource, $locale, $domain = 'messages') |
|
32 { |
|
33 $xml = $this->parseFile($resource); |
|
34 $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2'); |
|
35 |
|
36 $catalogue = new MessageCatalogue($locale); |
|
37 foreach ($xml->xpath('//xliff:trans-unit') as $translation) { |
|
38 $catalogue->set((string) $translation->source, (string) $translation->target, $domain); |
|
39 } |
|
40 $catalogue->addResource(new FileResource($resource)); |
|
41 |
|
42 return $catalogue; |
|
43 } |
|
44 |
|
45 /** |
|
46 * Validates and parses the given file into a SimpleXMLElement |
|
47 * |
|
48 * @param string $file |
|
49 * @return SimpleXMLElement |
|
50 */ |
|
51 private function parseFile($file) |
|
52 { |
|
53 $dom = new \DOMDocument(); |
|
54 $current = libxml_use_internal_errors(true); |
|
55 if (!@$dom->load($file, LIBXML_COMPACT)) { |
|
56 throw new \RuntimeException(implode("\n", $this->getXmlErrors())); |
|
57 } |
|
58 |
|
59 $location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd'; |
|
60 $parts = explode('/', $location); |
|
61 if (preg_match('#^phar://#i', $location)) { |
|
62 $tmpfile = tempnam(sys_get_temp_dir(), 'sf2'); |
|
63 if ($tmpfile) { |
|
64 file_put_contents($tmpfile, file_get_contents($location)); |
|
65 $tmpfiles[] = $tmpfile; |
|
66 $parts = explode('/', str_replace('\\', '/', $tmpfile)); |
|
67 } |
|
68 } |
|
69 $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : ''; |
|
70 $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts)); |
|
71 |
|
72 $source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd'); |
|
73 $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source); |
|
74 |
|
75 if (!@$dom->schemaValidateSource($source)) { |
|
76 throw new \RuntimeException(implode("\n", $this->getXmlErrors())); |
|
77 } |
|
78 $dom->validateOnParse = true; |
|
79 $dom->normalizeDocument(); |
|
80 libxml_use_internal_errors($current); |
|
81 |
|
82 return simplexml_import_dom($dom); |
|
83 } |
|
84 |
|
85 /** |
|
86 * Returns the XML errors of the internal XML parser |
|
87 * |
|
88 * @return array An array of errors |
|
89 */ |
|
90 private function getXmlErrors() |
|
91 { |
|
92 $errors = array(); |
|
93 foreach (libxml_get_errors() as $error) { |
|
94 $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)', |
|
95 LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', |
|
96 $error->code, |
|
97 trim($error->message), |
|
98 $error->file ? $error->file : 'n/a', |
|
99 $error->line, |
|
100 $error->column |
|
101 ); |
|
102 } |
|
103 |
|
104 libxml_clear_errors(); |
|
105 libxml_use_internal_errors(false); |
|
106 |
|
107 return $errors; |
|
108 } |
|
109 } |