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