diff --git a/Build/phpstan/Core11/phpstan-baseline.neon b/Build/phpstan/Core11/phpstan-baseline.neon index a97d8e19..89346688 100644 --- a/Build/phpstan/Core11/phpstan-baseline.neon +++ b/Build/phpstan/Core11/phpstan-baseline.neon @@ -10,6 +10,11 @@ parameters: count: 1 path: ../../../Classes/Domain/Repository/GlossaryEntryRepository.php + - + message: "#^Cannot call method getLanguageCode\\(\\) on string\\.$#" + count: 2 + path: ../../../Classes/Domain/Repository/GlossaryRepository.php + - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossariesInRootByCurrentPage\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -40,11 +45,6 @@ parameters: count: 1 path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - message: "#^Parameter \\#3 \\$pageUid of method WebVision\\\\WvDeepltranslate\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossary\\(\\) expects int, array\\|float\\|int\\|string\\|false\\|null given\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - message: "#^Call to method getButtonBar\\(\\) on an unknown class TYPO3\\\\CMS\\\\Backend\\\\Template\\\\Components\\\\ModifyButtonBarEvent\\.$#" count: 1 @@ -200,21 +200,6 @@ parameters: count: 1 path: ../../../Classes/Utility/DeeplBackendUtility.php - - - message: "#^Offset 'pid' does not exist on array\\|null\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Parameter \\#1 \\$id of static method WebVision\\\\WvDeepltranslate\\\\Utility\\\\DeeplBackendUtility\\:\\:getPageRecord\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Parameter \\#2 \\$id of static method WebVision\\\\WvDeepltranslate\\\\Utility\\\\DeeplBackendUtility\\:\\:getPageIdFromRecord\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Utility\\\\HtmlUtility\\:\\:stripSpecificTags\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -320,6 +305,76 @@ parameters: count: 1 path: ../../../Tests/Functional/Hooks/TranslateHookTest.php + - + message: "#^Class TYPO3\\\\CMS\\\\Core\\\\Configuration\\\\SiteConfiguration constructor invoked with 3 parameters, 1\\-2 required\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + + - + message: "#^Method WebVision\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildSiteConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + + - + message: "#^Method WebVision\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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: "#^Parameter \\#1 \\$current of method WebVision\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:mergeInstruction\\(\\) expects TYPO3\\\\TestingFramework\\\\Core\\\\Functional\\\\Framework\\\\Frontend\\\\Internal\\\\AbstractInstruction, TYPO3\\\\TestingFramework\\\\Core\\\\Functional\\\\Framework\\\\Frontend\\\\Internal\\\\AbstractInstruction\\|null given\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + + - + message: "#^Parameter \\#2 \\$coreCache of class TYPO3\\\\CMS\\\\Core\\\\Configuration\\\\SiteConfiguration constructor expects TYPO3\\\\CMS\\\\Core\\\\Cache\\\\Frontend\\\\PhpFrontend\\|null, Psr\\\\EventDispatcher\\\\EventDispatcherInterface given\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + - message: "#^Cannot access property \\$code on DeepL\\\\Language\\|null\\.$#" count: 7 diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index b8e17689..d33e49dc 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -50,11 +50,6 @@ parameters: count: 1 path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - - message: "#^Parameter \\#3 \\$pageUid of method WebVision\\\\WvDeepltranslate\\\\Domain\\\\Repository\\\\GlossaryRepository\\:\\:getGlossary\\(\\) expects int, array\\|float\\|int\\|string\\|false\\|null given\\.$#" - count: 1 - path: ../../../Classes/Domain/Repository/GlossaryRepository.php - - message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException\\|Doctrine\\\\DBAL\\\\Driver\\\\Exception is not subtype of Throwable$#" count: 1 @@ -200,21 +195,6 @@ parameters: count: 1 path: ../../../Classes/Utility/DeeplBackendUtility.php - - - message: "#^Offset 'pid' does not exist on array\\|null\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Parameter \\#1 \\$id of static method WebVision\\\\WvDeepltranslate\\\\Utility\\\\DeeplBackendUtility\\:\\:getPageRecord\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - - - message: "#^Parameter \\#2 \\$id of static method WebVision\\\\WvDeepltranslate\\\\Utility\\\\DeeplBackendUtility\\:\\:getPageIdFromRecord\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../Classes/Utility/DeeplBackendUtility.php - - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Utility\\\\HtmlUtility\\:\\:stripSpecificTags\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -305,6 +285,66 @@ parameters: count: 1 path: ../../../Tests/Functional/Hooks/TranslateHookTest.php + - + message: "#^Method WebVision\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:buildSiteConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + + - + message: "#^Method WebVision\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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\\\\WvDeepltranslate\\\\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: "#^Parameter \\#1 \\$current of method WebVision\\\\WvDeepltranslate\\\\Tests\\\\Functional\\\\Regression\\\\GlossaryRegressionTest\\:\\:mergeInstruction\\(\\) expects TYPO3\\\\TestingFramework\\\\Core\\\\Functional\\\\Framework\\\\Frontend\\\\Internal\\\\AbstractInstruction, TYPO3\\\\TestingFramework\\\\Core\\\\Functional\\\\Framework\\\\Frontend\\\\Internal\\\\AbstractInstruction\\|null given\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/GlossaryRegressionTest.php + - message: "#^Cannot access property \\$code on DeepL\\\\Language\\|null\\.$#" count: 7 diff --git a/Classes/Domain/Repository/GlossaryRepository.php b/Classes/Domain/Repository/GlossaryRepository.php index a040558b..76a76e89 100644 --- a/Classes/Domain/Repository/GlossaryRepository.php +++ b/Classes/Domain/Repository/GlossaryRepository.php @@ -13,6 +13,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Exception\SiteNotFoundException; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -50,7 +51,11 @@ public function getGlossaryInformationForSync(int $pageId): array $localizationLanguageIds = $this->getAvailableLocalizations($pageId); $site = GeneralUtility::makeInstance(SiteFinder::class) ->getSiteByPageId($pageId); - $sourceLangIsoCode = $site->getDefaultLanguage()->getTwoLetterIsoCode(); + if ((new Typo3Version())->getMajorVersion() >= 12) { + $sourceLangIsoCode = $site->getDefaultLanguage()->getLocale()->getLanguageCode(); + } else { + $sourceLangIsoCode = $site->getDefaultLanguage()->getTwoLetterIsoCode(); + } $localizationArray[$sourceLangIsoCode] = $entries; @@ -225,7 +230,7 @@ public function getGlossaryBySourceAndTarget( return $this->getGlossary( $lowerSourceLang, $lowerTargetLang, - $page['uid'], + (int)$page['uid'], true ) ?? $defaultGlossary; } @@ -254,7 +259,7 @@ public function getGlossaryBySourceAndTargetForSync( $lowerTargetLang = substr($lowerTargetLang, 0, 2); } - $result = $this->getGlossary($lowerSourceLang, $lowerTargetLang, $page['uid']); + $result = $this->getGlossary($lowerSourceLang, $lowerTargetLang, (int)$page['uid']); if ($result === null) { $insert = [ @@ -403,7 +408,7 @@ private function getAvailableLocalizations(int $pageId): array } $availableTranslations = []; foreach ($translations['translations'] as $translation) { - $availableTranslations[] = $translation['sys_language_uid']; + $availableTranslations[] = (int)$translation['sys_language_uid']; } return $availableTranslations; @@ -411,7 +416,11 @@ private function getAvailableLocalizations(int $pageId): array protected function getTargetLanguageIsoCode(Site $site, int $languageId): string { - return $site->getLanguageById($languageId)->getTwoLetterIsoCode(); + if ((new Typo3Version())->getMajorVersion() >= 12) { + return $site->getLanguageById($languageId)->getLocale()->getLanguageCode(); + } else { + return $site->getLanguageById($languageId)->getTwoLetterIsoCode(); + } } /** diff --git a/Classes/Hooks/AbstractTranslateHook.php b/Classes/Hooks/AbstractTranslateHook.php index 8f2119a0..b6a10eb1 100644 --- a/Classes/Hooks/AbstractTranslateHook.php +++ b/Classes/Hooks/AbstractTranslateHook.php @@ -17,33 +17,27 @@ use WebVision\WvDeepltranslate\Exception\LanguageRecordNotFoundException; use WebVision\WvDeepltranslate\Service\DeeplService; use WebVision\WvDeepltranslate\Service\LanguageService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; abstract class AbstractTranslateHook { - /** - * @var array{tableName: string|null, id: string|int|null, mode: string|false} - */ - protected static array $coreProcessorsInformation = [ - 'tableName' => null, - 'id' => null, - // @todo rename identifier to "deepl" - 'mode' => false, - ]; - protected DeeplService $deeplService; protected PageRepository $pageRepository; protected LanguageService $languageService; + protected ProcessingInstruction $processingInstruction; public function __construct( PageRepository $pageRepository, DeeplService $deeplService, - LanguageService $languageService + LanguageService $languageService, + ProcessingInstruction $processingInstruction ) { $this->deeplService = $deeplService; $this->pageRepository = $pageRepository; $this->languageService = $languageService; + $this->processingInstruction = $processingInstruction; } /** @@ -133,9 +127,6 @@ public function processCmdmap( if ($commandIsProcessed !== false) { return; } - - self::$coreProcessorsInformation['tableName'] = $table; - self::$coreProcessorsInformation['id'] = $id; - self::$coreProcessorsInformation['mode'] = $dataHandler->cmdmap['localization']['custom']['mode'] ?? false; + $this->processingInstruction->setProcessingInstruction($table, $id, $dataHandler->cmdmap['localization']['custom']['mode'] ?? false); } } diff --git a/Classes/Hooks/TranslateHook.php b/Classes/Hooks/TranslateHook.php index c4f99581..38878257 100644 --- a/Classes/Hooks/TranslateHook.php +++ b/Classes/Hooks/TranslateHook.php @@ -22,13 +22,13 @@ public function processTranslateTo_copyAction( DataHandler $dataHandler ): void { // Table Information are importen to find deepl configuration for site - $tableName = self::$coreProcessorsInformation['tableName']; + $tableName = $this->processingInstruction->getProcessingTable(); if ($tableName === null) { return; } // Record Information are importen to find deepl configuration for site - $currentRecordId = self::$coreProcessorsInformation['id']; + $currentRecordId = $this->processingInstruction->getProcessingId(); if ($currentRecordId === null) { return; } @@ -39,7 +39,7 @@ public function processTranslateTo_copyAction( } // Translation mode not set to DeepL translate skip the translation - if (self::$coreProcessorsInformation['mode'] !== 'deepl') { + if ($this->processingInstruction->isDeeplMode() === false) { return; } diff --git a/Classes/Service/DeeplService.php b/Classes/Service/DeeplService.php index e3a94609..7d18f707 100644 --- a/Classes/Service/DeeplService.php +++ b/Classes/Service/DeeplService.php @@ -23,15 +23,18 @@ final class DeeplService implements LoggerAwareInterface private FrontendInterface $cache; private ClientInterface $client; + private ProcessingInstruction $processingInstruction; public function __construct( FrontendInterface $cache, ClientInterface $client, - GlossaryRepository $glossaryRepository + GlossaryRepository $glossaryRepository, + ProcessingInstruction $processingInstruction ) { $this->cache = $cache; $this->client = $client; $this->glossaryRepository = $glossaryRepository; + $this->processingInstruction = $processingInstruction; } /** @@ -57,13 +60,20 @@ public function translateRequest( */ public function translateContent(TranslateContext $translateContext): string { + if ($this->processingInstruction->isDeeplMode() === false) { + // @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->warning('DeepL mode not set. Exit.'); + } + return $translateContext->getContent(); + } // If the source language is set to Autodetect, no glossary can be detected. if ($translateContext->getSourceLanguageCode() !== null) { // @todo Make glossary findable by current site. $glossary = $this->glossaryRepository->getGlossaryBySourceAndTarget( $translateContext->getSourceLanguageCode(), $translateContext->getTargetLanguageCode(), - DeeplBackendUtility::detectCurrentPage() + DeeplBackendUtility::detectCurrentPage($this->processingInstruction) ); $translateContext->setGlossaryId($glossary['glossary_id']); diff --git a/Classes/Service/ProcessingInstruction.php b/Classes/Service/ProcessingInstruction.php new file mode 100644 index 00000000..c793b760 --- /dev/null +++ b/Classes/Service/ProcessingInstruction.php @@ -0,0 +1,77 @@ +runtimeCache = $runtimeCache; + } + + /** + * @param int|string|null $id + * @todo harden deeplMode being a pure boolean + * @param string|bool $deeplMode + */ + public function setProcessingInstruction(?string $table = null, $id = null, $deeplMode = false): void + { + $processingInformation = [ + 'tableName' => $table, + 'id' => $id, + 'deeplMode' => $deeplMode, + ]; + $this->runtimeCache->set(self::PROCESSING_CACHE_IDENTIFIER, $processingInformation); + } + + /** + * @return array{ + * tableName: ?string, + * id: int|string|null, + * deeplMode: bool|string + * } + */ + public function getProcessingInstruction(): array + { + if (!$this->runtimeCache->has(self::PROCESSING_CACHE_IDENTIFIER)) { + return [ + 'tableName' => null, + 'id' => null, + 'deeplMode' => false, + ]; + } + return $this->runtimeCache->get(self::PROCESSING_CACHE_IDENTIFIER); + } + + public function isDeeplMode(): bool + { + $processingInstructions = $this->getProcessingInstruction(); + + return $processingInstructions['deeplMode'] === 'deepl' || $processingInstructions['deeplMode'] === true; + } + + public function getProcessingTable(): ?string + { + $processingInstructions = $this->getProcessingInstruction(); + + return $processingInstructions['tableName']; + } + + /** + * @return int|string|null + */ + public function getProcessingId() + { + $processingInstructions = $this->getProcessingInstruction(); + + return $processingInstructions['id']; + } +} diff --git a/Classes/Utility/DeeplBackendUtility.php b/Classes/Utility/DeeplBackendUtility.php index 268aa5ef..3efa1f9e 100644 --- a/Classes/Utility/DeeplBackendUtility.php +++ b/Classes/Utility/DeeplBackendUtility.php @@ -17,6 +17,7 @@ use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; use WebVision\WvDeepltranslate\Configuration; use WebVision\WvDeepltranslate\Exception\LanguageIsoCodeNotFoundException; @@ -24,6 +25,7 @@ use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; use WebVision\WvDeepltranslate\Service\IconOverlayGenerator; use WebVision\WvDeepltranslate\Service\LanguageService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; // @todo Make class final. Overriding a static utility class does not make much sense, but better to enforce it. class DeeplBackendUtility @@ -253,28 +255,22 @@ private static function getBackendUserAuthentication(): BackendUserAuthenticatio /** * @return array{uid: int, title: string}|array */ - public static function detectCurrentPage(): array + public static function detectCurrentPage(ProcessingInstruction $processingInstruction): array { self::$currentPage = []; - $request = $GLOBALS['TYPO3_REQUEST'] ?? null; - $queryParams = $request ? $request->getQueryParams() : []; - if (isset($queryParams['id']) || isset($queryParams['pageId'])) { - $currentId = (int)($queryParams['id'] ?? $queryParams['pageId']); - return self::getPageRecord($currentId); - } - if (isset($queryParams['cmd'])) { - foreach ($queryParams['cmd'] as $possibleTable => $values) { - if ($possibleTable === 'localization') { - continue; - } - [$id] = array_keys($values); - if ($possibleTable === 'pages') { - self::$currentPage = self::getPageRecord($id); - } else { - $pageId = self::getPageIdFromRecord($possibleTable, $id); - self::$currentPage = self::getPageRecord($pageId); - } - } + + if ($processingInstruction->getProcessingTable() === 'pages') { + self::$currentPage = self::getPageRecord((int)$processingInstruction->getProcessingId()); + } elseif ( + $processingInstruction->getProcessingTable() !== null + && strlen($processingInstruction->getProcessingTable()) > 0 + && MathUtility::canBeInterpretedAsInteger($processingInstruction->getProcessingId()) + ) { + $pageId = self::getPageIdFromRecord( + (string)$processingInstruction->getProcessingTable(), + (int)$processingInstruction->getProcessingId() + ); + self::$currentPage = self::getPageRecord($pageId); } return self::$currentPage; @@ -300,6 +296,6 @@ private static function getPageIdFromRecord(string $table, int $id): int $id, 'pid' ); - return $record['pid']; + return (int)($record['pid'] ?? null); } } diff --git a/Configuration/Services.php b/Configuration/Services.php index c4a52d80..741846a5 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -29,6 +29,7 @@ use WebVision\WvDeepltranslate\Service\DeeplService; use WebVision\WvDeepltranslate\Service\IconOverlayGenerator; use WebVision\WvDeepltranslate\Service\LanguageService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; use WebVision\WvDeepltranslate\Service\UsageService; use WebVision\WvDeepltranslate\Widgets\UsageWidget; @@ -84,6 +85,9 @@ ->factory([service(CacheManager::class), 'getCache']) ->args(['wvdeepltranslate']); + $services + ->set(ProcessingInstruction::class) + ->arg('$runtimeCache', service('cache.runtime')); $services ->set(DeeplService::class) ->public() diff --git a/Tests/Functional/Hooks/TranslateHookTest.php b/Tests/Functional/Hooks/TranslateHookTest.php index c9793d85..6e87ec9a 100644 --- a/Tests/Functional/Hooks/TranslateHookTest.php +++ b/Tests/Functional/Hooks/TranslateHookTest.php @@ -14,6 +14,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use WebVision\WvDeepltranslate\Hooks\TranslateHook; use WebVision\WvDeepltranslate\Service\LanguageService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; use WebVision\WvDeepltranslate\Tests\Functional\AbstractDeepLTestCase; use WebVision\WvDeepltranslate\Tests\Functional\Fixtures\Traits\SiteBasedTestTrait; @@ -92,6 +93,10 @@ protected function setUp(): void ] ); $this->setUpFrontendRootPage(1, [], []); + + /** @var ProcessingInstruction $processingInstruction */ + $processingInstruction = $this->get(ProcessingInstruction::class); + $processingInstruction->setProcessingInstruction(null, null, true); } /** diff --git a/Tests/Functional/Regression/Fixtures/Results/translateWithGlossary.csv b/Tests/Functional/Regression/Fixtures/Results/translateWithGlossary.csv new file mode 100644 index 00000000..d37c0ea6 --- /dev/null +++ b/Tests/Functional/Regression/Fixtures/Results/translateWithGlossary.csv @@ -0,0 +1,7 @@ +pages,,,,, +,"uid","pid","title","subtitle","sys_language_uid",l10n_parent +,1,0,"Deepl-Functional-Test","",0,0 +,2,1,"Glossary","",0,0 +,3,1,"Glossar","",1,2 +,4,1,"proton beam","glossary term",0,0 +,5,1,"Protonenstrahl","Glossareintrag",1,4 diff --git a/Tests/Functional/Regression/Fixtures/glossary.csv b/Tests/Functional/Regression/Fixtures/glossary.csv new file mode 100644 index 00000000..3eba0653 --- /dev/null +++ b/Tests/Functional/Regression/Fixtures/glossary.csv @@ -0,0 +1,14 @@ +pages +,"uid","pid",doktype,"title",subtitle,"sys_language_uid","l10n_parent","slug" +,1,0,1,"Deepl-Functional-Test","",0,0,"/" +,2,1,254,"Glossary","",0,0,"" +,3,1,254,"Glossar","",1,2,"" +,4,1,1,"proton beam","glossary term",0,0,"/proton-beam" +tx_wvdeepltranslate_glossaryentry +,uid,pid,term,sys_language_uid,l10n_parent +,1,2,"glossary term",0,0 +,2,2,"Glossareintrag",1,1 +"be_users" +,"uid","pid","tstamp","username","password","admin","disable","starttime","endtime","options","crdate","workspace_perms","deleted","TSconfig","lastlogin","workspace_id" +# The password is "password" +,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0 diff --git a/Tests/Functional/Regression/GlossaryRegressionTest.php b/Tests/Functional/Regression/GlossaryRegressionTest.php new file mode 100644 index 00000000..1b64d45f --- /dev/null +++ b/Tests/Functional/Regression/GlossaryRegressionTest.php @@ -0,0 +1,99 @@ + [ + 'id' => 0, + 'title' => 'English', + 'locale' => 'en_US.UTF-8', + 'iso' => 'en', + 'hrefLang' => 'en-US', + 'direction' => '', + 'custom' => [ + 'deeplTargetLanguage' => '', + ], + ], + 'DE' => [ + 'id' => 1, + 'title' => 'Deutsch', + 'locale' => 'de_DE', + 'iso' => 'de', + 'hrefLang' => 'de-DE', + 'direction' => '', + 'custom' => [ + 'deeplTargetLanguage' => 'DE', + ], + ], + ]; + + protected array $configurationToUseInTestInstance = [ + 'EXTENSIONS' => [ + 'wv_deepltranslate' => [ + 'apiKey' => 'mock_server', + ], + ], + ]; + + protected function setUp(): void + { + parent::setUp(); + + $site = $this->buildSiteConfiguration(1, '/', 'Home'); + + $this->writeSiteConfiguration( + 'acme', + $site, + [ + $this->buildDefaultLanguageConfiguration('EN', '/'), + $this->buildLanguageConfiguration('DE', '/de/', ['EN'], 'strict'), + ] + ); + + $this->importCSVDataSet(__DIR__ . '/Fixtures/glossary.csv'); + + $this->setUpBackendUser(1); + $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class) + ->createFromUserPreferences($GLOBALS['BE_USER']); + GeneralUtility::makeInstance(DeeplGlossaryService::class) + ->syncGlossaries(2); + } + + /** + * @test + */ + public function glossaryIsRespectedOnLocalization(): void + { + $commandMap = [ + 'pages' => [ + 4 => [ + 'localize' => 1, + ], + ], + 'localization' => [ + 'custom' => [ + 'mode' => 'deepl', + ], + ], + ]; + $dataHandler = GeneralUtility::makeInstance(DataHandler::class); + $dataHandler->start([], $commandMap); + $dataHandler->process_cmdmap(); + + self::assertEmpty($dataHandler->errorLog); + self::assertCSVDataSet(__DIR__ . '/Fixtures/Results/translateWithGlossary.csv'); + } +} diff --git a/Tests/Functional/Services/DeeplServiceTest.php b/Tests/Functional/Services/DeeplServiceTest.php index 7acc2b39..d8df9b2c 100644 --- a/Tests/Functional/Services/DeeplServiceTest.php +++ b/Tests/Functional/Services/DeeplServiceTest.php @@ -7,6 +7,7 @@ use DeepL\Language; use WebVision\WvDeepltranslate\Domain\Dto\TranslateContext; use WebVision\WvDeepltranslate\Service\DeeplService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; use WebVision\WvDeepltranslate\Tests\Functional\AbstractDeepLTestCase; /** @@ -23,6 +24,10 @@ protected function setUp(): void parent::setUp(); + /** @var ProcessingInstruction $processingInstruction */ + $processingInstruction = $this->get(ProcessingInstruction::class); + $processingInstruction->setProcessingInstruction(null, null, true); + } /** diff --git a/Tests/Functional/Services/UsageServiceTest.php b/Tests/Functional/Services/UsageServiceTest.php index 6f4b8399..f4181770 100644 --- a/Tests/Functional/Services/UsageServiceTest.php +++ b/Tests/Functional/Services/UsageServiceTest.php @@ -7,6 +7,7 @@ use DeepL\Usage; use DeepL\UsageDetail; use WebVision\WvDeepltranslate\Service\DeeplService; +use WebVision\WvDeepltranslate\Service\ProcessingInstruction; use WebVision\WvDeepltranslate\Service\UsageService; use WebVision\WvDeepltranslate\Tests\Functional\AbstractDeepLTestCase; @@ -22,6 +23,10 @@ protected function setUp(): void ); parent::setUp(); + + /** @var ProcessingInstruction $processingInstruction */ + $processingInstruction = $this->get(ProcessingInstruction::class); + $processingInstruction->setProcessingInstruction(null, null, true); } /**