From 23efd87003a3705885645cb2cff0988f66927d4b Mon Sep 17 00:00:00 2001 From: mhofmann Date: Wed, 18 Dec 2024 12:34:57 +0100 Subject: [PATCH] [TASK] Change Dropdown rendering for translations Getting rid of x-classing is the goal and with v12 an event is provided manipulating the header of the RecordListController. In favour of using this event instead of x-classing the original class, an event listener is added generating the dropdown and adding top-most of the recordlist. This has effects on positioning of the translation dropdown, which now is rendered before the core dropdown instead of next to it. --- Build/phpstan/Core12/phpstan-baseline.neon | 130 -------------- .../Listener/RenderLocalizationSelect.php | 45 +++++ .../Event/RenderLocalizationSelectAllowed.php | 20 +++ Classes/Form/TranslationDropdownGenerator.php | 122 +++++++++++++ .../Core12/DeeplRecordListController.php | 168 ------------------ Classes/Service/DeeplService.php | 5 +- Classes/Utility/DeeplBackendUtility.php | 91 ---------- Configuration/Services.php | 74 -------- Configuration/Services.yaml | 54 ++++++ ext_localconf.php | 7 +- 10 files changed, 244 insertions(+), 472 deletions(-) create mode 100644 Classes/Event/Listener/RenderLocalizationSelect.php create mode 100644 Classes/Event/RenderLocalizationSelectAllowed.php create mode 100644 Classes/Form/TranslationDropdownGenerator.php delete mode 100644 Classes/Override/Core12/DeeplRecordListController.php create mode 100644 Configuration/Services.yaml diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index f10b4578..3bb73956 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -1,50 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryEntryRepository\\:\\:findEntriesByGlossary\\(\\) should return array\\ but returns array\\\\>\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryEntryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryEntryRepository\\:\\:findEntryByUid\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryEntryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossariesInRootByCurrentPage\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossary\\(\\) should return array\\{uid\\: int, glossary_name\\: string, glossary_id\\: string, glossary_lastsync\\: int, glossary_ready\\: int\\}\\|null but returns non\\-empty\\-array\\\\|null\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossaryBySourceAndTargetForSync\\(\\) should return array\\{uid\\: int, glossary_name\\: string, glossary_id\\: string, glossary_lastsync\\: int, glossary_ready\\: int\\} but returns array\\{glossary_name\\: non\\-falsy\\-string, glossary_id\\: '', glossary_lastsync\\: 0, glossary_ready\\: 0, source_lang\\: string, target_lang\\: string, uid\\: string\\}\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getLocalizedEntries\\(\\) should return array\\ but returns array\\\\>\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getOriginalEntries\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Parameter \\#3 \\$page of method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossaryBySourceAndTargetForSync\\(\\) expects array\\{uid\\: int, title\\: string\\}, array\\|null given\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - - message: "#^Cannot call method getRequestUri\\(\\) on TYPO3\\\\CMS\\\\Core\\\\Http\\\\NormalizedParams\\|null\\.$#" - count: 1 - path: ../../../Classes/Event/Listener/GlossarySyncButtonProvider.php - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Form\\\\Item\\\\SiteConfigSupportedLanguageItemsProcFunc\\:\\:getSupportedLanguageForField\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#" count: 1 @@ -60,26 +15,11 @@ parameters: count: 1 path: ../../../Classes/Hooks/ButtonBarHook.php - - - message: "#^Parameter \\#1 \\$uid of method WebVision\\\\Deepltranslate\\\\Core\\\\Domain\\\\Repository\\\\GlossaryEntryRepository\\:\\:findEntryByUid\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../Classes/Hooks/Glossary/UpdatedGlossaryEntryTermHook.php - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Override\\\\Core12\\\\DatabaseRecordList\\:\\:makeLocalizationPanel\\(\\) has parameter \\$translations with no value type specified in iterable type array\\.$#" count: 1 path: ../../../Classes/Override/Core12/DatabaseRecordList.php - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Override\\\\Core12\\\\DeeplRecordListController\\:\\:languageSelector\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: ../../../Classes/Override/Core12/DeeplRecordListController.php - - - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#" - count: 1 - path: ../../../Classes/Override/Core12/DeeplRecordListController.php - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Override\\\\LocalizationController\\:\\:process\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#" count: 1 @@ -95,11 +35,6 @@ parameters: count: 3 path: ../../../Classes/Override/LocalizationController.php - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Service\\\\DeeplGlossaryService\\:\\:getPossibleGlossaryLanguageConfig\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Classes/Service/DeeplGlossaryService.php - - message: "#^Property WebVision\\\\Deepltranslate\\\\Core\\\\Service\\\\LanguageService\\:\\:\\$possibleLangMatches type has no value type specified in iterable type array\\.$#" count: 1 @@ -140,21 +75,6 @@ parameters: count: 1 path: ../../../Classes/Utility/DeeplBackendUtility.php - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Utility\\\\DeeplBackendUtility\\:\\:buildTranslateDropdown\\(\\) has parameter \\$id with no type specified\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Utility\\\\DeeplBackendUtility\\:\\:buildTranslateDropdown\\(\\) has parameter \\$requestUri with no type specified\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Utility\\\\DeeplBackendUtility\\:\\:buildTranslateDropdown\\(\\) has parameter \\$siteLanguages with no type specified\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Utility\\\\HtmlUtility\\:\\:stripSpecificTags\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -235,56 +155,6 @@ parameters: count: 1 path: ../../../Tests/Functional/Hooks/TranslateHookTest.php - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildDefaultLanguageConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildErrorHandlingConfiguration\\(\\) has parameter \\$codes with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildErrorHandlingConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildLanguageConfiguration\\(\\) has parameter \\$fallbackIdentifiers with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildLanguageConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:failIfArrayIsNotEmpty\\(\\) has parameter \\$items with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:mergeSiteConfiguration\\(\\) has parameter \\$overrides with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$errorHandling with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$languages with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$site with no value type specified in iterable type array\\.$#" - count: 1 - path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php - - message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\LocalizationInlineRegressionTest\\:\\:buildDefaultLanguageConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 diff --git a/Classes/Event/Listener/RenderLocalizationSelect.php b/Classes/Event/Listener/RenderLocalizationSelect.php new file mode 100644 index 00000000..9097201d --- /dev/null +++ b/Classes/Event/Listener/RenderLocalizationSelect.php @@ -0,0 +1,45 @@ +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'], $request->getUri()); + if ($options !== '') { + $additionalHeader = '
' + . '
' + . '' + . '
' + . '
'; + $event->addContentAbove($additionalHeader); + } + } +} diff --git a/Classes/Event/RenderLocalizationSelectAllowed.php b/Classes/Event/RenderLocalizationSelectAllowed.php new file mode 100644 index 00000000..e5250b20 --- /dev/null +++ b/Classes/Event/RenderLocalizationSelectAllowed.php @@ -0,0 +1,20 @@ + $siteLanguages + * @throws \Doctrine\DBAL\Exception + * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException + */ + public function buildTranslateDropdownOptions( + $siteLanguages, + int $id, + string|UriInterface $requestUri + ): string { + $availableTranslations = []; + foreach ($siteLanguages as $siteLanguage) { + if ( + $siteLanguage->getLanguageId() === 0 + || $siteLanguage->getLanguageId() === -1 + ) { + continue; + } + $availableTranslations[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle(); + } + // Then, subtract the languages which are already on the page: + $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']; + $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField']; + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $queryBuilder->getRestrictions()->removeAll() + ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) + ->add( + GeneralUtility::makeInstance( + WorkspaceRestriction::class, + (int)$this->getBackendUser()?->workspace + ) + ); + $statement = $queryBuilder + ->select('uid', $languageField) + ->from('pages') + ->where( + $queryBuilder->expr()->eq( + $localizationParentField, + $queryBuilder->createNamedParameter($id, Connection::PARAM_INT) + ) + ) + ->executeQuery(); + while ($pageTranslation = $statement->fetchAssociative()) { + unset($availableTranslations[(int)$pageTranslation[$languageField]]); + } + // If any languages are left, make selector: + if (!empty($availableTranslations)) { + $output = ''; + foreach ($availableTranslations as $languageUid => $languageTitle) { + // check if language can be translated with DeepL + // otherwise continue to next + if (!DeeplBackendUtility::checkCanBeTranslated($id, $languageUid)) { + continue; + } + // Build localize command URL to DataHandler (tce_db) + // which redirects to FormEngine (record_edit) + // which, when finished editing should return back to the current page (returnUrl) + $parameters = [ + 'justLocalized' => 'pages:' . $id . ':' . $languageUid, + 'returnUrl' => (string)$requestUri, + ]; + $redirectUrl = DeeplBackendUtility::buildBackendRoute('record_edit', $parameters); + $params = []; + $params['redirect'] = $redirectUrl; + $params['cmd']['pages'][$id]['localize'] = $languageUid; + $params['cmd']['localization']['custom']['mode'] = 'deepl'; + $targetUrl = DeeplBackendUtility::buildBackendRoute('tce_db', $params); + $output .= ''; + } + if ($output !== '') { + $output = sprintf( + '%s', + htmlspecialchars($this->getLocalization()->sL('LLL:EXT:deepltranslate_core/Resources/Private/Language/locallang.xlf:backend.label')), + $output + ); + } + + return $output; + } + return ''; + } + + private function getLocalization(): LanguageService + { + return GeneralUtility::makeInstance(LanguageServiceFactory::class) + ->createFromUserPreferences($this->getBackendUser()); + } + + private function getBackendUser(): ?BackendUserAuthentication + { + return $GLOBALS['BE_USER'] ?? null; + } +} diff --git a/Classes/Override/Core12/DeeplRecordListController.php b/Classes/Override/Core12/DeeplRecordListController.php deleted file mode 100644 index adbc1748..00000000 --- a/Classes/Override/Core12/DeeplRecordListController.php +++ /dev/null @@ -1,168 +0,0 @@ -pageInfo['module'] === 'glossary') { - return $this->buildGlossaryTranslationOptionDropdown($siteLanguages, $requestUri); - } - $originalOutput = parent::languageSelector($siteLanguages, $requestUri); - - if ($originalOutput === '') { - return $originalOutput; - } - - if (!DeeplBackendUtility::isDeeplApiKeySet()) { - return $originalOutput; - } - - if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedTranslateAccess::ALLOWED_TRANSLATE_OPTION_VALUE)) { - return $originalOutput; - } - - $options = DeeplBackendUtility::buildTranslateDropdown( - $siteLanguages, - $this->id, - $requestUri - ); - - if ($options == '') { - return $originalOutput; - } - - return preg_replace( - '/<\/div>$/', - '
' - . '' - . '
' - . '', - $originalOutput - ); - } - - /** - * @param SiteLanguage[] $siteLanguages - * @throws \Doctrine\DBAL\Exception - * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException - * @throws \TYPO3\CMS\Core\Exception\SiteNotFoundException - */ - private function buildGlossaryTranslationOptionDropdown(array $siteLanguages, string $requestUri): string - { - if (!$this->getBackendUserAuthentication()->check('tables_modify', 'pages')) { - return ''; - } - - if (!$this->getBackendUserAuthentication()->check('custom_options', AllowedGlossarySyncAccess::ALLOWED_GLOSSARY_SYNC)) { - return ''; - } - - $glossaryService = GeneralUtility::makeInstance(DeeplGlossaryService::class); - $possiblePairs = $glossaryService->getPossibleGlossaryLanguageConfig(); - $site = GeneralUtility::makeInstance(SiteFinder::class) - ->getSiteByPageId($this->id); - $defaultLanguageIsoCode = $site->getDefaultLanguage()->getLocale()->getLanguageCode(); - - $possibleGlossaryEntryLanguages = $possiblePairs[$defaultLanguageIsoCode] ?? []; - - $availableTranslations = []; - foreach ($siteLanguages as $siteLanguage) { - if ($siteLanguage->getLanguageId() === 0) { - continue; - } - if (in_array($siteLanguage->getLocale()->getLanguageCode(), $possibleGlossaryEntryLanguages)) { - $availableTranslations[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle(); - } - } - - /** - * code copied from RecordListController - * @see RecordListController::languageSelector() - */ - // Then, subtract the languages which are already on the page: - $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']; - $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField']; - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); - $queryBuilder->getRestrictions()->removeAll() - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) - ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUserAuthentication()->workspace)); - $statement = $queryBuilder->select('uid', $languageField) - ->from('pages') - ->where( - $queryBuilder->expr()->eq( - $localizationParentField, - $queryBuilder->createNamedParameter($this->id, Connection::PARAM_INT) - ) - ) - ->executeQuery(); - while ($pageTranslation = $statement->fetchAssociative()) { - unset($availableTranslations[(int)$pageTranslation[$languageField]]); - } - // If any languages are left, make selector: - if (empty($availableTranslations)) { - return ''; - } - $output = ''; - - /** - * code copied from RecordListController - * @see RecordListController::languageSelector() - */ - foreach ($availableTranslations as $languageUid => $languageTitle) { - // Build localize command URL to DataHandler (tce_db) - // which redirects to FormEngine (record_edit) - // which, when finished editing should return back to the current page (returnUrl) - $parameters = [ - 'justLocalized' => 'pages:' . $this->id . ':' . $languageUid, - 'returnUrl' => $requestUri, - ]; - $redirectUrl = (string)$this->uriBuilder->buildUriFromRoute('record_edit', $parameters); - $params = []; - $params['redirect'] = $redirectUrl; - $params['cmd']['pages'][$this->id]['localize'] = $languageUid; - $targetUrl = (string)$this->uriBuilder->buildUriFromRoute('tce_db', $params); - $output .= ''; - } - - return '
' - . '
'; - } -} diff --git a/Classes/Service/DeeplService.php b/Classes/Service/DeeplService.php index 90b2a9ae..40e3aea7 100644 --- a/Classes/Service/DeeplService.php +++ b/Classes/Service/DeeplService.php @@ -225,10 +225,7 @@ private function loadSupportedLanguagesFromAPI(string $type = 'target'): array try { return $this->client->getSupportedLanguageByType($type); } catch (ApiKeyNotSetException $exception) { - // @todo Can be replaced with `$this->logger?->` when TYPO3 v11 and therefore PHP 7.4/8.0 support is dropped. - if ($this->logger !== null) { - $this->logger->error(sprintf('%s (%d)', $exception->getMessage(), $exception->getCode())); - } + $this->logger?->error(sprintf('%s (%d)', $exception->getMessage(), $exception->getCode())); return []; } } diff --git a/Classes/Utility/DeeplBackendUtility.php b/Classes/Utility/DeeplBackendUtility.php index 84509c83..b9fd64a8 100644 --- a/Classes/Utility/DeeplBackendUtility.php +++ b/Classes/Utility/DeeplBackendUtility.php @@ -7,11 +7,6 @@ use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; -use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Core\Database\Connection; -use TYPO3\CMS\Core\Database\ConnectionPool; -use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; -use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; @@ -27,7 +22,6 @@ use WebVision\Deepltranslate\Core\Service\LanguageService; use WebVision\Deepltranslate\Core\Service\ProcessingInstruction; - /** * Utility helper methods for DeepL-translate * @@ -130,86 +124,6 @@ public static function buildBackendRoute(string $route, array $parameters): stri return (string)$uriBuilder->buildUriFromRoute($route, $parameters); } - /** - * ToDo: Migrated function to own class object "WebVision\Deepltranslate\Core\Form\TranslationDropdownGenerator" - */ - public static function buildTranslateDropdown( - $siteLanguages, - $id, - $requestUri - ): string { - $availableTranslations = []; - foreach ($siteLanguages as $siteLanguage) { - if ( - $siteLanguage->getLanguageId() === 0 - || $siteLanguage->getLanguageId() === -1 - ) { - continue; - } - $availableTranslations[$siteLanguage->getLanguageId()] = $siteLanguage->getTitle(); - } - // Then, subtract the languages which are already on the page: - $localizationParentField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']; - $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField']; - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); - $queryBuilder->getRestrictions()->removeAll() - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) - ->add( - GeneralUtility::makeInstance( - WorkspaceRestriction::class, - (int)self::getBackendUserAuthentication()->workspace - ) - ); - $statement = $queryBuilder - ->select('uid', $languageField) - ->from('pages') - ->where( - $queryBuilder->expr()->eq( - $localizationParentField, - $queryBuilder->createNamedParameter($id, Connection::PARAM_INT) - ) - ) - ->executeQuery(); - while ($pageTranslation = $statement->fetchAssociative()) { - unset($availableTranslations[(int)$pageTranslation[$languageField]]); - } - // If any languages are left, make selector: - if (!empty($availableTranslations)) { - $output = ''; - foreach ($availableTranslations as $languageUid => $languageTitle) { - // check if language can be translated with DeepL - // otherwise continue to next - if (!DeeplBackendUtility::checkCanBeTranslated($id, $languageUid)) { - continue; - } - // Build localize command URL to DataHandler (tce_db) - // which redirects to FormEngine (record_edit) - // which, when finished editing should return back to the current page (returnUrl) - $parameters = [ - 'justLocalized' => 'pages:' . $id . ':' . $languageUid, - 'returnUrl' => $requestUri, - ]; - $redirectUrl = self::buildBackendRoute('record_edit', $parameters); - $params = []; - $params['redirect'] = $redirectUrl; - $params['cmd']['pages'][$id]['localize'] = $languageUid; - $params['cmd']['localization']['custom']['mode'] = 'deepl'; - $targetUrl = self::buildBackendRoute('tce_db', $params); - $output .= ''; - } - if ($output !== '') { - $output = sprintf( - '%s', - htmlspecialchars((string)LocalizationUtility::translate('backend.label', 'DeepltranslateCore')), - $output - ); - } - - return $output; - } - return ''; - } - public static function checkCanBeTranslated(int $pageId, int $languageId): bool { try { @@ -251,11 +165,6 @@ public static function detectCurrentPage(ProcessingInstruction $processingInstru return self::$currentPage; } - private static function getBackendUserAuthentication(): BackendUserAuthentication - { - return $GLOBALS['BE_USER']; - } - /** * @return array{uid: int, title: string}|null */ diff --git a/Configuration/Services.php b/Configuration/Services.php index ef47dc9e..07116698 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -4,70 +4,16 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; -use TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent; -use TYPO3\CMS\Core\Cache\CacheManager; -use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\DependencyInjection\SingletonPass; use TYPO3\CMS\Dashboard\WidgetRegistry; -use WebVision\Deepltranslate\Core\Client; -use WebVision\Deepltranslate\Core\ClientInterface; -use WebVision\Deepltranslate\Core\Controller\Backend\AjaxController; -use WebVision\Deepltranslate\Core\Event\Listener\RenderTranslatedFlagInFrontendPreviewMode; -use WebVision\Deepltranslate\Core\Event\Listener\UsageToolBarEventListener; use WebVision\Deepltranslate\Core\Form\Item\SiteConfigSupportedLanguageItemsProcFunc; use WebVision\Deepltranslate\Core\Form\User\HasFormalitySupport; use WebVision\Deepltranslate\Core\Hooks\TranslateHook; -use WebVision\Deepltranslate\Core\Hooks\UsageProcessAfterFinishHook; -use WebVision\Deepltranslate\Core\Service\DeeplService; -use WebVision\Deepltranslate\Core\Service\IconOverlayGenerator; -use WebVision\Deepltranslate\Core\Service\LanguageService; -use WebVision\Deepltranslate\Core\Service\ProcessingInstruction; -use WebVision\Deepltranslate\Core\Service\UsageService; use WebVision\Deepltranslate\Core\Widgets\UsageWidget; return function (ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder) { $services = $containerConfigurator ->services(); - $services->defaults() - ->autowire() - ->autoconfigure(); - - // Main DI - $services - ->load('WebVision\\Deepltranslate\\Core\\', '../Classes/') - ->exclude('../Classes/{Domain/Model,Override/Core12}'); - - // add caching - $services->set('cache.wvdeepltranslate') - ->class(FrontendInterface::class) - ->factory([service(CacheManager::class), 'getCache']) - ->args(['wvdeepltranslate']); - - $services - ->set(ProcessingInstruction::class) - ->arg('$runtimeCache', service('cache.runtime')); - $services - ->set(DeeplService::class) - ->public() - ->arg('$cache', service('cache.wvdeepltranslate')); - $services - ->set(LanguageService::class) - ->public(); - $services - ->set(IconOverlayGenerator::class) - ->public(); - $services - ->set(UsageService::class) - ->public(); - $services - ->set(UsageProcessAfterFinishHook::class) - ->public(); - - $services - ->set(AjaxController::class) - ->public(); - - $services->alias(ClientInterface::class, Client::class); $containerBuilder ->registerForAutoconfiguration(TranslateHook::class) @@ -86,26 +32,6 @@ $containerBuilder ->addCompilerPass(new SingletonPass('deepl.HasFormalitySupport')); - // register Events - $services - ->set(UsageToolBarEventListener::class) - ->tag( - 'event.listener', - [ - 'identifier' => 'deepl.usages', - 'event' => SystemInformationToolbarCollectorEvent::class, - ] - ); - - $services - ->set(RenderTranslatedFlagInFrontendPreviewMode::class) - ->tag( - 'event.listener', - [ - 'identifier' => 'deepltranslate-core/render-translated-flag-in-frontend-preview-mode', - ] - ); - /** * Check if WidgetRegistry is defined, which means that EXT:dashboard is available. * Registration directly in Services.yaml will break without EXT:dashboard installed! diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 00000000..4f6e1609 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,54 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + WebVision\Deepltranslate\Core\: + resource: '../Classes/*' + exclude: '../Classes/{Domain/Model,Override/Core12}' + + cache.deepltranslateCore: + class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface + factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] + arguments: ['deepltranslate_core'] + + WebVision\Deepltranslate\Core\Service\: + resource: '../Classes/Service/*' + public: true + + WebVision\Deepltranslate\Core\Hooks\: + resource: '../Classes/Hooks/*' + public: true + + WebVision\Deepltranslate\Core\Service\ProcessingInstruction: + arguments: + $runtimeCache: '@cache.runtime' + + WebVision\Deepltranslate\Core\Service\DeeplService: + public: true + arguments: + $cache: '@cache.deepltranslateCore' + + WebVision\Deepltranslate\Core\Controller\Backend\AjaxController: + public: true + + 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' + identifier: 'deepltranslate-core/render-translated-flag-in-frontend-preview-mode' + + WebVision\Deepltranslate\Core\Event\Listener\UsageToolBarEventListener: + tags: + - name: 'event.listener' + identifier: 'deepltranslate-core/usages' + event: TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent diff --git a/ext_localconf.php b/ext_localconf.php index 02bb21dc..e3e7583b 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -28,9 +28,6 @@ 'className' => \WebVision\Deepltranslate\Core\Override\LocalizationController::class, ]; - $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Backend\Controller\RecordListController::class] = [ - 'className' => \WebVision\Deepltranslate\Core\Override\Core12\DeeplRecordListController::class, - ]; //xclass databaserecordlist for rendering custom checkboxes to toggle deepl selection in recordlist $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Backend\RecordList\DatabaseRecordList::class] = [ 'className' => \WebVision\Deepltranslate\Core\Override\Core12\DatabaseRecordList::class, @@ -52,9 +49,9 @@ = \WebVision\Deepltranslate\Core\Hooks\PageRendererHook::class . '->renderPreProcess'; //add caching for DeepL API-supported Languages - $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['wvdeepltranslate'] + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['deepltranslate_core'] ??= []; - $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['wvdeepltranslate']['backend'] + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['deepltranslate_core']['backend'] ??= \TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend::class; $accessRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\WebVision\Deepltranslate\Core\Access\AccessRegistry::class);