Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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\Config\Resource\FileResource;
15
use Symfony\Component\Config\Util\Exception\InvalidXmlException;
16
use Symfony\Component\Config\Util\Exception\XmlParsingException;
17
use Symfony\Component\Config\Util\XmlUtils;
18
use Symfony\Component\Translation\Exception\InvalidResourceException;
19
use Symfony\Component\Translation\Exception\NotFoundResourceException;
20
use Symfony\Component\Translation\Exception\RuntimeException;
21
use Symfony\Component\Translation\MessageCatalogue;
22
use Symfony\Component\Translation\Util\XliffUtils;
23
 
24
/**
25
 * XliffFileLoader loads translations from XLIFF files.
26
 *
27
 * @author Fabien Potencier <fabien@symfony.com>
28
 */
29
class XliffFileLoader implements LoaderInterface
30
{
31
    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
32
    {
33
        if (!class_exists(XmlUtils::class)) {
34
            throw new RuntimeException('Loading translations from the Xliff format requires the Symfony Config component.');
35
        }
36
 
37
        if (!$this->isXmlString($resource)) {
38
            if (!stream_is_local($resource)) {
39
                throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
40
            }
41
 
42
            if (!file_exists($resource)) {
43
                throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
44
            }
45
 
46
            if (!is_file($resource)) {
47
                throw new InvalidResourceException(sprintf('This is neither a file nor an XLIFF string "%s".', $resource));
48
            }
49
        }
50
 
51
        try {
52
            if ($this->isXmlString($resource)) {
53
                $dom = XmlUtils::parse($resource);
54
            } else {
55
                $dom = XmlUtils::loadFile($resource);
56
            }
57
        } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {
58
            throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e);
59
        }
60
 
61
        if ($errors = XliffUtils::validateSchema($dom)) {
62
            throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors));
63
        }
64
 
65
        $catalogue = new MessageCatalogue($locale);
66
        $this->extract($dom, $catalogue, $domain);
67
 
68
        if (is_file($resource) && class_exists(FileResource::class)) {
69
            $catalogue->addResource(new FileResource($resource));
70
        }
71
 
72
        return $catalogue;
73
    }
74
 
75
    private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
76
    {
77
        $xliffVersion = XliffUtils::getVersionNumber($dom);
78
 
79
        if ('1.2' === $xliffVersion) {
80
            $this->extractXliff1($dom, $catalogue, $domain);
81
        }
82
 
83
        if ('2.0' === $xliffVersion) {
84
            $this->extractXliff2($dom, $catalogue, $domain);
85
        }
86
    }
87
 
88
    /**
89
     * Extract messages and metadata from DOMDocument into a MessageCatalogue.
90
     */
91
    private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
92
    {
93
        $xml = simplexml_import_dom($dom);
94
        $encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
95
 
96
        $namespace = 'urn:oasis:names:tc:xliff:document:1.2';
97
        $xml->registerXPathNamespace('xliff', $namespace);
98
 
99
        foreach ($xml->xpath('//xliff:file') as $file) {
100
            $fileAttributes = $file->attributes();
101
 
102
            $file->registerXPathNamespace('xliff', $namespace);
103
 
104
            foreach ($file->xpath('.//xliff:prop') as $prop) {
105
                $catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain);
106
            }
107
 
108
            foreach ($file->xpath('.//xliff:trans-unit') as $translation) {
109
                $attributes = $translation->attributes();
110
 
111
                if (!(isset($attributes['resname']) || isset($translation->source))) {
112
                    continue;
113
                }
114
 
115
                $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
116
                // If the xlf file has another encoding specified, try to convert it because
117
                // simple_xml will always return utf-8 encoded values
118
                $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding);
119
 
120
                $catalogue->set((string) $source, $target, $domain);
121
 
122
                $metadata = [
123
                    'source' => (string) $translation->source,
124
                    'file' => [
125
                        'original' => (string) $fileAttributes['original'],
126
                    ],
127
                ];
128
                if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {
129
                    $metadata['notes'] = $notes;
130
                }
131
 
132
                if (isset($translation->target) && $translation->target->attributes()) {
133
                    $metadata['target-attributes'] = [];
134
                    foreach ($translation->target->attributes() as $key => $value) {
135
                        $metadata['target-attributes'][$key] = (string) $value;
136
                    }
137
                }
138
 
139
                if (isset($attributes['id'])) {
140
                    $metadata['id'] = (string) $attributes['id'];
141
                }
142
 
143
                $catalogue->setMetadata((string) $source, $metadata, $domain);
144
            }
145
        }
146
    }
147
 
148
    private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
149
    {
150
        $xml = simplexml_import_dom($dom);
151
        $encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
152
 
153
        $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');
154
 
155
        foreach ($xml->xpath('//xliff:unit') as $unit) {
156
            foreach ($unit->segment as $segment) {
157
                $attributes = $unit->attributes();
158
                $source = $attributes['name'] ?? $segment->source;
159
 
160
                // If the xlf file has another encoding specified, try to convert it because
161
                // simple_xml will always return utf-8 encoded values
162
                $target = $this->utf8ToCharset((string) ($segment->target ?? $segment->source), $encoding);
163
 
164
                $catalogue->set((string) $source, $target, $domain);
165
 
166
                $metadata = [];
167
                if (isset($segment->target) && $segment->target->attributes()) {
168
                    $metadata['target-attributes'] = [];
169
                    foreach ($segment->target->attributes() as $key => $value) {
170
                        $metadata['target-attributes'][$key] = (string) $value;
171
                    }
172
                }
173
 
174
                if (isset($unit->notes)) {
175
                    $metadata['notes'] = [];
176
                    foreach ($unit->notes->note as $noteNode) {
177
                        $note = [];
178
                        foreach ($noteNode->attributes() as $key => $value) {
179
                            $note[$key] = (string) $value;
180
                        }
181
                        $note['content'] = (string) $noteNode;
182
                        $metadata['notes'][] = $note;
183
                    }
184
                }
185
 
186
                $catalogue->setMetadata((string) $source, $metadata, $domain);
187
            }
188
        }
189
    }
190
 
191
    /**
192
     * Convert a UTF8 string to the specified encoding.
193
     */
194
    private function utf8ToCharset(string $content, string $encoding = null): string
195
    {
196
        if ('UTF-8' !== $encoding && !empty($encoding)) {
197
            return mb_convert_encoding($content, $encoding, 'UTF-8');
198
        }
199
 
200
        return $content;
201
    }
202
 
203
    private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array
204
    {
205
        $notes = [];
206
 
207
        if (null === $noteElement) {
208
            return $notes;
209
        }
210
 
211
        /** @var \SimpleXMLElement $xmlNote */
212
        foreach ($noteElement as $xmlNote) {
213
            $noteAttributes = $xmlNote->attributes();
214
            $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)];
215
            if (isset($noteAttributes['priority'])) {
216
                $note['priority'] = (int) $noteAttributes['priority'];
217
            }
218
 
219
            if (isset($noteAttributes['from'])) {
220
                $note['from'] = (string) $noteAttributes['from'];
221
            }
222
 
223
            $notes[] = $note;
224
        }
225
 
226
        return $notes;
227
    }
228
 
229
    private function isXmlString(string $resource): bool
230
    {
231
        return str_starts_with($resource, '<?xml');
232
    }
233
}