From 81ec05a3fc39845426f302412d53ef6480fc7c3a Mon Sep 17 00:00:00 2001
From: Mathias Schreiber <mathias.schreiber@wmdb.de>
Date: Thu, 18 Dec 2014 11:24:21 +0100
Subject: [PATCH] [BUGFIX] Properly handle translation file detection

The GeneralUtility::llXmlAutoFileName() method will now also correctly
handle paths to files that are not placed within a known directory (ext,
sysext, test etc.) if the call is made with $sameFile = TRUE.

This allows placing language files in storages like fileadmin.

Resolves: #35093
Resolves: #34728
Releases: master, 6.2
Change-Id: Ic5901c3fa98233978abf26db377666dade16f8e6
Reviewed-on: http://review.typo3.org/34285
Reviewed-by: Gernot Ploiner <gp@webprofil.at>
Tested-by: Gernot Ploiner <gp@webprofil.at>
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
---
 .../Parser/LocallangXmlParser.php             | 27 ++++++++++++++-----
 .../core/Classes/Utility/GeneralUtility.php   | 22 ++++++++-------
 2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php b/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php
index 2d5cff53f3db..c1f3edbc26c4 100644
--- a/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php
+++ b/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php
@@ -14,6 +14,9 @@ namespace TYPO3\CMS\Core\Localization\Parser;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
 /**
  * Parser for XML locallang file.
  *
@@ -43,11 +46,21 @@ class LocallangXmlParser extends AbstractXmlParser {
 		// Parse source
 		$parsedSource = $this->parseXmlFile();
 		// Parse target
-		$localizedTargetPath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName(\TYPO3\CMS\Core\Utility\GeneralUtility::llXmlAutoFileName($this->sourcePath, $this->languageKey));
-		$targetPath = $this->languageKey !== 'default' && @is_file($localizedTargetPath) ? $localizedTargetPath : $this->sourcePath;
+		$targetPath = $this->sourcePath;
+		if ($this->languageKey !== 'default') {
+			$localizedTargetPath = GeneralUtility::getFileAbsFileName(GeneralUtility::llXmlAutoFileName($this->sourcePath, $this->languageKey));
+			if (!@is_file($localizedTargetPath)) {
+				// Global localization is not available, try split localization file
+				$localizedTargetPath = GeneralUtility::getFileAbsFileName(GeneralUtility::llXmlAutoFileName($this->sourcePath, $this->languageKey, TRUE));
+			}
+			if (!@is_file($localizedTargetPath)) {
+				$localizedTargetPath = $this->sourcePath;
+			}
+			$targetPath = $localizedTargetPath;
+		}
 		try {
 			$parsedTarget = $this->getParsedTargetData($targetPath);
-		} catch (\TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException $e) {
+		} catch (InvalidXmlFileException $e) {
 			$parsedTarget = $this->getParsedTargetData($this->sourcePath);
 		}
 		$LOCAL_LANG = array();
@@ -59,7 +72,7 @@ class LocallangXmlParser extends AbstractXmlParser {
 	/**
 	 * Returns array representation of XLIFF data, starting from a root node.
 	 *
-	 * @param SimpleXMLElement $root XML root element
+	 * @param \SimpleXMLElement $root XML root element
 	 * @param string $element Target or Source
 	 * @return array
 	 */
@@ -99,7 +112,7 @@ class LocallangXmlParser extends AbstractXmlParser {
 			// <languageKey index="fr">EXT:yourext/path/to/localized/locallang.xml</languageKey>
 			$reference = sprintf('%s', $bodyOfFileTag);
 			if (substr($reference, -4) === '.xml') {
-				return $this->getParsedTargetData(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($reference));
+				return $this->getParsedTargetData(GeneralUtility::getFileAbsFileName($reference));
 			}
 		}
 		/** @var \SimpleXMLElement $translationElement */
@@ -154,7 +167,7 @@ class LocallangXmlParser extends AbstractXmlParser {
 	 *
 	 * @param string $targetPath Path of the target file
 	 * @return array
-	 * @throws \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException
+	 * @throws InvalidXmlFileException
 	 */
 	protected function parseXmlTargetFile($targetPath) {
 		$rootXmlNode = FALSE;
@@ -162,7 +175,7 @@ class LocallangXmlParser extends AbstractXmlParser {
 			$rootXmlNode = simplexml_load_file($targetPath, 'SimpleXmlElement', \LIBXML_NOWARNING);
 		}
 		if (!isset($rootXmlNode) || $rootXmlNode === FALSE) {
-			throw new \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987);
+			throw new InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987);
 		}
 		return $this->doParsingTargetFromRoot($rootXmlNode);
 	}
diff --git a/typo3/sysext/core/Classes/Utility/GeneralUtility.php b/typo3/sysext/core/Classes/Utility/GeneralUtility.php
index 43e3069fe8c0..f662a8a201ca 100755
--- a/typo3/sysext/core/Classes/Utility/GeneralUtility.php
+++ b/typo3/sysext/core/Classes/Utility/GeneralUtility.php
@@ -3979,18 +3979,24 @@ Connection: close
 	/**
 	 * Returns auto-filename for locallang-XML localizations.
 	 *
-	 * @param string $fileRef Absolute file reference to locallang-XML file. Must be inside system/global/local extension
+	 * @param string $fileRef Absolute file reference to locallang-XML file.
 	 * @param string $language Language key
 	 * @param bool $sameLocation if TRUE, then locallang-XML localization file name will be returned with same directory as $fileRef
-	 * @return string Returns the filename reference for the language unless error occurred (or local mode is used) in which case it will be NULL
+	 * @return string Returns the filename reference for the language unless error occurred in which case it will be NULL
 	 */
 	static public function llXmlAutoFileName($fileRef, $language, $sameLocation = FALSE) {
+		// If $fileRef is already prefixed with "[language key]" then we should return it as this
+		$fileName = basename($fileRef);
+		if (self::isFirstPartOfStr($fileName, $language . '.')) {
+			return $fileRef;
+		}
+
 		if ($sameLocation) {
-			$location = 'EXT:';
-		} else {
-			// Default location of translations
-			$location = 'typo3conf/l10n/' . $language . '/';
+			return str_replace($fileName, $language . '.' . $fileName, $fileRef);
 		}
+
+		// Default location of translations
+		$location = 'typo3conf/l10n/' . $language . '/';
 		// Analyse file reference:
 		// Is system:
 		if (self::isFirstPartOfStr($fileRef, PATH_typo3 . 'sysext/')) {
@@ -4017,10 +4023,6 @@ Connection: close
 			}
 			// Add empty first-entry if not there.
 			list($file_extPath, $file_fileName) = $temp;
-			// If $fileRef is already prefix with "[language key]" then we should return it as this
-			if (substr($file_fileName, 0, strlen($language) + 1) === $language . '.') {
-				return $fileRef;
-			}
 			// The filename is prefixed with "[language key]." because it prevents the llxmltranslate tool from detecting it.
 			return $location . $file_extKey . '/' . ($file_extPath ? $file_extPath . '/' : '') . $language . '.' . $file_fileName;
 		} else {
-- 
GitLab