]> git.immae.eu Git - github/wallabag/wallabag.git/blame - vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php
gitignore vendor
[github/wallabag/wallabag.git] / vendor / symfony / translation / Symfony / Component / Translation / Loader / XliffFileLoader.php
CommitLineData
4f5b44bd
NL
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
12namespace Symfony\Component\Translation\Loader;
13
14use Symfony\Component\Translation\MessageCatalogue;
15use Symfony\Component\Translation\Exception\InvalidResourceException;
16use Symfony\Component\Translation\Exception\NotFoundResourceException;
17use Symfony\Component\Config\Resource\FileResource;
18
19/**
20 * XliffFileLoader loads translations from XLIFF files.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 *
24 * @api
25 */
26class XliffFileLoader implements LoaderInterface
27{
28 /**
29 * {@inheritdoc}
30 *
31 * @api
32 */
33 public function load($resource, $locale, $domain = 'messages')
34 {
35 if (!stream_is_local($resource)) {
36 throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
37 }
38
39 if (!file_exists($resource)) {
40 throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
41 }
42
43 list($xml, $encoding) = $this->parseFile($resource);
44 $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
45
46 $catalogue = new MessageCatalogue($locale);
47 foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
48 $attributes = $translation->attributes();
49
50 if (!(isset($attributes['resname']) || isset($translation->source)) || !isset($translation->target)) {
51 continue;
52 }
53
54 $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
55 $target = (string) $translation->target;
56
57 // If the xlf file has another encoding specified, try to convert it because
58 // simple_xml will always return utf-8 encoded values
59 if ('UTF-8' !== $encoding && !empty($encoding)) {
60 if (function_exists('mb_convert_encoding')) {
61 $target = mb_convert_encoding($target, $encoding, 'UTF-8');
62 } elseif (function_exists('iconv')) {
63 $target = iconv('UTF-8', $encoding, $target);
64 } else {
65 throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
66 }
67 }
68
69 $catalogue->set((string) $source, $target, $domain);
70 }
71 $catalogue->addResource(new FileResource($resource));
72
73 return $catalogue;
74 }
75
76 /**
77 * Validates and parses the given file into a SimpleXMLElement
78 *
79 * @param string $file
80 *
81 * @throws \RuntimeException
82 *
83 * @return \SimpleXMLElement
84 *
85 * @throws InvalidResourceException
86 */
87 private function parseFile($file)
88 {
89 $internalErrors = libxml_use_internal_errors(true);
90 $disableEntities = libxml_disable_entity_loader(true);
91 libxml_clear_errors();
92
93 $dom = new \DOMDocument();
94 $dom->validateOnParse = true;
95 if (!@$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
96 libxml_disable_entity_loader($disableEntities);
97
98 throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
99 }
100
101 libxml_disable_entity_loader($disableEntities);
102
103 foreach ($dom->childNodes as $child) {
104 if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
105 libxml_use_internal_errors($internalErrors);
106
107 throw new InvalidResourceException('Document types are not allowed.');
108 }
109 }
110
111 $location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
112 $parts = explode('/', $location);
113 if (0 === stripos($location, 'phar://')) {
114 $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
115 if ($tmpfile) {
116 copy($location, $tmpfile);
117 $parts = explode('/', str_replace('\\', '/', $tmpfile));
118 }
119 }
120 $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
121 $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
122
123 $source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
124 $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
125
126 if (!@$dom->schemaValidateSource($source)) {
127 throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
128 }
129
130 $dom->normalizeDocument();
131
132 libxml_use_internal_errors($internalErrors);
133
134 return array(simplexml_import_dom($dom), strtoupper($dom->encoding));
135 }
136
137 /**
138 * Returns the XML errors of the internal XML parser
139 *
140 * @param Boolean $internalErrors
141 *
142 * @return array An array of errors
143 */
144 private function getXmlErrors($internalErrors)
145 {
146 $errors = array();
147 foreach (libxml_get_errors() as $error) {
148 $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
149 LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
150 $error->code,
151 trim($error->message),
152 $error->file ? $error->file : 'n/a',
153 $error->line,
154 $error->column
155 );
156 }
157
158 libxml_clear_errors();
159 libxml_use_internal_errors($internalErrors);
160
161 return $errors;
162 }
163}