[BUGFIX] Assure language override without original file 94/42694/5
authorStefan Galinski <stefan@sgalinski.de>
Wed, 4 Mar 2015 14:50:20 +0000 (15:50 +0100)
committerMarkus Klein <markus.klein@typo3.org>
Mon, 17 Aug 2015 23:06:33 +0000 (01:06 +0200)
The language override of language files is currently broken,
because it only works if a localized language file already
exists inside the extension or l10n directory. This patch assures
that the language override takes place even if no file could
be found in the first place.

Resolves: #65513
Releases: master, 6.2
Change-Id: I9269e60c5788c435b06b820c459fd4f077d066ea
Reviewed-on: http://review.typo3.org/42694
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
typo3/sysext/core/Classes/Localization/LocalizationFactory.php
typo3/sysext/core/Tests/Unit/Localization/LocalizationFactoryTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php

index b8f53fd..6641e5f 100644 (file)
@@ -13,6 +13,10 @@ namespace TYPO3\CMS\Core\Localization;
  *
  * The TYPO3 project - inspiring people to share!
  */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
 /**
  * Provides a language parser factory.
  *
@@ -48,7 +52,7 @@ class LocalizationFactory implements \TYPO3\CMS\Core\SingletonInterface {
         * @return void
         */
        protected function initialize() {
-               $this->store = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Localization\\LanguageStore');
+               $this->store = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Localization\\LanguageStore');
                $this->initializeCache();
        }
 
@@ -58,7 +62,7 @@ class LocalizationFactory implements \TYPO3\CMS\Core\SingletonInterface {
         * @return void
         */
        protected function initializeCache() {
-               $this->cacheInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n');
+               $this->cacheInstance = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n');
        }
 
        /**
@@ -72,42 +76,47 @@ class LocalizationFactory implements \TYPO3\CMS\Core\SingletonInterface {
         * @return array|boolean
         */
        public function getParsedData($fileReference, $languageKey, $charset, $errorMode, $isLocalizationOverride = FALSE) {
-               try {
-                       $hash = md5($fileReference . $languageKey . $charset);
-                       $this->errorMode = $errorMode;
-                       // Check if the default language is processed before processing other language
-                       if (!$this->store->hasData($fileReference, 'default') && $languageKey !== 'default') {
-                               $this->getParsedData($fileReference, 'default', $charset, $this->errorMode);
-                       }
-                       // If the content is parsed (local cache), use it
-                       if ($this->store->hasData($fileReference, $languageKey)) {
-                               return $this->store->getData($fileReference);
-                       }
+               $hash = md5($fileReference . $languageKey . $charset);
+               $this->errorMode = $errorMode;
+               // Check if the default language is processed before processing other language
+               if (!$this->store->hasData($fileReference, 'default') && $languageKey !== 'default') {
+                       $this->getParsedData($fileReference, 'default', $charset, $this->errorMode);
+               }
+               // If the content is parsed (local cache), use it
+               if ($this->store->hasData($fileReference, $languageKey)) {
+                       return $this->store->getData($fileReference);
+               }
 
-                       // If the content is in cache (system cache), use it
-                       $data = $this->cacheInstance->get($hash);
-                       if ($data !== FALSE) {
-                               $this->store->setData($fileReference, $languageKey, $data);
-                               return $this->store->getData($fileReference, $languageKey);
-                       }
+               // If the content is in cache (system cache), use it
+               $data = $this->cacheInstance->get($hash);
+               if ($data !== FALSE) {
+                       $this->store->setData($fileReference, $languageKey, $data);
+                       return $this->store->getData($fileReference);
+               }
 
+               try {
                        $this->store->setConfiguration($fileReference, $languageKey, $charset);
                        /** @var $parser \TYPO3\CMS\Core\Localization\Parser\LocalizationParserInterface */
                        $parser = $this->store->getParserInstance($fileReference);
                        // Get parsed data
                        $LOCAL_LANG = $parser->getParsedData($this->store->getAbsoluteFileReference($fileReference), $languageKey, $charset);
-                       // Override localization
-                       if (!$isLocalizationOverride && isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'])) {
-                               $this->localizationOverride($fileReference, $languageKey, $charset, $errorMode, $LOCAL_LANG);
-                       }
-                       // Save parsed data in cache
-                       $this->store->setData($fileReference, $languageKey, $LOCAL_LANG[$languageKey]);
-                       // Cache processed data
-                       $this->cacheInstance->set($hash, $this->store->getDataByLanguage($fileReference, $languageKey));
-               } catch (\TYPO3\CMS\Core\Localization\Exception\FileNotFoundException $exception) {
-                       // Source localization file not found
+               } catch (Exception\FileNotFoundException $exception) {
+                       // Source localization file not found, set empty data as there could be an override
                        $this->store->setData($fileReference, $languageKey, array());
+                       $LOCAL_LANG = $this->store->getData($fileReference);
+               }
+
+               // Override localization
+               if (!$isLocalizationOverride && isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'])) {
+                       $this->localizationOverride($fileReference, $languageKey, $charset, $errorMode, $LOCAL_LANG);
                }
+
+               // Save parsed data in cache
+               $this->store->setData($fileReference, $languageKey, $LOCAL_LANG[$languageKey]);
+
+               // Cache processed data
+               $this->cacheInstance->set($hash, $this->store->getDataByLanguage($fileReference, $languageKey));
+
                return $this->store->getData($fileReference);
        }
 
@@ -136,8 +145,8 @@ class LocalizationFactory implements \TYPO3\CMS\Core\SingletonInterface {
                }
                if (count($overrides) > 0) {
                        foreach ($overrides as $overrideFile) {
-                               $languageOverrideFileName = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($overrideFile);
-                               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($LOCAL_LANG, $this->getParsedData($languageOverrideFileName, $languageKey, $charset, $errorMode, TRUE));
+                               $languageOverrideFileName = GeneralUtility::getFileAbsFileName($overrideFile);
+                               ArrayUtility::mergeRecursiveWithOverrule($LOCAL_LANG, $this->getParsedData($languageOverrideFileName, $languageKey, $charset, $errorMode, TRUE));
                        }
                }
        }
diff --git a/typo3/sysext/core/Tests/Unit/Localization/LocalizationFactoryTest.php b/typo3/sysext/core/Tests/Unit/Localization/LocalizationFactoryTest.php
new file mode 100644 (file)
index 0000000..7ef5d88
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Localization;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Localization\Exception\FileNotFoundException;
+use TYPO3\CMS\Core\Localization\LocalizationFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Test case
+ */
+class LocalizationFactoryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * @test
+        */
+       public function getParsedDataHandlesLocallangXMLOverride() {
+               /** @var $subject LocalizationFactory */
+               $subject = new LocalizationFactory;
+
+               $unique = 'locallangXMLOverrideTest' . substr($this->getUniqueId(), 0, 10);
+               $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+                       <T3locallang>
+                               <data type="array">
+                                       <languageKey index="default" type="array">
+                                               <label index="buttons.logout">EXIT</label>
+                                       </languageKey>
+                               </data>
+                       </T3locallang>';
+               $file = PATH_site . 'typo3temp/' . $unique . '.xml';
+               GeneralUtility::writeFileToTypo3tempDir($file, $xml);
+               // Make sure there is no cached version of the label
+               GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n')->flush();
+               // Get default value
+               $defaultLL = $subject->getParsedData('EXT:lang/locallang_core.xlf', 'default', 'utf-8', 0);
+               // Clear language cache again
+               GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n')->flush();
+               // Set override file
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:lang/locallang_core.xlf'][$unique] = $file;
+               /** @var $store \TYPO3\CMS\Core\Localization\LanguageStore */
+               $store = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Localization\\LanguageStore');
+               $store->flushData('EXT:lang/locallang_core.xlf');
+               // Get override value
+               $overrideLL = $subject->getParsedData('EXT:lang/locallang_core.xlf', 'default', 'utf-8', 0);
+               // Clean up again
+               unlink($file);
+               $this->assertNotEquals($overrideLL['default']['buttons.logout'][0]['target'], '');
+               $this->assertNotEquals($defaultLL['default']['buttons.logout'][0]['target'], $overrideLL['default']['buttons.logout'][0]['target']);
+               $this->assertEquals($overrideLL['default']['buttons.logout'][0]['target'], 'EXIT');
+       }
+
+       /**
+        * @test
+        */
+       public function getParsedDataCallsLocalizationOverrideIfFileNotFoundExceptionIsThrown() {
+               /** @var LocalizationFactory|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $localizationFactory */
+               $localizationFactory = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Localization\\LocalizationFactory', array('localizationOverride'));
+               $languageStore = $this->getMock('TYPO3\\CMS\\Core\\Localization\\LanguageStore', array('hasData', 'setConfiguration', 'getData', 'setData'));
+               $cacheInstance = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\StringFrontend', array('get', 'set'), array(), '', FALSE);
+               $localizationFactory->_set('store', $languageStore);
+               $localizationFactory->_set('cacheInstance', $cacheInstance);
+               $languageStore->method('hasData')->willReturn(FALSE);
+               $languageStore->method('getData')->willReturn(array());
+               $languageStore->method('setConfiguration')->willThrowException(new FileNotFoundException());
+               $cacheInstance->method('get')->willReturn(FALSE);
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'] = array('foo' => 'bar');
+
+               $localizationFactory->expects($this->once())->method('localizationOverride');
+               $localizationFactory->getParsedData('EXT:backend/Resources/Private/Language/locallang_layout.xlf', 'default', 'utf-8', 0);
+       }
+
+}
index 4180e23..dacbfcf 100644 (file)
@@ -2605,44 +2605,6 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->assertSame('\'' . $expected . '\'', Utility\GeneralUtility::quoteJSvalue($input));
        }
 
-       //////////////////////////////////
-       // Tests concerning readLLfile
-       //////////////////////////////////
-       /**
-        * @test
-        */
-       public function readLLfileHandlesLocallangXMLOverride() {
-               $unique = 'locallangXMLOverrideTest' . substr($this->getUniqueId(), 0, 10);
-               $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-                       <T3locallang>
-                               <data type="array">
-                                       <languageKey index="default" type="array">
-                                               <label index="buttons.logout">EXIT</label>
-                                       </languageKey>
-                               </data>
-                       </T3locallang>';
-               $file = PATH_site . 'typo3temp/' . $unique . '.xml';
-               Utility\GeneralUtility::writeFileToTypo3tempDir($file, $xml);
-               // Make sure there is no cached version of the label
-               Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n')->flush();
-               // Get default value
-               $defaultLL = Utility\GeneralUtility::readLLfile('EXT:lang/locallang_core.xlf', 'default');
-               // Clear language cache again
-               Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n')->flush();
-               // Set override file
-               $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:lang/locallang_core.xlf'][$unique] = $file;
-               /** @var $store \TYPO3\CMS\Core\Localization\LanguageStore */
-               $store = Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Localization\\LanguageStore');
-               $store->flushData('EXT:lang/locallang_core.xlf');
-               // Get override value
-               $overrideLL = Utility\GeneralUtility::readLLfile('EXT:lang/locallang_core.xlf', 'default');
-               // Clean up again
-               unlink($file);
-               $this->assertNotEquals($overrideLL['default']['buttons.logout'][0]['target'], '');
-               $this->assertNotEquals($defaultLL['default']['buttons.logout'][0]['target'], $overrideLL['default']['buttons.logout'][0]['target']);
-               $this->assertEquals($overrideLL['default']['buttons.logout'][0]['target'], 'EXIT');
-       }
-
        ///////////////////////////////
        // Tests concerning _GETset()
        ///////////////////////////////