Known issues
Translation options not shown
When API key is not set, deepltranslate_core disables all functions. Go to Settings and fix it. Clear cache after this.
TYPO3 Core patch required (l10n_source)
Localizing a record whose table declares a translation source field
(l10n_source) - for example content elements built with MASK - can create
a duplicate translation in the same language. This is the root cause of the
duplicated translations reported for web-vision/deepltranslate-auto-renew in
#42.
The defect is in the TYPO3 Core, not in this extension:
BackendUtility::getRecordLocalization() matches existing translations by
l10n_source when the table defines one and does not fall back to
l10n_parent. A valid translation created without populating l10n_source
(the usual result of a plain DataHandler datamap, an importer, a migration or
MASK) is not found, so DataHandler::localize() creates a second one.
The fix is upstream: forge #110281, Gerrit 94915 (13.4). TYPO3 v12.4 has reached ELTS and never receives the fix upstream. Until the fix is released for v13.4, and permanently for v12.4, instances have to apply it through a Composer patch.
This extension ships the patch file below Documentation/CorePatches/ and
declares it in its own composer.json. When the project uses
vaimo/composer-patches, nothing
has to be configured: patch declarations are collected from installed
dependencies as well, not only from the root composer.json, so having this
extension installed is enough and the patch matching the TYPO3 version in use is
applied automatically:
- Applying patches for typo3/cms-backend (1)
~ web-vision/deepltranslate-core: Documentation/CorePatches/typo3-cms-backend-110281-v12-v13.patch [NEW]
Do not declare the same patch a second time in the project. Declarations for the same target package are de-duplicated, the declaration of the dependency wins and the own one is dropped silently.
Plugins which only evaluate the root composer.json - for example
cweagans/composer-patches in
its default configuration - do not pick that declaration up. Copy the patch file
into the project and declare it, scoped so it only applies to the affected
versions:
{
"require-dev": {
"vaimo/composer-patches": "^6.0.1"
},
"extra": {
"patches": {
"typo3/cms-backend": {
"TYPO3 #110281 l10n_source on v12.4 (ELTS, always)": {
"source": "patches/typo3-cms-backend-110281-v12-v13.patch",
"version": ">=12.4.0 <13.0.0"
},
"TYPO3 #110281 l10n_source on v13.4 (until the fix release)": {
"source": "patches/typo3-cms-backend-110281-v12-v13.patch",
"version": ">=13.4.0 <13.4.34"
}
}
}
}
}
Patches the project applies to typo3/cms-backend itself may need adoption:
they have to apply on top of the changes shown below, otherwise patching fails
and aborts the Composer run. The same is true for patches provided by other
extensions for the same file.
See the general TYPO3 documentation on applying Composer patches for project-specific setup details. The patch used by this extension:
diff --git a/Classes/Utility/BackendUtility.php b/Classes/Utility/BackendUtility.php
index 893f781..f442596 100644
--- a/Classes/Utility/BackendUtility.php
+++ b/Classes/Utility/BackendUtility.php
@@ -27,6 +27,7 @@
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Platform\PlatformInformation;
+use TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\QueryHelper;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
@@ -293,10 +294,7 @@
$queryBuilder->select('*')
->from($table)
->where(
- $queryBuilder->expr()->eq(
- $tcaCtrl['translationSource'] ?? $tcaCtrl['transOrigPointerField'],
- $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)
- ),
+ self::createTranslationParentConstraint($queryBuilder, $tcaCtrl, (int)$uid),
$queryBuilder->expr()->eq(
$tcaCtrl['languageField'],
$queryBuilder->createNamedParameter((int)$language, Connection::PARAM_INT)
@@ -314,6 +312,44 @@
return $recordLocalization;
}
+ /**
+ * Constraint matching all translations of the given record.
+ *
+ * `translationSource` (l10n_source) is preferred, since it is the more precise information for
+ * translation chains. It is however not maintained by all writes - a DataHandler datamap which
+ * creates a translation by only setting the language field and the transOrigPointerField leaves
+ * it empty - so such records are matched by their transOrigPointerField (l10n_parent) instead.
+ * Without that, valid translations would be invisible for callers like
+ * `DataHandler::localize()`, which uses this lookup to prevent duplicate translations.
+ *
+ * @param array $tcaCtrl The `ctrl` section of the table
+ */
+ protected static function createTranslationParentConstraint(
+ QueryBuilder $queryBuilder,
+ array $tcaCtrl,
+ int $uid
+ ): CompositeExpression|string {
+ $uidParameter = $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT);
+ $translationOriginPointerConstraint = $queryBuilder->expr()->eq(
+ $tcaCtrl['transOrigPointerField'],
+ $uidParameter
+ );
+ if (!isset($tcaCtrl['translationSource'])) {
+ return $translationOriginPointerConstraint;
+ }
+
+ return $queryBuilder->expr()->or(
+ $queryBuilder->expr()->eq($tcaCtrl['translationSource'], $uidParameter),
+ $queryBuilder->expr()->and(
+ $queryBuilder->expr()->eq(
+ $tcaCtrl['translationSource'],
+ $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)
+ ),
+ $translationOriginPointerConstraint
+ )
+ );
+ }
+
/*******************************************
*
* Page tree, TCA related