From c607d319f16eada816a3d200c9a43658f376ab9b Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Mon, 24 Apr 2023 10:10:02 +0200 Subject: [PATCH] [TASK] Deprecate various language-related methods and properties The following methods and properties have been deprecated: * Argument $alternativeLanguageKeys in LocalizationUtility::translate() * <f:translate> ViewHelper argument "alternativeLanguageKeys" * LanguageService->getLL() The method "LanguageService->includeLLFile()" is marked as internal. This is done in order to streamline future development in label-related areas. Resolves: #100721 Releases: main Change-Id: I1a0bc2eab61ec807cb43082dfef2361dbe6b185f Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78799 Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: core-ci <typo3@b13.com> Tested-by: Benni Mack <benni@typo3.org> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Oliver Bartsch <bo@cedev.de> Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: Oliver Klee <typo3-coding@oliverklee.de> --- .../Classes/RecordList/DatabaseRecordList.php | 4 +- .../Classes/Localization/LanguageService.php | 3 + ...100721-LabelRelatedMethodsAndArguments.rst | 74 ++++++++++++ .../Classes/Utility/LocalizationUtility.php | 20 ++-- .../Utility/LocalizationUtilityTest.php | 9 -- .../Utility/LocalizationUtilityTest.php | 108 ++++++++++++++++++ .../ViewHelpers/TranslateViewHelper.php | 5 +- .../MethodArgumentDroppedStaticMatcher.php | 6 + .../Php/MethodCallMatcher.php | 7 ++ 9 files changed, 216 insertions(+), 20 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100721-LabelRelatedMethodsAndArguments.rst create mode 100644 typo3/sysext/extbase/Tests/FunctionalDeprecated/Utility/LocalizationUtilityTest.php diff --git a/typo3/sysext/backend/Classes/RecordList/DatabaseRecordList.php b/typo3/sysext/backend/Classes/RecordList/DatabaseRecordList.php index 6663e20092c1..ab741ff11074 100644 --- a/typo3/sysext/backend/Classes/RecordList/DatabaseRecordList.php +++ b/typo3/sysext/backend/Classes/RecordList/DatabaseRecordList.php @@ -622,11 +622,11 @@ class DatabaseRecordList $icon = $this->table // @todo separate table header from contract/expand link ? $this->iconFactory ->getIcon('actions-view-table-collapse', Icon::SIZE_SMALL) - ->setTitle($lang->getLL('contractView')) + ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:contractView')) ->render() : $this->iconFactory ->getIcon('actions-view-table-expand', Icon::SIZE_SMALL) - ->setTitle($lang->getLL('expandView')) + ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:expandView')) ->render(); $theData[$titleCol] = $this->linkWrapTable($table, $tableTitle . ' (<span class="t3js-table-total-items">' . $totalItems . '</span>) ' . $icon); } diff --git a/typo3/sysext/core/Classes/Localization/LanguageService.php b/typo3/sysext/core/Classes/Localization/LanguageService.php index 6ca4b861028d..27ca8dc18aa6 100644 --- a/typo3/sysext/core/Classes/Localization/LanguageService.php +++ b/typo3/sysext/core/Classes/Localization/LanguageService.php @@ -128,9 +128,11 @@ class LanguageService * * @param string $index Label key * @return string + * @deprecated will be removed in TYPO3 v13.0. Use sL() instead. */ public function getLL($index) { + trigger_error('Calling LanguageService->getLL() will be removed in TYPO3 v13.0. Use LanguageService->sL() instead.', E_USER_DEPRECATED); return $this->getLLL($index, $this->labels); } @@ -216,6 +218,7 @@ class LanguageService * * @param string $fileRef $fileRef is a file-reference * @return array returns the loaded label file + * @internal do not rely on this method as it is only used for internal purposes in TYPO3 v13.0. */ public function includeLLFile(string $fileRef): array { diff --git a/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100721-LabelRelatedMethodsAndArguments.rst b/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100721-LabelRelatedMethodsAndArguments.rst new file mode 100644 index 000000000000..aaae92cbbf7b --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/12.4/Deprecation-100721-LabelRelatedMethodsAndArguments.rst @@ -0,0 +1,74 @@ +.. include:: /Includes.rst.txt + +.. _deprecation-100721-1682333511: + +========================================================== +Deprecation: #100721 - Label-related methods and arguments +========================================================== + +See :issue:`100721` + +Description +=========== + +The method :php:`TYPO3\CMS\Core\Localization\LanguageService->getLL()` has been +marked as deprecated. + +Along with the deprecation the method +:php:`TYPO3\CMS\Core\Localization\LanguageService->includeLLFile()` has been +marked as internal, as it is still used in TYPO3 core for backwards-compatibility +internally, but not part of TYPO3's Core API anymore. + +With the introduction of Locales, it is also now not recommended anymore to use +custom alternative language keys. + +For this reason the argument "alternativeLanguageKeys" of the +:html:`<f:translate>` ViewHelper has been deprecated as well, along with the +method argument of the same name in +:php:`TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate()`. + + +Impact +====== + +Calling the method :php:`TYPO3\CMS\Core\Localization\LanguageService->getLL()` +will trigger a PHP deprecation warning. + +Calling :php:`TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate()` with +the argument "alternativeLanguageKeys" will also trigger a PHP deprecation warning, +which is the underlying deprecation warning when using the argument +"alternativeLanguageKeys" of the :html:`<f:translate>` ViewHelper. + + +Affected installations +====================== + +TYPO3 installations within Backend modules using the method :php:`getLL()` or +extensions or templates using the translate methods. + +The former usually happens in extensions which have been migrated from older +TYPO3 versions with legacy functionality in Backend modules along +with :php:`$GLOBALS['LANG']` as LanguageService object. + + +Migration +========= + +It is highly recommended to use the full path to a label file along +with the :php:`sL()` method of :php:`TYPO3\CMS\Core\Localization\LanguageService`: + +Before: + +.. code-block:: php + + $GLOBALS['LANG']->includeLLfile('EXT:my_extension/Resources/Private/Language/db.xlf'); + $label = htmlspecialchars($GLOBALS['LANG']->getLL('my_label')); + +After: + +.. code-block:: php + + $label = $GLOBALS['LANG']->sL('LLL:EXT:my_extension/Resources/Private/Language/db.xlf:my_label'); + $label = htmlspecialchars($label); + +.. index:: PHP-API, PartiallyScanned, ext:core diff --git a/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php b/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php index 6c1147cf4a02..bdf27ea4a0e3 100644 --- a/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php +++ b/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php @@ -34,10 +34,7 @@ use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; */ class LocalizationUtility { - /** - * @var string - */ - protected static $locallangPath = 'Resources/Private/Language/'; + protected static string $locallangPath = 'Resources/Private/Language/'; /** * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface @@ -50,11 +47,11 @@ class LocalizationUtility * @param string $key The key from the LOCAL_LANG array for which to return the value. * @param string|null $extensionName The name of the extension * @param array|null $arguments The arguments of the extension, being passed over to sprintf - * @param string|null $languageKey The language key or null for using the current language from the system - * @param string[]|null $alternativeLanguageKeys The alternative language keys if no translation was found. + * @param Locale|string|null $languageKey The language key or null for using the current language from the system + * @param string[]|null $alternativeLanguageKeys The alternative language keys if no translation was found. @deprecated will be removed in TYPO3 v12.0 * @return string|null The value from LOCAL_LANG or null if no translation was found. */ - public static function translate(string $key, ?string $extensionName = null, array $arguments = null, string $languageKey = null, array $alternativeLanguageKeys = null): ?string + public static function translate(string $key, ?string $extensionName = null, array $arguments = null, Locale|string $languageKey = null, array $alternativeLanguageKeys = null): ?string { if ($key === '') { // Early return guard: returns null if the key was empty, because the key may be a dynamic value @@ -78,6 +75,15 @@ class LocalizationUtility if ($languageKey === null) { $languageKey = static::getLanguageKey(); } + if ($alternativeLanguageKeys !== null && $alternativeLanguageKeys !== []) { + trigger_error('Calling LocalizationUtility::translate() with the argument $alternativeLanguageKeys will be removed in TYPO3 v13.0. Use Locales instead.', E_USER_DEPRECATED); + } + if ($languageKey instanceof Locale) { + if ($alternativeLanguageKeys !== null && $alternativeLanguageKeys !== []) { + $alternativeLanguageKeys = $languageKey->getDependencies(); + } + $languageKey = (string)$languageKey; + } $languageService = static::initializeLocalization($languageFilePath, $languageKey, $alternativeLanguageKeys, $extensionName); $resolvedLabel = $languageService->sL('LLL:' . $languageFilePath . ':' . $key); $value = $resolvedLabel !== '' ? $resolvedLabel : null; diff --git a/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php b/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php index bb880ce5c9a2..db9b90570a01 100644 --- a/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php +++ b/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php @@ -115,15 +115,6 @@ final class LocalizationUtilityTest extends FunctionalTestCase 'placeholder and empty arguments in translation' => ['keyWithPlaceholderAndNoArguments', 'da', '%d-%m-%Y', [], []], - - 'get translated key from primary language' => - ['key1', 'da', 'Dansk label for key1', ['da_alt']], - - 'fallback to alternative language if translation is missing' => - ['key2', 'da', 'Dansk alternative label for key2', ['da_alt']], - - 'fallback to English for label not translated in da and da_alt' => - ['key3', 'da', 'English label for key3', ['da_alt']], ]; } diff --git a/typo3/sysext/extbase/Tests/FunctionalDeprecated/Utility/LocalizationUtilityTest.php b/typo3/sysext/extbase/Tests/FunctionalDeprecated/Utility/LocalizationUtilityTest.php new file mode 100644 index 000000000000..dfde867cdd82 --- /dev/null +++ b/typo3/sysext/extbase/Tests/FunctionalDeprecated/Utility/LocalizationUtilityTest.php @@ -0,0 +1,108 @@ +<?php + +declare(strict_types=1); + +/* + * 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! + */ + +namespace TYPO3\CMS\Extbase\Tests\FunctionalDeprecated\Utility; + +use PHPUnit\Framework\MockObject\MockObject; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Extbase\Utility\LocalizationUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; + +final class LocalizationUtilityTest extends FunctionalTestCase +{ + protected ConfigurationManagerInterface&MockObject $configurationManagerInterfaceMock; + + protected array $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/label_test']; + + protected function setUp(): void + { + parent::setUp(); + $reflectionClass = new \ReflectionClass(LocalizationUtility::class); + $this->configurationManagerInterfaceMock = $this->createMock(ConfigurationManagerInterface::class); + $property = $reflectionClass->getProperty('configurationManager'); + $property->setValue($this->configurationManagerInterfaceMock); + } + + /** + * Reset static properties + */ + protected function tearDown(): void + { + $reflectionClass = new \ReflectionClass(LocalizationUtility::class); + $property = $reflectionClass->getProperty('configurationManager'); + $property->setValue(null); + parent::tearDown(); + } + + public static function translateDataProvider(): array + { + return [ + 'get translated key from primary language' => + ['key1', 'da', 'Dansk label for key1', ['da_alt']], + + 'fallback to alternative language if translation is missing' => + ['key2', 'da', 'Dansk alternative label for key2', ['da_alt']], + + 'fallback to English for label not translated in da and da_alt' => + ['key3', 'da', 'English label for key3', ['da_alt']], + ]; + } + + /** + * @dataProvider translateDataProvider + * @test + */ + public function translateTestWithBackendUserLanguage( + string $key, + string $languageKey, + string $expected, + array $altLanguageKeys = [], + array $arguments = null + ): void { + // No TypoScript overrides + $this->configurationManagerInterfaceMock + ->method('getConfiguration') + ->with('Framework', 'label_test', null) + ->willReturn([]); + + $GLOBALS['BE_USER'] = new BackendUserAuthentication(); + $GLOBALS['BE_USER']->user = ['lang' => $languageKey]; + self::assertSame($expected, LocalizationUtility::translate($key, 'label_test', $arguments, alternativeLanguageKeys: $altLanguageKeys)); + } + + /** + * @dataProvider translateDataProvider + * @test + */ + public function translateTestWithExplicitLanguageParameters( + string $key, + string $languageKey, + string $expected, + array $altLanguageKeys = [], + array $arguments = null + ): void { + // No TypoScript overrides + $this->configurationManagerInterfaceMock + ->method('getConfiguration') + ->with('Framework', 'label_test', null) + ->willReturn([]); + + self::assertSame($expected, LocalizationUtility::translate($key, 'label_test', $arguments, $languageKey, $altLanguageKeys)); + } + +} diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php index 724d32b060fc..894e599453b9 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php @@ -123,7 +123,8 @@ final class TranslateViewHelper extends AbstractViewHelper $this->registerArgument('arguments', 'array', 'Arguments to be replaced in the resulting string'); $this->registerArgument('extensionName', 'string', 'UpperCamelCased extension key (for example BlogExample)'); $this->registerArgument('languageKey', 'string', 'Language key ("da" for example) or "default" to use. If empty, use current language. Ignored in non-extbase context.'); - $this->registerArgument('alternativeLanguageKeys', 'array', 'Alternative language keys if no translation does exist. Ignored in non-extbase context.'); + // @deprecated will be removed in TYPO3 v13.0. Deprecation is triggered in LocalizationUtility + $this->registerArgument('alternativeLanguageKeys', 'array', 'Alternative language keys if no translation does exist. Ignored in non-extbase context. Deprecated, will be removed in TYPO3 v13.0'); } /** @@ -196,7 +197,7 @@ final class TranslateViewHelper extends AbstractViewHelper // overloads from _LOCAL_LANG extbase TypoScript settings if specified. // Not this triggers TypoScript parsing via extbase ConfigurationManager // and should be avoided in backend context! - $value = LocalizationUtility::translate($id, $extensionName, $translateArguments, $arguments['languageKey'], $arguments['alternativeLanguageKeys'] ?? []); + $value = LocalizationUtility::translate($id, $extensionName, $translateArguments, $arguments['languageKey'], $arguments['alternativeLanguageKeys'] ?? null); } catch (\InvalidArgumentException $e) { // @todo: Switch to more specific Exceptions here - for instance those thrown when a package was not found, see #95957 $value = null; diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedStaticMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedStaticMatcher.php index a83d0e374eba..ae399d2f668b 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedStaticMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedStaticMatcher.php @@ -95,4 +95,10 @@ return [ 'Breaking-98069-DebugConsoleRemoved.rst', ], ], + 'TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate' => [ + 'maximumNumberOfArguments' => 4, + 'restFiles' => [ + 'Deprecation-100721-LabelRelatedMethodsAndArguments.rst', + ], + ], ]; diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php index 1f222e0b164a..01666eec3494 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php @@ -5715,4 +5715,11 @@ return [ 'Deprecation-100622-ExtbaseFeatureToggles.rst', ], ], + 'TYPO3\CMS\Core\Localization\LanguageService->getLL' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-100721-LabelRelatedMethodsAndArguments.rst', + ], + ], ]; -- GitLab