Skip to content

Commit f99d421

Browse files
committed
[!!!][TASK] Remove DeepL Translate fallback to HREF and ISO config
DeeplTranslate only supports a narrowed down list of selected languages, which is only a subset of TYPO3 supported languages and the reason why a dedicated option `DeeplTranslate Language` is provided on the SiteConfig language level. As a left over from the original `Proof-of-Concept` phase and the first version iteration a fallback to SiteConfig language `HREF` and `ISO Locale` has been in place trying to get some kind of fallback. That turned out not to be that reliable and becomes more unreliable and invalid with planned upcoming features. Even with the fallback in place it has been recommended to specify the deepl translate language manually for a long time and the fallback is now removed in favour of explicit, manual configuration. > [!IMPORTANT] > This is technically breaking and SiteConfiguration needs to > be checked and the language set manually to mitigate this issue. > This can be done already since quite a lot version.
1 parent 0d783aa commit f99d421

File tree

8 files changed

+119
-98
lines changed

8 files changed

+119
-98
lines changed

Build/phpstan/Core12/phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,6 @@ parameters:
5050
count: 3
5151
path: ../../../Classes/Override/LocalizationController.php
5252

53-
-
54-
message: "#^Property WebVision\\\\Deepltranslate\\\\Core\\\\Service\\\\LanguageService\\:\\:\\$possibleLangMatches type has no value type specified in iterable type array\\.$#"
55-
count: 1
56-
path: ../../../Classes/Service/LanguageService.php
57-
5853
-
5954
message: "#^Call to method write\\(\\) on an unknown class TYPO3\\\\CMS\\\\Core\\\\Configuration\\\\SiteWriter\\.$#"
6055
count: 1

Build/phpstan/Core13/phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ parameters:
5555
count: 3
5656
path: ../../../Classes/Override/LocalizationController.php
5757

58-
-
59-
message: "#^Property WebVision\\\\Deepltranslate\\\\Core\\\\Service\\\\LanguageService\\:\\:\\$possibleLangMatches type has no value type specified in iterable type array\\.$#"
60-
count: 1
61-
path: ../../../Classes/Service/LanguageService.php
62-
6358
-
6459
message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Utility\\\\DeeplBackendUtility\\:\\:buildBackendRoute\\(\\) has parameter \\$parameters with no value type specified in iterable type array\\.$#"
6560
count: 1

Classes/Exception/LanguageIsoCodeNotFoundException.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace WebVision\Deepltranslate\Core\Exception;
66

7+
/**
8+
* @deprecated since v5 since no longer thrown and will be removed in v6.
9+
*/
710
class LanguageIsoCodeNotFoundException extends \Exception
811
{
912
}

Classes/Hooks/AbstractTranslateHook.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use TYPO3\CMS\Core\Utility\GeneralUtility;
1515
use WebVision\Deepltranslate\Core\Domain\Dto\TranslateContext;
1616
use WebVision\Deepltranslate\Core\Domain\Repository\PageRepository;
17+
use WebVision\Deepltranslate\Core\Exception\InvalidArgumentException;
1718
use WebVision\Deepltranslate\Core\Exception\LanguageIsoCodeNotFoundException;
1819
use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException;
1920
use WebVision\Deepltranslate\Core\Service\DeeplService;
@@ -72,10 +73,20 @@ protected function createTranslateContext(string $content, int $targetLanguageUi
7273

7374
$context->setSourceLanguageCode($sourceLanguageRecord['languageCode']);
7475

75-
$targetLanguageRecord = $this->languageService->getTargetLanguage($site, $targetLanguageUid);
76+
try {
77+
$targetLanguageRecord = $this->languageService->getTargetLanguage($site, $targetLanguageUid);
78+
} catch (\Throwable $e) {
79+
throw new InvalidArgumentException(
80+
sprintf(
81+
'The target language is not DeepL supported. Possibly wrong Site configuration. Message: %s',
82+
$e->getMessage(),
83+
),
84+
1746962367,
85+
$e,
86+
);
87+
}
7688

7789
$context->setTargetLanguageCode($targetLanguageRecord['languageCode']);
78-
7990
if (
8091
$targetLanguageRecord['formality'] !== ''
8192
&& $this->deeplService->hasLanguageFormalitySupport($targetLanguageRecord['languageCode'])

Classes/Service/LanguageService.php

Lines changed: 28 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,13 @@
55
namespace WebVision\Deepltranslate\Core\Service;
66

77
use TYPO3\CMS\Core\Site\Entity\Site;
8-
use WebVision\Deepltranslate\Core\Exception\LanguageIsoCodeNotFoundException;
8+
use WebVision\Deepltranslate\Core\Exception\InvalidArgumentException;
99
use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException;
1010

1111
final class LanguageService
1212
{
1313
protected DeeplService $deeplService;
1414

15-
/**
16-
* @todo TYPO3 v12 do not have hreflang & iso-639-1 directly in the raw language configurations anymore.
17-
* @link LanguageService::getTargetLanguage() for additional commets.
18-
* See: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77807
19-
* https://review.typo3.org/c/Packages/TYPO3.CMS/+/77597
20-
* https://review.typo3.org/c/Packages/TYPO3.CMS/+/77726
21-
* https://review.typo3.org/c/Packages/TYPO3.CMS/+/77814
22-
*/
23-
protected array $possibleLangMatches = [
24-
'deeplTargetLanguage',
25-
'hreflang',
26-
'iso-639-1',
27-
];
28-
2915
public function __construct(
3016
DeeplService $deeplService
3117
) {
@@ -58,72 +44,44 @@ public function getSourceLanguage(Site $currentSite): array
5844
/**
5945
* @return array{uid: int, title: string, language_isocode: string, languageCode: string, formality: string}
6046
* @throws LanguageRecordNotFoundException
61-
* @throws LanguageIsoCodeNotFoundException
47+
* @throws InvalidArgumentException
6248
*/
6349
public function getTargetLanguage(Site $currentSite, int $languageId): array
6450
{
65-
// @todo TYPO3 v12 changed locale API and therefore site configuration. Configured languages do no longer
66-
// directly contains values like hreflang or iso-639-1 directly. Possible workarounds would be to
67-
// operate directly on the siteLanguage objects and no longer use the raw configuration values.
68-
// See: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77807
69-
// https://review.typo3.org/c/Packages/TYPO3.CMS/+/77597
70-
// https://review.typo3.org/c/Packages/TYPO3.CMS/+/77726
71-
// https://review.typo3.org/c/Packages/TYPO3.CMS/+/77814
72-
$languages = array_filter($currentSite->getConfiguration()['languages'], function ($value) use ($languageId) {
73-
if (!is_array($value)) {
74-
return false;
51+
try {
52+
$language = $currentSite->getLanguageById($languageId);
53+
} catch (\Exception $e) {
54+
if ($e->getCode() === 1522960188) {
55+
throw new LanguageRecordNotFoundException(
56+
sprintf('Language "%d" in site "%s" not found.', $languageId, $currentSite->getIdentifier()),
57+
1746959505,
58+
$e,
59+
);
7560
}
76-
77-
if ((int)$value['languageId'] === $languageId) {
78-
return true;
79-
}
80-
81-
return false;
82-
});
83-
84-
if (count($languages) === 0) {
85-
throw new LanguageRecordNotFoundException(
86-
sprintf(
87-
'Language "%d" not found in SiteConfig "%s"',
88-
$languageId,
89-
(string)($currentSite->getConfiguration()['websiteTitle'] ?? '')
90-
),
91-
1676824459
92-
);
61+
throw $e;
9362
}
94-
$language = reset($languages);
95-
$languageCode = null;
96-
97-
foreach ($this->possibleLangMatches as $possibleLangMatch) {
98-
if (!array_key_exists($possibleLangMatch, $language)) {
99-
continue;
100-
}
101-
102-
if (!$this->deeplService->isTargetLanguageSupported(strtoupper($language[$possibleLangMatch]))) {
103-
continue;
104-
}
105-
106-
$languageCode = strtoupper($language[$possibleLangMatch]);
107-
break;
63+
$configuration = $language->toArray();
64+
$deeplTargetLanguage = $configuration['deeplTargetLanguage'] ?? null;
65+
if ($deeplTargetLanguage === null || $deeplTargetLanguage === '') {
66+
throw new InvalidArgumentException(
67+
sprintf('Missing deeplTargetLanguage or Language "%d" in site "%s"', $languageId, $currentSite->getIdentifier()),
68+
1746973481,
69+
);
10870
}
10971

110-
if ($languageCode === null) {
111-
throw new LanguageIsoCodeNotFoundException(
112-
sprintf(
113-
'No API supported target found for language "%s" in site "%s"',
114-
$language['title'],
115-
(string)($currentSite->getConfiguration()['websiteTitle'] ?? '')
116-
),
117-
1676741837
72+
if (!$this->deeplService->isTargetLanguageSupported($deeplTargetLanguage)) {
73+
throw new InvalidArgumentException(
74+
sprintf('The given language key "%s" is not supported by DeepL. Possibly wrong Site configuration.', $deeplTargetLanguage),
75+
1746959745,
11876
);
11977
}
12078

12179
return [
122-
'uid' => $language['languageId'] ?? 0,
123-
'title' => $language['title'],
124-
'language_isocode' => $languageCode,
125-
'languageCode' => $languageCode,
126-
'formality' => $language['deeplFormality'] ?? '',
80+
'uid' => $language->getLanguageId(),
81+
'title' => $language->getTitle(),
82+
'language_isocode' => $deeplTargetLanguage,
83+
'languageCode' => $deeplTargetLanguage,
84+
'formality' => $configuration['deeplFormality'] ?? '',
12785
];
12886
}
12987
}

Classes/Utility/DeeplBackendUtility.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
1717
use WebVision\Deepltranslate\Core\Configuration;
1818
use WebVision\Deepltranslate\Core\Domain\Dto\CurrentPage;
19-
use WebVision\Deepltranslate\Core\Exception\LanguageIsoCodeNotFoundException;
19+
use WebVision\Deepltranslate\Core\Exception\InvalidArgumentException;
2020
use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException;
2121
use WebVision\Deepltranslate\Core\Service\IconOverlayGenerator;
2222
use WebVision\Deepltranslate\Core\Service\LanguageService;
@@ -131,13 +131,11 @@ public static function checkCanBeTranslated(int $pageId, int $languageId): bool
131131
/** @var LanguageService $languageService */
132132
$languageService = GeneralUtility::makeInstance(LanguageService::class);
133133
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageId);
134-
135134
$languageService->getSourceLanguage($site);
136135
$languageService->getTargetLanguage($site, $languageId);
137-
} catch (LanguageIsoCodeNotFoundException|LanguageRecordNotFoundException|SiteNotFoundException $e) {
136+
} catch (LanguageRecordNotFoundException|SiteNotFoundException|InvalidArgumentException) {
138137
return false;
139138
}
140-
141139
return true;
142140
}
143141

Tests/Functional/Services/LanguageServiceTest.php

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use PHPUnit\Framework\Attributes\Test;
88
use SBUERK\TYPO3\Testing\SiteHandling\SiteBasedTestTrait;
99
use TYPO3\CMS\Core\Site\SiteFinder;
10-
use WebVision\Deepltranslate\Core\Exception\LanguageIsoCodeNotFoundException;
10+
use WebVision\Deepltranslate\Core\Exception\InvalidArgumentException;
1111
use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException;
1212
use WebVision\Deepltranslate\Core\Service\LanguageService;
1313
use WebVision\Deepltranslate\Core\Tests\Functional\AbstractDeepLTestCase;
@@ -58,7 +58,7 @@ final class LanguageServiceTest extends AbstractDeepLTestCase
5858
'hrefLang' => 'bs',
5959
'direction' => '',
6060
'custom' => [
61-
'deeplTargetLanguage' => '',
61+
'deeplTargetLanguage' => 'BS',
6262
],
6363
],
6464
'BS' => [
@@ -72,6 +72,17 @@ final class LanguageServiceTest extends AbstractDeepLTestCase
7272
'deeplTargetLanguage' => '',
7373
],
7474
],
75+
'Not-supported' => [
76+
'id' => 5,
77+
'title' => 'Bosnian',
78+
'locale' => 'bs_BA.utf8',
79+
'iso' => 'bs',
80+
'hrefLang' => 'bs',
81+
'direction' => '',
82+
'custom' => [
83+
'deeplTargetLanguage' => 'BS',
84+
],
85+
],
7586
];
7687

7788
protected function setUp(): void
@@ -92,6 +103,7 @@ protected function setUp(): void
92103
$this->buildLanguageConfiguration('DE', '/de/', ['EN'], 'strict'),
93104
$this->buildLanguageConfiguration('EB', '/eb/', ['EN'], 'strict'),
94105
$this->buildLanguageConfiguration('BS', '/bs/', ['EN'], 'strict'),
106+
$this->buildLanguageConfiguration('Not-supported', '/not-supported/', ['EN'], 'strict'),
95107
],
96108
);
97109
$this->setUpFrontendRootPage(1, [], []);
@@ -149,14 +161,15 @@ public function getTargetLanguageInformationIsValid(): void
149161
$siteFinder = $this->get(SiteFinder::class);
150162
$siteInformation = $siteFinder->getSiteByPageId(1);
151163

152-
$sourceLanguageRecord = $languageService->getTargetLanguage($siteInformation, 2);
164+
$targetLanguageRecord = $languageService->getTargetLanguage($siteInformation, 2);
165+
static::assertIsArray($targetLanguageRecord);
153166

154-
static::assertArrayHasKey('uid', $sourceLanguageRecord);
155-
static::assertArrayHasKey('title', $sourceLanguageRecord);
156-
static::assertArrayHasKey('language_isocode', $sourceLanguageRecord);
167+
static::assertArrayHasKey('uid', $targetLanguageRecord);
168+
static::assertArrayHasKey('title', $targetLanguageRecord);
169+
static::assertArrayHasKey('language_isocode', $targetLanguageRecord);
157170

158-
static::assertSame(2, $sourceLanguageRecord['uid']);
159-
static::assertSame('DE', $sourceLanguageRecord['language_isocode']);
171+
static::assertSame(2, $targetLanguageRecord['uid']);
172+
static::assertSame('DE', $targetLanguageRecord['language_isocode']);
160173
}
161174

162175
#[Test]
@@ -169,21 +182,38 @@ public function getTargetLanguageExceptionWhenLanguageNotExist(): void
169182
$siteInformation = $siteFinder->getSiteByPageId(1);
170183

171184
static::expectException(LanguageRecordNotFoundException::class);
172-
static::expectExceptionMessage('Language "1" not found in SiteConfig "Home"');
185+
static::expectExceptionCode(1746959505);
186+
static::expectExceptionMessage(sprintf('Language "%s" in site "%s" not found.', 1, 'site-a'));
173187
$languageService->getTargetLanguage($siteInformation, 1);
174188
}
175189

176190
#[Test]
177-
public function getTargetLanguageExceptionWhenLanguageIsoNotSupported(): void
191+
public function getTargetLanguageReturnsFalseOnNotConfiguredTargetLanguage(): void
178192
{
179193
/** @var LanguageService $languageService */
180194
$languageService = $this->get(LanguageService::class);
181195
/** @var SiteFinder $siteFinder */
182196
$siteFinder = $this->get(SiteFinder::class);
183197
$siteInformation = $siteFinder->getSiteByPageId(1);
184198

185-
static::expectException(LanguageIsoCodeNotFoundException::class);
186-
static::expectExceptionMessage('No API supported target found for language "Bosnian" in site "Home"');
199+
static::expectException(InvalidArgumentException::class);
200+
static::expectExceptionCode(1746973481);
201+
static::expectExceptionMessage(sprintf('Missing deeplTargetLanguage or Language "%s" in site "%s"', 4, 'site-a'));
187202
$languageService->getTargetLanguage($siteInformation, 4);
188203
}
204+
205+
#[Test]
206+
public function getTargetLanguageExceptionWhenLanguageIsoNotSupported(): void
207+
{
208+
/** @var LanguageService $languageService */
209+
$languageService = $this->get(LanguageService::class);
210+
/** @var SiteFinder $siteFinder */
211+
$siteFinder = $this->get(SiteFinder::class);
212+
$siteInformation = $siteFinder->getSiteByPageId(1);
213+
214+
static::expectException(InvalidArgumentException::class);
215+
static::expectExceptionCode(1746959745);
216+
static::expectExceptionMessage(sprintf('The given language key "%s" is not supported by DeepL. Possibly wrong Site configuration.', 'BS'));
217+
$languageService->getTargetLanguage($siteInformation, 5);
218+
}
189219
}

UPGRADE.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Upgrade 5.x
2+
3+
## X.Y.Z
4+
5+
### (BREAKING): Removed language fallback using SiteConfig ISO and HREF
6+
7+
DeeplTranslate only supports a narrowed down list of selected languages, which
8+
is only a subset of TYPO3 supported languages and the reason why a dedicated
9+
option `DeeplTranslate Language` is provided on the SiteConfig language level.
10+
11+
As a left over from the original `Proof-of-Concept` phase and the first version
12+
iteration a fallback to `HREF` and `ISO Locale` has been in place trying to get
13+
some kind of fallback. That turned out not to be that reliable and becomes more
14+
unreliable and invalid with planned upcoming features.
15+
16+
Even with the fallback in place it has been recommended to specify the deepl
17+
translate language manually for a long time and the fallback is now removed
18+
in favour of explicit, manual configuration.
19+
20+
> [!IMPORTANT]
21+
> This is technically breaking and SiteConfiguration needs to be checked and
22+
> the language set manually to mitigate this issue. This can be done already
23+
> since quite a lot version.
24+
25+
## 5.0.3
26+
27+
## 5.0.2
28+
29+
## 5.0.1
30+
31+
## 5.0.0

0 commit comments

Comments
 (0)