TYPO3 CMS  TYPO3_7-6
LocallangXmlParser.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 
26 {
32  protected $parsedTargetFiles;
33 
43  {
44  $this->sourcePath = $sourcePath;
45  $this->languageKey = $languageKey;
46  $this->charset = $this->getCharset($languageKey, $charset);
47  // Parse source
48  $parsedSource = $this->parseXmlFile();
49  // Parse target
50  $localizedTargetPath = GeneralUtility::getFileAbsFileName(GeneralUtility::llXmlAutoFileName($this->sourcePath, $this->languageKey));
51  $targetPath = $this->languageKey !== 'default' && @is_file($localizedTargetPath) ? $localizedTargetPath : $this->sourcePath;
52  try {
53  $parsedTarget = $this->getParsedTargetData($targetPath);
54  } catch (InvalidXmlFileException $e) {
55  $parsedTarget = $this->getParsedTargetData($this->sourcePath);
56  }
57  $LOCAL_LANG = [];
58  $LOCAL_LANG[$languageKey] = $parsedSource;
59  ArrayUtility::mergeRecursiveWithOverrule($LOCAL_LANG[$languageKey], $parsedTarget);
60  return $LOCAL_LANG;
61  }
62 
71  protected function doParsingFromRootForElement(\SimpleXMLElement $root, $element)
72  {
73  $bodyOfFileTag = $root->data->languageKey;
74  if ($bodyOfFileTag === null) {
75  throw new InvalidXmlFileException('Invalid locallang.xml language file "' . PathUtility::stripPathSitePrefix($this->sourcePath) . '"', 1487944884);
76  }
77 
78  if ($element === 'source' || $this->languageKey === 'default') {
79  $parsedData = $this->getParsedDataForElement($bodyOfFileTag, $element);
80  } else {
81  $parsedData = [];
82  }
83  if ($element === 'target') {
84  // Check if the source llxml file contains localized records
85  $localizedBodyOfFileTag = $root->data->xpath('languageKey[@index=\'' . $this->languageKey . '\']');
86  if (isset($localizedBodyOfFileTag[0]) && $localizedBodyOfFileTag[0] instanceof \SimpleXMLElement) {
87  $parsedDataTarget = $this->getParsedDataForElement($localizedBodyOfFileTag[0], $element);
88  $mergedData = $parsedDataTarget + $parsedData;
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  }
96  return $parsedData;
97  }
98 
106  protected function getParsedDataForElement(\SimpleXMLElement $bodyOfFileTag, $element)
107  {
108  $parsedData = [];
109  $children = $bodyOfFileTag->children();
110  if ($children->count() === 0) {
111  // Check for externally-referenced resource:
112  // <languageKey index="fr">EXT:yourext/path/to/localized/locallang.xml</languageKey>
113  $reference = sprintf('%s', $bodyOfFileTag);
114  if (substr($reference, -4) === '.xml') {
115  return $this->getParsedTargetData(GeneralUtility::getFileAbsFileName($reference));
116  }
117  }
119  foreach ($children as $translationElement) {
120  if ($translationElement->getName() === 'label') {
121  $parsedData[(string)$translationElement['index']][0] = [
122  $element => (string)$translationElement
123  ];
124  }
125  }
126  return $parsedData;
127  }
128 
135  protected function doParsingFromRoot(\SimpleXMLElement $root)
136  {
137  return $this->doParsingFromRootForElement($root, 'source');
138  }
139 
146  protected function doParsingTargetFromRoot(\SimpleXMLElement $root)
147  {
148  return $this->doParsingFromRootForElement($root, 'target');
149  }
150 
159  public function getParsedTargetData($path)
160  {
161  if (!isset($this->parsedTargetFiles[$path])) {
162  $this->parsedTargetFiles[$path] = $this->parseXmlTargetFile($path);
163  }
164  return $this->parsedTargetFiles[$path];
165  }
166 
174  protected function parseXmlTargetFile($targetPath)
175  {
176  $rootXmlNode = false;
177  if (file_exists($targetPath)) {
178  $xmlContent = file_get_contents($targetPath);
179  // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
180  $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
181  $rootXmlNode = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOWARNING);
182  libxml_disable_entity_loader($previousValueOfEntityLoader);
183  }
184  if (!isset($rootXmlNode) || $rootXmlNode === false) {
185  $xmlError = libxml_get_last_error();
186  throw new InvalidXmlFileException(
187  'The path provided does not point to existing and accessible well-formed XML file. Reason: ' . $xmlError->message . ' in ' . $targetPath . ', line ' . $xmlError->line,
188  1278155987
189  );
190  }
191  return $this->doParsingTargetFromRoot($rootXmlNode);
192  }
193 }
static llXmlAutoFileName($fileRef, $language, $sameLocation=false)
getParsedData($sourcePath, $languageKey, $charset='')
doParsingFromRootForElement(\SimpleXMLElement $root, $element)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static getFileAbsFileName($filename, $onlyRelative=true, $relToTYPO3_mainDir=false)