Skip to content

Commit 140669d

Browse files
astridhauboldlolli42
authored andcommitted
[BUGFIX] Preserve language of translations on copy
When copying an element with existing translations, the language of those translations must not be changed. In addition, when copying or moving a -1 element to default language, it must keep the value -1. Resolves: #106334 Resolves: #83533 Resolves: #39054 Related: #89787 Releases: main, 13.4 Change-Id: Id6663aa8a0efe435edd972ff496d98ac31609951 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/88827 Tested-by: Benni Mack <benni@typo3.org> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Benni Mack <benni@typo3.org>
1 parent a789a83 commit 140669d

File tree

4 files changed

+72
-7
lines changed

4 files changed

+72
-7
lines changed

typo3/sysext/core/Classes/DataHandling/DataHandler.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,10 +3284,24 @@ public function process_cmdmap()
32843284

32853285
foreach ($incomingCmdArray as $command => $value) {
32863286
$pasteUpdate = false;
3287+
$schema = $this->tcaSchemaFactory->get($table);
3288+
$languageField = $schema->isLanguageAware() ? $schema->getCapability(TcaSchemaCapability::Language)->getLanguageField()->getName() : null;
32873289
if (is_array($value) && isset($value['action']) && $value['action'] === 'paste') {
32883290
// Extended paste command: $command is set to "move" or "copy"
32893291
// $value['update'] holds field/value pairs which should be updated after copy/move operation
32903292
// $value['target'] holds original $value (target of move/copy)
3293+
if ($languageField) {
3294+
$row = BackendUtility::getRecord($table, $id);
3295+
$languageId = $value['update'][$languageField] ?? null;
3296+
// Update language field after copy/move only if language was changed
3297+
if ($languageId !== null && (int)$languageId === $row[$languageField]) {
3298+
unset($value['update'][$languageField]);
3299+
}
3300+
// Reset language for a -1 element from original record if copied or moved into language 0
3301+
if ($row[$languageField] === -1 && (int)$languageId === 0) {
3302+
$value['update'][$languageField] = $row[$languageField];
3303+
}
3304+
}
32913305
$pasteUpdate = $value['update'];
32923306
$value = $value['target'];
32933307
}
@@ -3345,12 +3359,8 @@ public function process_cmdmap()
33453359
foreach ($this->copyMappingArray as $procTable => $copyProcIds) {
33463360
foreach ($copyProcIds as $copyProcId) {
33473361
if ($copyProcId !== $procId) {
3348-
$schema = $this->tcaSchemaFactory->get($procTable);
3349-
if ($schema->isLanguageAware()) {
3350-
$languageField = $schema->getCapability(TcaSchemaCapability::Language)->getLanguageField()->getName();
3351-
if (isset($pasteUpdate[$languageField])) {
3352-
$pasteDatamap[$procTable][$copyProcId][$languageField] = $pasteUpdate[$languageField];
3353-
}
3362+
if ($languageField !== null && isset($pasteUpdate[$languageField])) {
3363+
$pasteDatamap[$procTable][$copyProcId][$languageField] = $pasteUpdate[$languageField];
33543364
}
33553365
}
33563366
}

typo3/sysext/core/Tests/Functional/DataScenarios/Regular/AbstractActionTestCase.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,23 @@ public function copyContentToLanguageFromNonDefaultLanguage(): void
146146

147147
public function copyLocalizedContent(): void
148148
{
149-
$copiedTableIds = $this->actionService->copyRecord(self::TABLE_Content, self::VALUE_ContentIdFirst, self::VALUE_PageId);
149+
// When a record is copied in the backend, this data is always passed along
150+
$recordData = [
151+
'colPos' => 0, // target colPos
152+
'sys_language_uid' => 0, // target language
153+
];
154+
$copiedTableIds = $this->actionService->copyRecord(self::TABLE_Content, self::VALUE_ContentIdFirst, self::VALUE_PageId, $recordData);
150155
$this->recordIds['copiedContentId'] = $copiedTableIds[self::TABLE_Content][self::VALUE_ContentIdFirst];
151156
}
157+
public function copyLanguageAllContent(): void
158+
{
159+
$recordData = [
160+
'colPos' => 0, // target colPos
161+
'sys_language_uid' => 0, // target language – for a -1 element, this can be 0 or -1 depending on paste position
162+
];
163+
$copiedTableIds = $this->actionService->copyRecord(self::TABLE_Content, self::VALUE_ContentLanguageAll, self::VALUE_PageId, $recordData);
164+
$this->recordIds['copiedContentId'] = $copiedTableIds[self::TABLE_Content][self::VALUE_ContentLanguageAll];
165+
}
152166

153167
public function copyLocalizedContentToLocalizedPage(): void
154168
{

typo3/sysext/core/Tests/Functional/DataScenarios/Regular/Modify/ActionTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ public function copyLocalizedContent(): void
234234
->setTable(self::TABLE_Content)->setField('header')->setValues('[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1 (copy 1)'));
235235
}
236236

237+
#[Test]
238+
public function copyLanguageAllContent(): void
239+
{
240+
parent::copyLanguageAllContent();
241+
$this->assertCSVDataSet(__DIR__ . '/DataSet/copyLanguageAllContent.csv');
242+
243+
$response = $this->executeFrontendSubRequest((new InternalRequest())->withPageId(self::VALUE_PageId));
244+
$responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
245+
self::assertThat($responseSections, (new HasRecordConstraint())
246+
->setTable(self::TABLE_Content)->setField('header')->setValues('Language all element'));
247+
}
248+
237249
#[Test]
238250
public function copyLocalizedContentToLocalizedPage(): void
239251
{
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"pages",,,,,,,,,,,,,
2+
,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","slug"
3+
,1,0,256,0,0,0,0,0,0,0,"FunctionalTest","/"
4+
,50,0,512,0,0,0,0,0,0,0,"Second Root Page","/"
5+
,51,50,128,0,0,0,0,0,0,0,"DataHandlerTest in second tree","/data-handler"
6+
,52,51,128,0,0,0,0,0,0,0,"Relations in second tree","/data-handler/relations"
7+
,88,1,256,0,0,0,0,0,0,0,"DataHandlerTest","/data-handler"
8+
,89,88,256,0,0,0,0,0,0,0,"Relations","/data-handler/relations"
9+
,90,88,512,0,0,0,0,0,0,0,"Target","/data-handler/target"
10+
,91,88,256,0,1,89,0,0,0,0,"[Translate to Dansk:] Relations","/data-handler/translate-to-dansk-relations"
11+
,92,88,256,0,2,89,0,0,0,0,"[Translate to Deutsch:] Relations","/data-handler/translate-to-deutsch-relations"
12+
"tt_content",,,,,,,,,,,,,
13+
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l10n_source","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header"
14+
,200,88,256,0,0,0,0,0,0,0,0,"Regular Element #0"
15+
,201,88,512,0,-1,0,0,0,0,0,0,Language all element
16+
,297,89,384,0,0,0,0,0,0,0,0,"Regular Element #1"
17+
,298,89,512,0,0,0,0,0,0,0,0,"Regular Element #2"
18+
,299,89,768,0,0,0,0,0,0,0,0,"Regular Element #3"
19+
,300,89,1024,0,1,299,299,0,0,0,0,"[Translate to Dansk:] Regular Element #3"
20+
,301,89,384,0,1,297,297,0,0,0,0,"[Translate to Dansk:] Regular Element #1"
21+
,302,89,448,0,2,297,301,0,0,0,0,[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1
22+
,303,89,192,0,-1,0,0,0,0,0,0,Language all element
23+
"sys_refindex"
24+
,"hash","tablename","recuid","field","hidden","starttime","endtime","t3ver_state","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_field","ref_hidden","ref_starttime","ref_endtime","ref_t3ver_state","ref_sorting","ref_string"
25+
,"02aa95a647ed365ffeeac881bd1af449","pages",91,"l10n_parent",0,0,2147483647,0,,,,0,0,"pages",89,,0,0,2147483647,0,0,
26+
,"14f90231b8565c61decd2aeaebea6034","pages",92,"l10n_parent",0,0,2147483647,0,,,,0,0,"pages",89,,0,0,2147483647,0,0,
27+
,"ca4f164be617724388f00923729e8558","tt_content",300,"l18n_parent",0,0,2147483647,0,,,,0,0,"tt_content",299,,0,0,2147483647,0,0,
28+
,"3676712de719382fe386617c1942c940","tt_content",301,"l18n_parent",0,0,2147483647,0,,,,0,0,"tt_content",297,,0,0,2147483647,0,0,
29+
,"2b5621b6ac407f06a71e517bf98c9c94","tt_content",302,"l18n_parent",0,0,2147483647,0,,,,0,0,"tt_content",297,,0,0,2147483647,0,0,

0 commit comments

Comments
 (0)