From 64f4d35f3c655d99c02850fc7a5a672c3146316c Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Mon, 30 Jun 2025 10:01:31 +0200 Subject: [PATCH] [WIP][FEATURE] Make DeepL translation TSconfig configurable Following the example of TYPO3's Page TSConfig settings, DeepL should also allow settings to be made via Page TSConfig. This makes it easier for integrators to use and provides a better overview, as the settings are made in the same way as for TYPO3 Core. New: ``` mod { web_layout { localization { # default, set to 0 to disable DeepL Translate enableDeeplTranslate = 1 # default, set to 1 to disable core translation options disableCoreTranslation = 0 } } } ``` --- Classes/Configuration.php | 42 ++++++++++ Classes/ConfigurationInterface.php | 3 + .../ApplyLocalizationModesEventListener.php | 23 +++++- ...ecordListLanguageDropdownEventListener.php | 80 +++++++++++++++++++ .../Listener/RenderLocalizationSelect.php | 45 ----------- .../Event/RenderLocalizationSelectAllowed.php | 2 + Configuration/Services.yaml | 12 +-- 7 files changed, 152 insertions(+), 55 deletions(-) create mode 100644 Classes/Event/Listener/ModifyRecordListLanguageDropdownEventListener.php delete mode 100644 Classes/Event/Listener/RenderLocalizationSelect.php diff --git a/Classes/Configuration.php b/Classes/Configuration.php index 087c5423..5f8fed3f 100644 --- a/Classes/Configuration.php +++ b/Classes/Configuration.php @@ -5,10 +5,12 @@ namespace WebVision\Deepltranslate\Core; use Symfony\Component\DependencyInjection\Attribute\AsAlias; +use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException; use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationPathDoesNotExistException; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\MathUtility; #[AsAlias(id: ConfigurationInterface::class, public: true)] final class Configuration implements ConfigurationInterface @@ -30,4 +32,44 @@ public function getApiKey(): string { return $this->apiKey; } + + public function isDeeplTranslateAllowed(int $pageId): bool + { + $pageTsConfig = BackendUtility::getPagesTSconfig($pageId); + if (!is_array($pageTsConfig['mod.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.']['localization.'] ?? null) + || !( + is_bool($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + || is_int($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + || ( + is_string($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + && MathUtility::canBeInterpretedAsInteger($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate']) + ) + ) + ) { + return true; + } + return (bool)$pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate']; + } + + public function isCoreTranslationDisabled(int $pageId): bool + { + $pageTsConfig = BackendUtility::getPagesTSconfig($pageId); + if (!is_array($pageTsConfig['mod.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.']['localization.'] ?? null) + || !( + is_bool($pageTsConfig['mod.']['web_layout.']['localization.']['disableCoreTranslation'] ?? null) + || is_int($pageTsConfig['mod.']['web_layout.']['localization.']['disableCoreTranslation'] ?? null) + || ( + is_string($pageTsConfig['mod.']['web_layout.']['localization.']['disableCoreTranslation'] ?? null) + && MathUtility::canBeInterpretedAsInteger($pageTsConfig['mod.']['web_layout.']['localization.']['disableCoreTranslation']) + ) + ) + ) { + return false; + } + return (bool)$pageTsConfig['mod.']['web_layout.']['localization.']['disableCoreTranslation']; + } } diff --git a/Classes/ConfigurationInterface.php b/Classes/ConfigurationInterface.php index f08874de..8d3d03f1 100644 --- a/Classes/ConfigurationInterface.php +++ b/Classes/ConfigurationInterface.php @@ -13,4 +13,7 @@ interface ConfigurationInterface { public function getApiKey(): string; + public function isDeeplTranslateAllowed(int $pageId): bool; + + public function isCoreTranslationDisabled(int $pageId): bool; } diff --git a/Classes/Event/Listener/ApplyLocalizationModesEventListener.php b/Classes/Event/Listener/ApplyLocalizationModesEventListener.php index b7cded6f..276f118d 100644 --- a/Classes/Event/Listener/ApplyLocalizationModesEventListener.php +++ b/Classes/Event/Listener/ApplyLocalizationModesEventListener.php @@ -5,6 +5,7 @@ namespace WebVision\Deepltranslate\Core\Event\Listener; use TYPO3\CMS\Core\Information\Typo3Version; +use TYPO3\CMS\Core\Utility\MathUtility; use WebVision\Deepl\Base\Controller\Backend\LocalizationController; use WebVision\Deepl\Base\Event\GetLocalizationModesEvent; use WebVision\Deepl\Base\Localization\LocalizationMode; @@ -27,7 +28,7 @@ public function __invoke(GetLocalizationModesEvent $event): void description: $event->getLanguageService()->sL('LLL:EXT:deepltranslate_core/Resources/Private/Language/locallang.xlf:localize.educate.deepltranslate'), icon: ($majorVersion === 13 ? 'actions-localize-deepl-13' : 'actions-localize-deepl'), before: [], - after: ['translate', 'copy'], + after: [LocalizationController::ACTION_LOCALIZE, LocalizationController::ACTION_COPY], ); } if ($this->allowDeeplTranslateAuto($event)) { @@ -38,7 +39,7 @@ public function __invoke(GetLocalizationModesEvent $event): void description: $event->getLanguageService()->sL('LLL:EXT:deepltranslate_core/Resources/Private/Language/locallang.xlf:localize.educate.deepltranslateAuto'), icon: ($majorVersion === 13 ? 'actions-localize-deepl-13' : 'actions-localize-deepl'), before: [], - after: ['translate', 'copy', 'deepltranslate'], + after: [LocalizationController::ACTION_LOCALIZE, LocalizationController::ACTION_COPY, 'deepltranslate'], ); } if ($modes !== []) { @@ -48,8 +49,22 @@ public function __invoke(GetLocalizationModesEvent $event): void private function allowDeeplTranslate(GetLocalizationModesEvent $event): bool { - // @todo Prepared for PageTSConfig feature to toggle `deepltranslate`. - return true; + $pageTsConfig = $event->getPageTsConfig(); + if (!is_array($pageTsConfig['mod.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.'] ?? null) + || !is_array($pageTsConfig['mod.']['web_layout.']['localization.'] ?? null) + || !( + is_bool($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + || is_int($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + || ( + is_string($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate'] ?? null) + && MathUtility::canBeInterpretedAsInteger($pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate']) + ) + ) + ) { + return true; + } + return (bool)$pageTsConfig['mod.']['web_layout.']['localization.']['enableDeeplTranslate']; } private function allowDeeplTranslateAuto(GetLocalizationModesEvent $event): bool diff --git a/Classes/Event/Listener/ModifyRecordListLanguageDropdownEventListener.php b/Classes/Event/Listener/ModifyRecordListLanguageDropdownEventListener.php new file mode 100644 index 00000000..505d8114 --- /dev/null +++ b/Classes/Event/Listener/ModifyRecordListLanguageDropdownEventListener.php @@ -0,0 +1,80 @@ +getIdentifier() !== 'core-template-recordlist') { + return; + } + + $coreLanguageSelectorHtml = $event->getGlobalVariableProvider()->get('languageSelectorHtml'); + // means, no translations available, we can abort here. + if ($coreLanguageSelectorHtml === '') { + return; + } + $currentPageId = $event->getGlobalVariableProvider()->get('pageId'); + if (!$this->configuration->isDeeplTranslateAllowed($currentPageId)) { + return; + } + if ($this->configuration->isCoreTranslationDisabled($currentPageId)) { + $coreLanguageSelectorHtml = ''; + } else { + $coreLanguageSelectorHtml = str_replace('
', '', $coreLanguageSelectorHtml); + $coreLanguageSelectorHtml = substr($coreLanguageSelectorHtml, 0, (strlen($coreLanguageSelectorHtml) - strlen('
'))); + } + + $request = $GLOBALS['TYPO3_REQUEST'] ?? null; + + $deeplLanguageSelectorHtml = ''; + $site = $this->siteFinder->getSiteByPageId($currentPageId); + $siteLanguages = $site->getLanguages(); + $options = $this->generator->buildTranslateDropdownOptions($siteLanguages, $currentPageId, $request->getUri()); + if ($options !== '') { + $deeplLanguageSelectorHtml = '
' + . '
' + . '' + . '' + . '
' + . '
'; + } + + $event->getGlobalVariableProvider()->add( + 'languageSelectorHtml', + sprintf('
%s %s
', $coreLanguageSelectorHtml, $deeplLanguageSelectorHtml) + ); + } + + private function getLanguageService(): LanguageService + { + return $GLOBALS['LANG'] ?? GeneralUtility::makeInstance(LanguageServiceFactory::class) + ->createFromUserPreferences($GLOBALS['USER'] ?? null); + } +} diff --git a/Classes/Event/Listener/RenderLocalizationSelect.php b/Classes/Event/Listener/RenderLocalizationSelect.php deleted file mode 100644 index 7565e9a9..00000000 --- a/Classes/Event/Listener/RenderLocalizationSelect.php +++ /dev/null @@ -1,45 +0,0 @@ -getRequest(); - // Check, if some event listener doesn't allow rendering here. - // For use cases see Event - $renderingAllowedEvent = $this->eventDispatcher->dispatch(new RenderLocalizationSelectAllowed($request)); - if ($renderingAllowedEvent->renderingAllowed === false) { - return; - } - /** @var Site $site */ - $site = $request->getAttribute('site'); - $siteLanguages = $site->getLanguages(); - $options = $this->generator->buildTranslateDropdownOptions($siteLanguages, (int)($request->getQueryParams()['id'] ?? 0), $request->getUri()); - if ($options !== '') { - $additionalHeader = '
' - . '
' - . '' - . '
' - . '
'; - $event->addContentAbove($additionalHeader); - } - } -} diff --git a/Classes/Event/RenderLocalizationSelectAllowed.php b/Classes/Event/RenderLocalizationSelectAllowed.php index e5250b20..27d5fee0 100644 --- a/Classes/Event/RenderLocalizationSelectAllowed.php +++ b/Classes/Event/RenderLocalizationSelectAllowed.php @@ -9,6 +9,8 @@ /** * Event deciding if the localization dropdown should be rendered. * Could be used avoiding rendering for special cases, e.g., glossary or access denied. + * + * @deprecated Use page TS config options instead */ final class RenderLocalizationSelectAllowed { diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index f6dd83f1..5644133e 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -36,12 +36,6 @@ services: WebVision\Deepltranslate\Core\ClientInterface: class: WebVision\Deepltranslate\Core\Client - WebVision\Deepltranslate\Core\Event\Listener\RenderLocalizationSelect: - tags: - - name: 'event.listener' - identifier: 'deepltranslate/coreSelector' - event: TYPO3\CMS\Backend\Controller\Event\RenderAdditionalContentToRecordListEvent - WebVision\Deepltranslate\Core\Event\Listener\RenderTranslatedFlagInFrontendPreviewMode: tags: - name: 'event.listener' @@ -74,3 +68,9 @@ services: identifier: 'deepltranslate-core/translation-dropdown' event: WebVision\Deepl\Base\Event\ViewHelpers\ModifyInjectVariablesViewHelperEvent after: 'deepl-base/default-translation' + + WebVision\Deepltranslate\Core\Event\Listener\ModifyRecordListLanguageDropdownEventListener: + tags: + - name: 'event.listener' + identifier: 'deepltranslate-core/translation-dropdown-recordlist' + event: WebVision\Deepl\Base\Event\ViewHelpers\ModifyInjectVariablesViewHelperEvent