From 49ab70c120d7677062288d54c9a8f93743dd4c66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Buchmann?= <andy.schliesser@gmail.com>
Date: Wed, 12 Jul 2023 15:29:31 +0200
Subject: [PATCH] [BUGFIX] Localize children of all languages element
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When the parent record has been set to sys_language_uid=-1, but the
child record has translations, it should be displayed in the correct
language. Setting the languageUid for the querySettings to -1 results
in display of the default language record of the child.

Resolves: #92768
Releases: main, 12.4, 11.5
Change-Id: I25bcdbb182c1b35cbc08e5f91339453b0986cdcc
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/80929
Tested-by: core-ci <typo3@b13.com>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 composer.json                                 |   1 +
 .../Persistence/Generic/Mapper/DataMapper.php |   7 +-
 .../Classes/Controller/MainController.php     |  39 +++++
 .../Classes/Domain/Model/Child.php            |  44 ++++++
 .../Classes/Domain/Model/Main.php             | 135 ++++++++++++++++++
 .../Classes/Domain/Model/Squeeze.php          |  65 +++++++++
 .../Domain/Repository/MainRepository.php      |  40 ++++++
 .../Configuration/Services.yaml               |   9 ++
 .../TCA/Overrides/sys_template.php            |   7 +
 .../TCA/Overrides/tt_content.php              |  11 ++
 ...entchildtranslation_domain_model_child.php |  75 ++++++++++
 ...rentchildtranslation_domain_model_main.php | 100 +++++++++++++
 ...tchildtranslation_domain_model_squeeze.php |  93 ++++++++++++
 .../TypoScript/constants.typoscript           |  10 ++
 .../Configuration/TypoScript/setup.typoscript |  10 ++
 .../Resources/Private/Templates/List.html     |  20 +++
 .../parent_child_translation/composer.json    |  19 +++
 .../parent_child_translation/ext_emconf.php   |  21 +++
 .../ext_localconf.php                         |  18 +++
 .../parent_child_translation/ext_tables.sql   |  24 ++++
 .../parentChildTranslationExampleData.csv     |  24 ++++
 .../ParentChildTranslationTest.php            |  94 ++++++++++++
 22 files changed, 864 insertions(+), 2 deletions(-)
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Controller/MainController.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Child.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Main.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Squeeze.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Repository/MainRepository.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/Services.yaml
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/sys_template.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/tt_content.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_child.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_main.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_squeeze.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/constants.typoscript
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/setup.typoscript
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Resources/Private/Templates/List.html
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/composer.json
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_emconf.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_localconf.php
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_tables.sql
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/parentChildTranslationExampleData.csv
 create mode 100644 typo3/sysext/extbase/Tests/Functional/Persistence/ParentChildTranslationTest.php

diff --git a/composer.json b/composer.json
index 3b4847a41880..d66cbebbe146 100644
--- a/composer.json
+++ b/composer.json
@@ -288,6 +288,7 @@
 			"TYPO3\\CMS\\Recycler\\Tests\\": "typo3/sysext/recycler/Tests/",
 			"TYPO3\\CMS\\T3editor\\Tests\\": "typo3/sysext/t3editor/Tests/",
 			"TYPO3\\CMS\\Tstemplate\\Tests\\": "typo3/sysext/tstemplate/Tests/",
+			"TYPO3Tests\\ParentChildTranslation\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/",
 			"TYPO3Tests\\TestLogger\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_logger/Classes/"
 		},
 		"classmap": [
diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
index d86ea769f26d..9cd668ebc15f 100644
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
@@ -402,8 +402,11 @@ class DataMapper
                 //pass language of parent record to child objects, so they can be overlaid correctly in case
                 //e.g. findByUid is used.
                 //the languageUid is used for getRecordOverlay later on, despite RespectSysLanguage being false
-                $languageUid = (int)$parentObject->_getProperty('_languageUid');
-                $query->getQuerySettings()->setLanguageUid($languageUid);
+                $parentLanguageUid = (int)$parentObject->_getProperty('_languageUid');
+                // do not override the language when the parent language uid is set to all languages (-1)
+                if ($parentLanguageUid !== -1) {
+                    $query->getQuerySettings()->setLanguageUid($parentLanguageUid);
+                }
             }
         }
 
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Controller/MainController.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Controller/MainController.php
new file mode 100644
index 000000000000..61a361ce6c70
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Controller/MainController.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3Tests\ParentChildTranslation\Controller;
+
+use Psr\Http\Message\ResponseInterface;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3Tests\ParentChildTranslation\Domain\Repository\MainRepository;
+
+final class MainController extends ActionController
+{
+    private MainRepository $mainRepository;
+
+    public function __construct(MainRepository $mainRepository)
+    {
+        $this->mainRepository = $mainRepository;
+    }
+
+    public function listAction(): ResponseInterface
+    {
+        $this->view->assign('items', $this->mainRepository->findAll());
+
+        return $this->htmlResponse();
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Child.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Child.php
new file mode 100644
index 000000000000..a130ac04dd3b
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Child.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3Tests\ParentChildTranslation\Domain\Model;
+
+use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+
+class Child extends AbstractEntity
+{
+    /**
+     * title
+     */
+    protected string $title = '';
+
+    /**
+     * Returns the title
+     */
+    public function getTitle(): string
+    {
+        return $this->title;
+    }
+
+    /**
+     * Sets the title
+     */
+    public function setTitle(string $title): void
+    {
+        $this->title = $title;
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Main.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Main.php
new file mode 100644
index 000000000000..b7584c1b3284
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Main.php
@@ -0,0 +1,135 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3Tests\ParentChildTranslation\Domain\Model;
+
+use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
+use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
+use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
+
+class Main extends AbstractEntity
+{
+    /**
+     * title
+     */
+    protected string $title = '';
+
+    /**
+     * child
+     */
+    protected ?Child $child = null;
+
+    /**
+     * squeeze
+     *
+     * @var ObjectStorage<Squeeze>
+     *
+     * @Cascade("remove")
+     *
+     * @Lazy
+     */
+    protected ObjectStorage $squeeze;
+
+    /**
+     * __construct
+     */
+    public function __construct()
+    {
+        // Do not remove the next line: It would break the functionality
+        $this->initializeObject();
+    }
+
+    /**
+     * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called)
+     * Do not modify this method!
+     * It will be rewritten on each save in the extension builder
+     * You may modify the constructor of this class instead
+     */
+    public function initializeObject(): void
+    {
+        $this->squeeze = new ObjectStorage();
+    }
+
+    /**
+     * Returns the title
+     */
+    public function getTitle(): string
+    {
+        return $this->title;
+    }
+
+    /**
+     * Sets the title
+     */
+    public function setTitle(string $title): void
+    {
+        $this->title = $title;
+    }
+
+    /**
+     * Returns the child
+     */
+    public function getChild(): ?Child
+    {
+        return $this->child;
+    }
+
+    /**
+     * Sets the child
+     */
+    public function setChild(Child $child): void
+    {
+        $this->child = $child;
+    }
+
+    /**
+     * Adds a Squeeze
+     */
+    public function addSqueeze(Squeeze $squeeze): void
+    {
+        $this->squeeze->attach($squeeze);
+    }
+
+    /**
+     * Removes a Squeeze
+     */
+    public function removeSqueeze(Squeeze $squeezeToRemove): void
+    {
+        $this->squeeze->detach($squeezeToRemove);
+    }
+
+    /**
+     * Returns the squeeze
+     *
+     * @return ObjectStorage<Squeeze>
+     */
+    public function getSqueeze(): ObjectStorage
+    {
+        return $this->squeeze;
+    }
+
+    /**
+     * Sets the squeeze
+     *
+     * @param ObjectStorage<Squeeze> $squeeze
+     */
+    public function setSqueeze(ObjectStorage $squeeze): void
+    {
+        $this->squeeze = $squeeze;
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Squeeze.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Squeeze.php
new file mode 100644
index 000000000000..967c9241b2b9
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Model/Squeeze.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3Tests\ParentChildTranslation\Domain\Model;
+
+use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+
+class Squeeze extends AbstractEntity
+{
+    /**
+     * title
+     */
+    protected string $title = '';
+
+    /**
+     * child
+     */
+    protected ?Child $child = null;
+
+    /**
+     * Returns the title
+     */
+    public function getTitle(): string
+    {
+        return $this->title;
+    }
+
+    /**
+     * Sets the title
+     */
+    public function setTitle(string $title): void
+    {
+        $this->title = $title;
+    }
+
+    /**
+     * Returns the child
+     */
+    public function getChild(): ?Child
+    {
+        return $this->child;
+    }
+
+    /**
+     * Sets the child
+     */
+    public function setChild(Child $child): void
+    {
+        $this->child = $child;
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Repository/MainRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Repository/MainRepository.php
new file mode 100644
index 000000000000..504c7d9acf16
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/Domain/Repository/MainRepository.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3Tests\ParentChildTranslation\Domain\Repository;
+
+use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
+use TYPO3\CMS\Extbase\Persistence\QueryInterface;
+use TYPO3\CMS\Extbase\Persistence\Repository;
+
+/**
+ * The repository for Mains
+ */
+class MainRepository extends Repository
+{
+    protected $defaultOrderings = [
+        'uid' => QueryInterface::ORDER_ASCENDING,
+    ];
+
+    public function initializeObject(): void
+    {
+        /** @var Typo3QuerySettings $defaultQuerySettings */
+        $defaultQuerySettings = $this->createQuery()->getQuerySettings();
+        $defaultQuerySettings->setRespectStoragePage(false);
+        $this->setDefaultQuerySettings($defaultQuerySettings);
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/Services.yaml b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/Services.yaml
new file mode 100644
index 000000000000..5d18bcd3e8ef
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/Services.yaml
@@ -0,0 +1,9 @@
+services:
+  _defaults:
+    autowire: true
+    autoconfigure: true
+    public: false
+
+  TYPO3Tests\ParentChildTranslation\:
+    resource: '../Classes/*'
+    exclude: '../Classes/Domain/{Model,Validator}'
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/sys_template.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/sys_template.php
new file mode 100644
index 000000000000..f85e5327fb85
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/sys_template.php
@@ -0,0 +1,7 @@
+<?php
+
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+
+defined('TYPO3') or die();
+
+ExtensionManagementUtility::addStaticFile('parent_child_translation', 'Configuration/TypoScript', 'Parent Child Translation');
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/tt_content.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/tt_content.php
new file mode 100644
index 000000000000..f8163b1f890f
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/Overrides/tt_content.php
@@ -0,0 +1,11 @@
+<?php
+
+use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
+
+defined('TYPO3') or die();
+
+ExtensionUtility::registerPlugin(
+    'ParentChildTranslation',
+    'ParentChildTranslation',
+    'ParentChildTranslation'
+);
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_child.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_child.php
new file mode 100644
index 000000000000..5a5d6efa110e
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_child.php
@@ -0,0 +1,75 @@
+<?php
+
+return [
+    'ctrl' => [
+        'title' => 'Child',
+        'label' => 'title',
+        'tstamp' => 'tstamp',
+        'crdate' => 'crdate',
+        'versioningWS' => true,
+        'languageField' => 'sys_language_uid',
+        'transOrigPointerField' => 'l10n_parent',
+        'transOrigDiffSourceField' => 'l10n_diffsource',
+        'delete' => 'deleted',
+        'enablecolumns' => [
+            'disabled' => 'hidden',
+        ],
+        'searchFields' => 'title',
+        'security' => [
+            'ignorePageTypeRestriction' => true,
+        ],
+    ],
+    'types' => [
+        '1' => ['showitem' => 'title,
+        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden',
+        ],
+    ],
+    'columns' => [
+        'sys_language_uid' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
+            'config' => [
+                'type' => 'language',
+            ],
+        ],
+        'l10n_parent' => [
+            'displayCond' => 'FIELD:sys_language_uid:>:0',
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
+            'config' => [
+                'type' => 'select',
+                'renderType' => 'selectSingle',
+                'default' => 0,
+                'items' => [
+                    [
+                        '',
+                        0,
+                    ],
+                ],
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_main',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_main}.{#pid}=###CURRENT_PID### AND {#tx_parentchildtranslation_domain_model_main}.{#sys_language_uid} IN (-1,0)',
+            ],
+        ],
+        'l10n_diffsource' => [
+            'config' => [
+                'type' => 'passthrough',
+            ],
+        ],
+        'hidden' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
+            'config' => [
+                'type' => 'check',
+            ],
+        ],
+        'title' => [
+            'exclude' => true,
+            'label' => 'Title',
+            'config' => [
+                'type' => 'input',
+                'size' => 30,
+                'eval' => 'trim',
+                'default' => '',
+            ],
+        ],
+    ],
+];
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_main.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_main.php
new file mode 100644
index 000000000000..28db27d9d6f4
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_main.php
@@ -0,0 +1,100 @@
+<?php
+
+return [
+    'ctrl' => [
+        'title' => 'Parent',
+        'label' => 'title',
+        'tstamp' => 'tstamp',
+        'crdate' => 'crdate',
+        'versioningWS' => true,
+        'languageField' => 'sys_language_uid',
+        'transOrigPointerField' => 'l10n_parent',
+        'transOrigDiffSourceField' => 'l10n_diffsource',
+        'delete' => 'deleted',
+        'enablecolumns' => [
+            'disabled' => 'hidden',
+        ],
+        'searchFields' => 'title',
+        'security' => [
+            'ignorePageTypeRestriction' => true,
+        ],
+    ],
+    'types' => [
+        '1' => ['showitem' => 'title, child, squeeze,
+        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden',
+        ],
+    ],
+    'columns' => [
+        'sys_language_uid' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
+            'config' => [
+                'type' => 'language',
+            ],
+        ],
+        'l10n_parent' => [
+            'displayCond' => 'FIELD:sys_language_uid:>:0',
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
+            'config' => [
+                'type' => 'select',
+                'renderType' => 'selectSingle',
+                'default' => 0,
+                'items' => [
+                    [
+                        '',
+                        0,
+                    ],
+                ],
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_main',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_main}.{#pid}=###CURRENT_PID### AND {#tx_parentchildtranslation_domain_model_main}.{#sys_language_uid} IN (-1,0)',
+            ],
+        ],
+        'l10n_diffsource' => [
+            'config' => [
+                'type' => 'passthrough',
+            ],
+        ],
+        'hidden' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
+            'config' => [
+                'type' => 'check',
+            ],
+        ],
+        'title' => [
+            'exclude' => true,
+            'label' => 'Title',
+            'config' => [
+                'type' => 'input',
+                'size' => 30,
+                'eval' => 'trim',
+                'default' => '',
+            ],
+        ],
+        'child' => [
+            'exclude' => true,
+            'label' => 'Child',
+            'config' => [
+                'type' => 'select',
+                'renderType' => 'selectSingle',
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_child',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_child}.{#sys_language_uid} IN (0,-1)',
+                'default' => 0,
+                'minitems' => 0,
+                'maxitems' => 1,
+            ],
+        ],
+        'squeeze' => [
+            'exclude' => true,
+            'label' => 'Squeeze',
+            'config' => [
+                'type' => 'inline',
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_squeeze',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_squeeze}.{#sys_language_uid} IN (0,-1)',
+                'foreign_field' => 'parent',
+                'maxitems' => 1,
+                'default' => 0,
+            ],
+        ],
+    ],
+];
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_squeeze.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_squeeze.php
new file mode 100644
index 000000000000..103d0d83d58b
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TCA/tx_parentchildtranslation_domain_model_squeeze.php
@@ -0,0 +1,93 @@
+<?php
+
+return [
+    'ctrl' => [
+        'title' => 'Squeeze',
+        'label' => 'title',
+        'tstamp' => 'tstamp',
+        'crdate' => 'crdate',
+        'versioningWS' => true,
+        'languageField' => 'sys_language_uid',
+        'transOrigPointerField' => 'l10n_parent',
+        'transOrigDiffSourceField' => 'l10n_diffsource',
+        'delete' => 'deleted',
+        'enablecolumns' => [
+            'disabled' => 'hidden',
+        ],
+        'searchFields' => 'title',
+        'security' => [
+            'ignorePageTypeRestriction' => true,
+        ],
+    ],
+    'types' => [
+        '1' => ['showitem' => 'title, child,
+        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden',
+        ],
+    ],
+    'columns' => [
+        'sys_language_uid' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
+            'config' => [
+                'type' => 'language',
+            ],
+        ],
+        'l10n_parent' => [
+            'displayCond' => 'FIELD:sys_language_uid:>:0',
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
+            'config' => [
+                'type' => 'select',
+                'renderType' => 'selectSingle',
+                'default' => 0,
+                'items' => [
+                    [
+                        '',
+                        0,
+                    ],
+                ],
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_main',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_main}.{#pid}=###CURRENT_PID### AND {#tx_parentchildtranslation_domain_model_main}.{#sys_language_uid} IN (-1,0)',
+            ],
+        ],
+        'l10n_diffsource' => [
+            'config' => [
+                'type' => 'passthrough',
+            ],
+        ],
+        'hidden' => [
+            'exclude' => true,
+            'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
+            'config' => [
+                'type' => 'check',
+            ],
+        ],
+        'title' => [
+            'exclude' => true,
+            'label' => 'Title',
+            'config' => [
+                'type' => 'input',
+                'size' => 30,
+                'eval' => 'trim',
+                'default' => '',
+            ],
+        ],
+        'child' => [
+            'exclude' => true,
+            'label' => 'Child',
+            'config' => [
+                'type' => 'select',
+                'renderType' => 'selectSingle',
+                'foreign_table' => 'tx_parentchildtranslation_domain_model_child',
+                'foreign_table_where' => 'AND {#tx_parentchildtranslation_domain_model_child}.{#sys_language_uid} IN (0,-1)',
+                'default' => 0,
+                'minitems' => 0,
+                'maxitems' => 1,
+            ],
+        ],
+        'parent' => [
+            'config' => [
+                'type' => 'passthrough',
+            ],
+        ],
+    ],
+];
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/constants.typoscript b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/constants.typoscript
new file mode 100644
index 000000000000..65cd115122d3
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/constants.typoscript
@@ -0,0 +1,10 @@
+plugin.tx_parentchildtranslation_parentchildtranslation {
+    view {
+        # cat=plugin.tx_parentchildtranslation_parentchildtranslation/file; type=string; label=Path to template root (FE)
+        templateRootPath = EXT:parent_child_translation/Resources/Private/Templates/
+        # cat=plugin.tx_parentchildtranslation_parentchildtranslation/file; type=string; label=Path to template partials (FE)
+        partialRootPath = EXT:parent_child_translation/Resources/Private/Partials/
+        # cat=plugin.tx_parentchildtranslation_parentchildtranslation/file; type=string; label=Path to template layouts (FE)
+        layoutRootPath = EXT:parent_child_translation/Resources/Private/Layouts/
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/setup.typoscript b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/setup.typoscript
new file mode 100644
index 000000000000..6ce2f16a2b21
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Configuration/TypoScript/setup.typoscript
@@ -0,0 +1,10 @@
+plugin.tx_parentchildtranslation_parentchildtranslation {
+    view {
+        templateRootPaths.0 = EXT:parent_child_translation/Resources/Private/Templates/
+        templateRootPaths.1 = {$plugin.tx_parentchildtranslation_parentchildtranslation.view.templateRootPath}
+        partialRootPaths.0 = EXT:parent_child_translation/Resources/Private/Partials/
+        partialRootPaths.1 = {$plugin.tx_parentchildtranslation_parentchildtranslation.view.partialRootPath}
+        layoutRootPaths.0 = EXT:parent_child_translation/Resources/Private/Layouts/
+        layoutRootPaths.1 = {$plugin.tx_parentchildtranslation_parentchildtranslation.view.layoutRootPath}
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Resources/Private/Templates/List.html b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Resources/Private/Templates/List.html
new file mode 100644
index 000000000000..bb389a748fcc
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Resources/Private/Templates/List.html
@@ -0,0 +1,20 @@
+<html xmlns:f="https://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
+<ul>
+    <f:for as="item" each="{items}" iteration="iteration">
+        <li>Parents:
+            <ul>
+                <li>Parent: {item.title}</li>
+                <li>Child: {item.child.title}</li>
+                <li>Squeezes:
+                    <ul>
+                        <f:for as="squeeze" each="{item.squeeze}" iteration="iteration">
+                            <li>Squeeze: {squeeze.title}
+                            <li>Child: {squeeze.child.title}</li>
+                        </f:for>
+                    </ul>
+                </li>
+            </ul>
+        </li>
+    </f:for>
+</ul>
+</html>
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/composer.json b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/composer.json
new file mode 100644
index 000000000000..3dafef50c9cf
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/composer.json
@@ -0,0 +1,19 @@
+{
+    "name": "typo3tests/parent-child-translation",
+    "type": "typo3-cms-extension",
+    "description": "Test extension for Forge issue #92768",
+	"license": "GPL-2.0-or-later",
+	"require": {
+		"typo3/cms-core": "13.0.*@dev"
+	},
+    "autoload": {
+        "psr-4": {
+            "TYPO3Tests\\ParentChildTranslation\\": "Classes/"
+        }
+    },
+    "extra": {
+        "typo3/cms": {
+            "extension-key": "parent_child_translation"
+        }
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_emconf.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_emconf.php
new file mode 100644
index 000000000000..41968970ebd3
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_emconf.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+$EM_CONF[$_EXTKEY] = [
+    'title' => 'parent_child_translation',
+    'description' => 'Test extension for Forge issue #92768',
+    'category' => 'example',
+    'author' => 'TYPO3 core team',
+    'author_company' => '',
+    'author_email' => '',
+    'state' => 'stable',
+    'version' => '13.0.0',
+    'constraints' => [
+        'depends' => [
+            'typo3' => '13.0.0',
+        ],
+        'conflicts' => [],
+        'suggests' => [],
+    ],
+];
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_localconf.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_localconf.php
new file mode 100644
index 000000000000..c02e4dc1030c
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_localconf.php
@@ -0,0 +1,18 @@
+<?php
+
+use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
+use TYPO3Tests\ParentChildTranslation\Controller\MainController;
+
+defined('TYPO3') or die();
+
+ExtensionUtility::configurePlugin(
+    'ParentChildTranslation',
+    'ParentChildTranslation',
+    [
+        MainController::class => 'list',
+    ],
+    // non-cacheable actions
+    [
+        MainController::class => 'list',
+    ]
+);
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_tables.sql b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_tables.sql
new file mode 100644
index 000000000000..2e839042fbf9
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/ext_tables.sql
@@ -0,0 +1,24 @@
+#
+# Table structure for table 'tx_parentchildtranslation_domain_model_main'
+#
+CREATE TABLE tx_parentchildtranslation_domain_model_main (
+	title varchar(255) NOT NULL DEFAULT '',
+	child int(11) unsigned DEFAULT '0' NOT NULL,
+	squeeze int(11) unsigned DEFAULT '0' NOT NULL,
+);
+
+#
+# Table structure for table 'tx_parentchildtranslation_domain_model_squeeze'
+#
+CREATE TABLE tx_parentchildtranslation_domain_model_squeeze (
+	title varchar(255) NOT NULL DEFAULT '',
+	parent int(11) unsigned DEFAULT '0' NOT NULL,
+	child int(11) unsigned DEFAULT '0' NOT NULL,
+);
+
+#
+# Table structure for table 'tx_parentchildtranslation_domain_model_child'
+#
+CREATE TABLE tx_parentchildtranslation_domain_model_child (
+	title varchar(255) NOT NULL DEFAULT ''
+);
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/parentChildTranslationExampleData.csv b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/parentChildTranslationExampleData.csv
new file mode 100644
index 000000000000..5395f1c45058
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/parentChildTranslationExampleData.csv
@@ -0,0 +1,24 @@
+pages,,,,,,,
+,uid,pid,sys_language_uid,l10n_parent,title,,
+,1,0,0,0,ParentChildTranslation,,
+,2,0,1,1,ElternKindÃœbersetzung,,
+tx_parentchildtranslation_domain_model_child,,,,,,,
+,uid,pid,sys_language_uid,l10n_parent,title,,
+,1,1,0,0,Child 1 EN,,
+,2,1,0,0,Child 2 EN,,
+,3,1,1,1,Kind 1 DE,,
+,4,1,1,2,Kind 2 DE,,
+,5,1,0,0,Child 3 EN,,
+,6,1,1,5,Kind 3 DE,,
+tx_parentchildtranslation_domain_model_main,,,,,,,
+,uid,pid,sys_language_uid,l10n_parent,title,child,squeeze
+,1,1,-1,0,Parent 1,1,1
+,2,1,-1,0,Parent 2,2,1
+tx_parentchildtranslation_domain_model_squeeze,,,,,,,
+,uid,pid,sys_language_uid,l10n_parent,title,parent,child
+,1,1,-1,0,Squeeze 1,1,1
+,2,1,-1,0,Squeeze 2,2,5
+tt_content,,,,,,,
+,uid,pid,sys_language_uid,l18n_parent,header,CType,list_type
+,1,1,0,0,Parent Child Translation,list,parentchildtranslation_parentchildtranslation
+,2,1,1,1,Eltern Kind Ãœbersetzung,list,parentchildtranslation_parentchildtranslation
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/ParentChildTranslationTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/ParentChildTranslationTest.php
new file mode 100644
index 000000000000..d5922b14c5e3
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Functional/Persistence/ParentChildTranslationTest.php
@@ -0,0 +1,94 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Extbase\Tests\Functional\Persistence;
+
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+use TYPO3Tests\ParentChildTranslation\Domain\Repository\MainRepository;
+
+final class ParentChildTranslationTest extends FunctionalTestCase
+{
+    protected $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation'];
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->importCSVDataSet(__DIR__ . '/Fixtures/parentChildTranslationExampleData.csv');
+    }
+
+    /**
+     * @test
+     */
+    public function localizeChildrenOfAllLanguageElementToDefaultLanguage(): void
+    {
+        $query = $this->get(MainRepository::class)->createQuery();
+        $results = $query->execute();
+
+        self::assertCount(2, $results);
+
+        $children = [];
+        foreach ($results as $main) {
+            $children[] = $main->getChild()->getTitle();
+            $children[] = $main->getSqueeze()[0]->getChild()->getTitle();
+        }
+
+        self::assertSame(
+            [
+                'Child 1 EN',
+                'Child 1 EN',
+                'Child 2 EN',
+                'Child 3 EN',
+            ],
+            $children
+        );
+    }
+
+    /**
+     * @test
+     */
+    public function localizesChildrenOfAllLanguageElementToTranslation(): void
+    {
+        $query = $this->get(MainRepository::class)->createQuery();
+        $querySettings = $query->getQuerySettings();
+        $querySettings->setStoragePageIds([1]);
+        $querySettings->setRespectSysLanguage(true);
+        $querySettings->setLanguageUid(1);
+        $querySettings->setLanguageOverlayMode('0');
+
+        $results = $query->execute();
+
+        self::assertCount(2, $results);
+
+        $children = [];
+        foreach ($results as $main) {
+            $children[] = $main->getChild()->getTitle();
+            $children[] = $main->getSqueeze()[0]->getChild()->getTitle();
+        }
+
+        self::assertSame(
+            [
+                'Kind 1 DE',
+                'Kind 1 DE',
+                'Kind 2 DE',
+                'Kind 3 DE',
+            ],
+            $children
+        );
+    }
+}
-- 
GitLab