diff options
Diffstat (limited to 'vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php')
-rw-r--r-- | vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php b/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php new file mode 100644 index 00000000..0cafc043 --- /dev/null +++ b/vendor/symfony/translation/Symfony/Component/Translation/Loader/XliffFileLoader.php | |||
@@ -0,0 +1,163 @@ | |||
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\Translation\Exception\InvalidResourceException; | ||
16 | use Symfony\Component\Translation\Exception\NotFoundResourceException; | ||
17 | use 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 | */ | ||
26 | class 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 | } | ||