e1776004e3e29b9c07e1851076408e3008452b8c
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Localization / Parser / LocallangXmlParser.php
1 <?php
2 namespace TYPO3\CMS\Core\Localization\Parser;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2011 Dominique Feyer <dfeyer@reelpeek.net>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Parser for XML locallang file.
31 *
32 * @author Dominique Feyer <dfeyer@reelpeek.net>
33 */
34 class LocallangXmlParser extends \TYPO3\CMS\Core\Localization\Parser\AbstractXmlParser {
35
36 /**
37 * Associative array of "filename => parsed data" pairs.
38 *
39 * @var array
40 */
41 protected $parsedTargetFiles;
42
43 /**
44 * Returns parsed representation of XML file.
45 *
46 * @param string $sourcePath Source file path
47 * @param string $languageKey Language key
48 * @param string $charset Charset
49 * @return array
50 */
51 public function getParsedData($sourcePath, $languageKey, $charset = '') {
52 $this->sourcePath = $sourcePath;
53 $this->languageKey = $languageKey;
54 $this->charset = $this->getCharset($languageKey, $charset);
55 // Parse source
56 $parsedSource = $this->parseXmlFile();
57 // Parse target
58 $localizedTargetPath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName(\TYPO3\CMS\Core\Utility\GeneralUtility::llXmlAutoFileName($this->sourcePath, $this->languageKey));
59 $targetPath = $this->languageKey !== 'default' && @is_file($localizedTargetPath) ? $localizedTargetPath : $this->sourcePath;
60 try {
61 $parsedTarget = $this->getParsedTargetData($targetPath);
62 } catch (\TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException $e) {
63 $parsedTarget = $this->getParsedTargetData($this->sourcePath);
64 }
65 $LOCAL_LANG = array();
66 $LOCAL_LANG[$languageKey] = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($parsedSource, $parsedTarget);
67 return $LOCAL_LANG;
68 }
69
70 /**
71 * Returns array representation of XLIFF data, starting from a root node.
72 *
73 * @param SimpleXMLElement $root XML root element
74 * @param string $element Target or Source
75 * @return array
76 */
77 protected function doParsingFromRootForElement(\SimpleXMLElement $root, $element) {
78 $bodyOfFileTag = $root->data->languageKey;
79 // Check if the source llxml file contains localized records
80 $localizedBodyOfFileTag = $root->data->xpath('languageKey[@index=\'' . $this->languageKey . '\']');
81 if ($element === 'source' || $this->languageKey === 'default') {
82 $parsedData = $this->getParsedDataForElement($bodyOfFileTag, $element);
83 } else {
84 $parsedData = array();
85 }
86 if ($element === 'target' && isset($localizedBodyOfFileTag[0]) && $localizedBodyOfFileTag[0] instanceof \SimpleXMLElement) {
87 $parsedDataTarget = $this->getParsedDataForElement($localizedBodyOfFileTag[0], $element);
88 $mergedData = array_merge($parsedData, $parsedDataTarget);
89 if ($this->languageKey === 'default') {
90 $parsedData = array_intersect_key($mergedData, $parsedData, $parsedDataTarget);
91 } else {
92 $parsedData = array_intersect_key($mergedData, $parsedDataTarget);
93 }
94 }
95 return $parsedData;
96 }
97
98 /**
99 * Parse the given language key tag
100 *
101 * @param SimpleXMLElement $bodyOfFileTag
102 * @param string $element
103 * @return array
104 */
105 protected function getParsedDataForElement(\SimpleXMLElement $bodyOfFileTag, $element) {
106 $parsedData = array();
107 if (count($bodyOfFileTag->children()) == 0) {
108 // Check for externally-referenced resource:
109 // <languageKey index="fr">EXT:yourext/path/to/localized/locallang.xml</languageKey>
110 $reference = sprintf('%s', $bodyOfFileTag);
111 if (substr($reference, -4) === '.xml') {
112 return $this->getParsedTargetData(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($reference));
113 }
114 }
115 foreach ($bodyOfFileTag->children() as $translationElement) {
116 if ($translationElement->getName() === 'label') {
117 // If restype would be set, it could be metadata from Gettext to XLIFF conversion (and we don't need this data)
118 $parsedData[(string) $translationElement['index']][0] = array(
119 $element => (string) $translationElement
120 );
121 }
122 }
123 return $parsedData;
124 }
125
126 /**
127 * Returns array representation of XLIFF data, starting from a root node.
128 *
129 * @param \SimpleXMLElement $root A root node
130 * @return array An array representing parsed XLIFF
131 */
132 protected function doParsingFromRoot(\SimpleXMLElement $root) {
133 return $this->doParsingFromRootForElement($root, 'source');
134 }
135
136 /**
137 * Returns array representation of XLIFF data, starting from a root node.
138 *
139 * @param \SimpleXMLElement $root A root node
140 * @return array An array representing parsed XLIFF
141 */
142 protected function doParsingTargetFromRoot(\SimpleXMLElement $root) {
143 return $this->doParsingFromRootForElement($root, 'target');
144 }
145
146 /**
147 * Returns parsed representation of XML file.
148 *
149 * Parses XML if it wasn't done before. Caches parsed data.
150 *
151 * @param string $path An absolute path to XML file
152 * @return array Parsed XML file
153 */
154 public function getParsedTargetData($path) {
155 if (!isset($this->parsedTargetFiles[$path])) {
156 $this->parsedTargetFiles[$path] = $this->parseXmlTargetFile($path);
157 }
158 return $this->parsedTargetFiles[$path];
159 }
160
161 /**
162 * Reads and parses XML file and returns internal representation of data.
163 *
164 * @param string $targetPath Path of the target file
165 * @return array
166 * @throws \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException
167 */
168 protected function parseXmlTargetFile($targetPath) {
169 $rootXmlNode = FALSE;
170 if (file_exists($targetPath)) {
171 $rootXmlNode = simplexml_load_file($targetPath, 'SimpleXmlElement', \LIBXML_NOWARNING);
172 }
173 if (!isset($rootXmlNode) || $rootXmlNode === FALSE) {
174 throw new \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987);
175 }
176 return $this->doParsingTargetFromRoot($rootXmlNode);
177 }
178
179 }
180
181
182 ?>