Skip to content

Commit

Permalink
[BUGFIX] Only localize inline records that are not translated
Browse files Browse the repository at this point in the history
This patch ensures that DataHandler does not try to localize inline
records that already have a translation for the given language.

With the change, no confusing error message is shown to the editor
when the "Localize all records" or "Synchronize with original language"
action is used in inline elements.

Resolves: #88844
Releases: master, 10.4
Change-Id: I6573aa233b4ce9dbe010d944fc1d461cf68e57cc
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65059
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack <benni@typo3.org>
  • Loading branch information
derhansen authored and bmack committed Mar 28, 2021
1 parent 14b865a commit 72c82fe
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
21 changes: 21 additions & 0 deletions typo3/sysext/core/Classes/DataHandling/DataHandler.php
Expand Up @@ -4583,6 +4583,9 @@ protected function inlineLocalizeSynchronize($table, $id, $command)
// Perform synchronization/localization: Possibly add unlocalized records for original language:
if ($action === 'localize' || $action === 'synchronize') {
foreach ($elementsOriginal as $originalId => $item) {
if ($this->isRecordLocalized((string)$item['table'], (int)$item['id'], (int)$language)) {
continue;
}
$item['id'] = $this->localize($item['table'], $item['id'], $language);
$item['id'] = $this->overlayAutoVersionId($item['table'], $item['id']);
$dbAnalysisCurrent->itemArray[] = $item;
Expand All @@ -4593,6 +4596,9 @@ protected function inlineLocalizeSynchronize($table, $id, $command)
continue;
}
$item = $elementsOriginal[$childId];
if ($this->isRecordLocalized((string)$item['table'], (int)$item['id'], (int)$language)) {
continue;
}
$item['id'] = $this->localize($item['table'], $item['id'], $language);
$item['id'] = $this->overlayAutoVersionId($item['table'], $item['id']);
$dbAnalysisCurrent->itemArray[] = $item;
Expand Down Expand Up @@ -4627,6 +4633,21 @@ protected function inlineLocalizeSynchronize($table, $id, $command)
}
}

/**
* Returns true if a localization of a record exists.
*
* @param string $table
* @param int $uid
* @param int $language
* @return bool
*/
protected function isRecordLocalized(string $table, int $uid, int $language): bool
{
$row = BackendUtility::getRecordWSOL($table, $uid);
$localizations = BackendUtility::getRecordLocalization($table, $uid, $language, 'pid=' . (int)$row['pid']);
return !empty($localizations);
}

/*********************************************
*
* Cmd: delete
Expand Down
Expand Up @@ -497,4 +497,33 @@ public function localizePageWithSynchronizationAndCustomLocalizedHotel()
]
);
}

public function inlineLocalizeSynchronizeLocalizeMissing(): void
{
// Translate page 89 first
$this->actionService->copyRecordToLanguage(self::TABLE_Page, self::VALUE_PageId, self::VALUE_LanguageId);
// Localize CE 297 which has two hotels, those are localized, too.
$newTableIds = $this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdFirst, self::VALUE_LanguageId);
$this->recordIds['localizedContentId'] = $newTableIds['tt_content'][self::VALUE_ContentIdFirst];
$this->recordIds['localizedHotelId'] = $newTableIds['tx_irretutorial_1nff_hotel'][self::VALUE_HotelIdFirst];
// Delete one localized hotel (and its children) again.
// We end up with having one localized hotel child and a missing one, while both exist in default language.
$this->actionService->deleteRecord('tx_irretutorial_1nff_hotel', $this->recordIds['localizedHotelId']);
// Now inlineLocalizeSynchronize->localize - This is the 'localize all records' button when inline
// 'appearance' 'showAllLocalizationLink' has been enabled. It should re-localize the missing hotel again.
$this->actionService->invoke(
[],
[
'tt_content' => [
$this->recordIds['localizedContentId'] => [
'inlineLocalizeSynchronize' => [
'field' => 'tx_irretutorial_1nff_hotels',
'language' => 1,
'action' => 'localize',
],
],
],
]
);
}
}
Expand Up @@ -692,4 +692,13 @@ public function localizePageAddMonoglotHotelChildAndCopyPageWithLanguageSynchron
->setRecordIdentifier(self::TABLE_Page . ':' . self::VALUE_PageId)->setRecordField(self::FIELD_PageHotel)
->setTable(self::TABLE_Hotel)->setField('title')->setValues('Hotel #0', 'Hotel #007'));
}

/**
* @test
*/
public function inlineLocalizeSynchronizeLocalizeMissing(): void
{
parent::inlineLocalizeSynchronizeLocalizeMissing();
$this->assertAssertionDataSet('inlineLocalizeSynchronizeLocalizeMissing');
}
}
@@ -0,0 +1,97 @@
"pages",,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","l10n_source","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","tx_irretutorial_hotels",,
,1,0,256,0,0,0,0,0,0,0,0,0,"FunctionalTest",0,,
,88,1,256,0,0,0,0,0,0,0,0,0,"DataHandlerTest",0,,
,89,88,256,0,0,0,0,0,0,0,0,0,"Relations",1,,
,90,88,512,0,0,0,0,0,0,0,0,0,"Target",0,,
,91,88,256,0,1,89,89,0,0,0,0,0,"[Translate to Dansk:] Relations",0,,
"sys_language",,,,,,,,,,,,,,,,
,"uid","pid","hidden","title","flag",,,,,,,,,,,
,1,0,0,"Dansk","dk",,,,,,,,,,,
,2,0,0,"Deutsch","de",,,,,,,,,,,
"tt_content",,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","tx_irretutorial_1nff_hotels",,,
,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",2,,,
,298,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",1,,,
,299,89,384,0,1,297,297,0,0,0,0,"[Translate to Dansk:] Regular Element #1",2,,,
"tx_irretutorial_1nff_hotel",,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","offers"
,2,89,1,0,0,0,0,0,0,0,0,"Hotel #0",89,"pages",,0
,3,89,1,0,0,0,0,0,0,0,0,"Hotel #1",297,"tt_content",,2
,4,89,1026,0,0,0,0,0,0,0,0,"Hotel #2",297,"tt_content",,1
,5,89,1,0,0,0,0,0,0,0,0,"Hotel #1",298,"tt_content",,1
,6,89,1,1,1,3,3,0,0,0,0,"[Translate to Dansk:] Hotel #1",299,"tt_content",,2
,7,89,1,0,1,4,4,0,0,0,0,"[Translate to Dansk:] Hotel #2",299,"tt_content",,1
,8,89,2,0,1,3,3,0,0,0,0,"[Translate to Dansk:] Hotel #1",299,"tt_content",,2
"tx_irretutorial_1nff_offer",,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","prices"
,5,89,1,0,0,0,0,0,0,0,0,"Offer #1.1",3,"tx_irretutorial_1nff_hotel",,3
,6,89,1538,0,0,0,0,0,0,0,0,"Offer #1.2",3,"tx_irretutorial_1nff_hotel",,2
,7,89,1,0,0,0,0,0,0,0,0,"Offer #2.1",4,"tx_irretutorial_1nff_hotel",,1
,8,89,1,0,0,0,0,0,0,0,0,"Offer #1.1",5,"tx_irretutorial_1nff_hotel",,1
,9,89,1,1,1,5,5,0,0,0,0,"[Translate to Dansk:] Offer #1.1",6,"tx_irretutorial_1nff_hotel",,3
,10,89,514,1,1,6,6,0,0,0,0,"[Translate to Dansk:] Offer #1.2",6,"tx_irretutorial_1nff_hotel",,2
,11,89,1,0,1,7,7,0,0,0,0,"[Translate to Dansk:] Offer #2.1",7,"tx_irretutorial_1nff_hotel",,1
,12,89,1,0,1,5,5,0,0,0,0,"[Translate to Dansk:] Offer #1.1",8,"tx_irretutorial_1nff_hotel",,3
,13,89,2,0,1,6,6,0,0,0,0,"[Translate to Dansk:] Offer #1.2",8,"tx_irretutorial_1nff_hotel",,2
"tx_irretutorial_1nff_price",,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier",
,7,89,1,0,0,0,0,0,0,0,0,"Price #1.1.1",5,"tx_irretutorial_1nff_offer",,
,8,89,2562,0,0,0,0,0,0,0,0,"Price #1.1.2",5,"tx_irretutorial_1nff_offer",,
,9,89,4611,0,0,0,0,0,0,0,0,"Price #1.1.3",5,"tx_irretutorial_1nff_offer",,
,10,89,1,0,0,0,0,0,0,0,0,"Price #1.2.1",6,"tx_irretutorial_1nff_offer",,
,11,89,2562,0,0,0,0,0,0,0,0,"Price #1.2.2",6,"tx_irretutorial_1nff_offer",,
,12,89,1,0,0,0,0,0,0,0,0,"Price #2.1.1",7,"tx_irretutorial_1nff_offer",,
,13,89,1,0,0,0,0,0,0,0,0,"Price #1.1.1",8,"tx_irretutorial_1nff_offer",,
,14,89,1,1,1,7,7,0,0,0,0,"[Translate to Dansk:] Price #1.1.1",9,"tx_irretutorial_1nff_offer",,
,15,89,1026,1,1,8,8,0,0,0,0,"[Translate to Dansk:] Price #1.1.2",9,"tx_irretutorial_1nff_offer",,
,16,89,1027,1,1,9,9,0,0,0,0,"[Translate to Dansk:] Price #1.1.3",9,"tx_irretutorial_1nff_offer",,
,17,89,1,1,1,10,10,0,0,0,0,"[Translate to Dansk:] Price #1.2.1",10,"tx_irretutorial_1nff_offer",,
,18,89,514,1,1,11,11,0,0,0,0,"[Translate to Dansk:] Price #1.2.2",10,"tx_irretutorial_1nff_offer",,
,19,89,1,0,1,12,12,0,0,0,0,"[Translate to Dansk:] Price #2.1.1",11,"tx_irretutorial_1nff_offer",,
,20,89,1,0,1,7,7,0,0,0,0,"[Translate to Dansk:] Price #1.1.1",12,"tx_irretutorial_1nff_offer",,
,21,89,514,0,1,8,8,0,0,0,0,"[Translate to Dansk:] Price #1.1.2",12,"tx_irretutorial_1nff_offer",,
,22,89,515,0,1,9,9,0,0,0,0,"[Translate to Dansk:] Price #1.1.3",12,"tx_irretutorial_1nff_offer",,
,23,89,1,0,1,10,10,0,0,0,0,"[Translate to Dansk:] Price #1.2.1",13,"tx_irretutorial_1nff_offer",,
,24,89,2,0,1,11,11,0,0,0,0,"[Translate to Dansk:] Price #1.2.2",13,"tx_irretutorial_1nff_offer",,
"sys_refindex",,,,,,,,,,,,,,,,
,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,
,"58521c3fb6b7050e33ae71d02a7ac20d","pages",89,"tx_irretutorial_hotels",,,,0,0,"tx_irretutorial_1nff_hotel",2,,,,,
,"74f844144854e2f894e8a22e620948d5","tt_content",297,"tx_irretutorial_1nff_hotels",,,,0,0,"tx_irretutorial_1nff_hotel",3,,,,,
,"4db47dff0b7cfc1011b50654d6ae26ba","tt_content",297,"tx_irretutorial_1nff_hotels",,,,1,0,"tx_irretutorial_1nff_hotel",4,,,,,
,"1ea8fb364449dd57ef33bf410d0d97ce","tt_content",298,"tx_irretutorial_1nff_hotels",,,,0,0,"tx_irretutorial_1nff_hotel",5,,,,,
,"6341e914a1bc771531b04a589f1e6c10","tx_irretutorial_1nff_hotel",3,"offers",,,,0,0,"tx_irretutorial_1nff_offer",5,,,,,
,"b6b18aded51cc224658c8eda1e009117","tx_irretutorial_1nff_hotel",3,"offers",,,,1,0,"tx_irretutorial_1nff_offer",6,,,,,
,"1c63417300a4a2423a0206cbc1cc6430","tx_irretutorial_1nff_hotel",4,"offers",,,,0,0,"tx_irretutorial_1nff_offer",7,,,,,
,"0db25b4f2fa1f8ab4d3296280222e2b5","tx_irretutorial_1nff_hotel",5,"offers",,,,0,0,"tx_irretutorial_1nff_offer",8,,,,,
,"0fc0d09ae681642e4bc17ef8e338b20e","tx_irretutorial_1nff_offer",5,"prices",,,,0,0,"tx_irretutorial_1nff_price",7,,,,,
,"ef81102fb56d455adf439a444ec05777","tx_irretutorial_1nff_offer",5,"prices",,,,1,0,"tx_irretutorial_1nff_price",8,,,,,
,"0be6b4051958ba5e752ac09f1b88ac7a","tx_irretutorial_1nff_offer",5,"prices",,,,2,0,"tx_irretutorial_1nff_price",9,,,,,
,"447af67bf50f6b2e12eeb8928b53849b","tx_irretutorial_1nff_offer",6,"prices",,,,0,0,"tx_irretutorial_1nff_price",10,,,,,
,"b509b296e32d7a2ee0b525f3cb04b30c","tx_irretutorial_1nff_offer",6,"prices",,,,1,0,"tx_irretutorial_1nff_price",11,,,,,
,"3cd13aad565798bc7837b17d09eae98a","tx_irretutorial_1nff_offer",7,"prices",,,,0,0,"tx_irretutorial_1nff_price",12,,,,,
,"2abe914437799afd8d74ff900e1ad9ea","tx_irretutorial_1nff_offer",8,"prices",,,,0,0,"tx_irretutorial_1nff_price",13,,,,,
,"583b9974d1df1d9efb695cdabfe53a73","pages",91,"l10n_parent",,,,0,0,"pages",89,,,,,
,"7c8c9b61b9e0a4503746dc43ba280829","tx_irretutorial_1nff_price",19,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",12,,,,,
,"7a9ef38af3fb8b25c5ccf23635ebadbf","tx_irretutorial_1nff_offer",11,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_offer",7,,,,,
,"14a321d5785ee3f32533644f6842f66d","tx_irretutorial_1nff_offer",11,"prices",,,,0,0,"tx_irretutorial_1nff_price",19,,,,,
,"cf7e2c4470a57ee188db50ef48ffb4ff","tx_irretutorial_1nff_hotel",7,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_hotel",4,,,,,
,"7168e38e79af70018f9ed09c164b0f8e","tx_irretutorial_1nff_hotel",7,"offers",,,,0,0,"tx_irretutorial_1nff_offer",11,,,,,
,"eed4d62814f2d515b4d7de94badbace1","tt_content",299,"l18n_parent",,,,0,0,"tt_content",297,,,,,
,"8383c20f5ece68a05f4e73423ceb4f69","tt_content",299,"tx_irretutorial_1nff_hotels",,,,0,0,"tx_irretutorial_1nff_hotel",7,,,,,
,"a7ec526f65745a9ed027b2a10933fdd6","tx_irretutorial_1nff_price",20,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",7,,,,,
,"b125eed346ebc5c4c2a2eb8de1dd8395","tx_irretutorial_1nff_price",21,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",8,,,,,
,"6561e05f3d575d709c6d584eae451b38","tx_irretutorial_1nff_price",22,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",9,,,,,
,"0df9080aee368183935c3a52d6b48207","tx_irretutorial_1nff_price",23,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",10,,,,,
,"f319508e16f6b014460480a0695d66f0","tx_irretutorial_1nff_price",24,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_price",11,,,,,
,"03ab6236716ead91993a153bfe31ce50","tx_irretutorial_1nff_offer",12,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_offer",5,,,,,
,"8c2094cd97152334826cfac5852aa42a","tx_irretutorial_1nff_offer",12,"prices",,,,0,0,"tx_irretutorial_1nff_price",20,,,,,
,"cec60d2e24f81281c55c7fabb028bbe6","tx_irretutorial_1nff_offer",12,"prices",,,,1,0,"tx_irretutorial_1nff_price",21,,,,,
,"2feab04553408f34c56d822e362c375d","tx_irretutorial_1nff_offer",12,"prices",,,,2,0,"tx_irretutorial_1nff_price",22,,,,,
,"be8429033419f51acae7b6b2a3b5efd3","tx_irretutorial_1nff_offer",13,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_offer",6,,,,,
,"054a89b5682e08b475e25c52175099dd","tx_irretutorial_1nff_offer",13,"prices",,,,0,0,"tx_irretutorial_1nff_price",23,,,,,
,"9e24b979fd462050c6f3c11fbc38ba95","tx_irretutorial_1nff_offer",13,"prices",,,,1,0,"tx_irretutorial_1nff_price",24,,,,,
,"f8b6ffa451f3fc6c172286643eae0364","tx_irretutorial_1nff_hotel",8,"l18n_parent",,,,0,0,"tx_irretutorial_1nff_hotel",3,,,,,
,"c5adc7befc1ffbaa1d0ef2870b6ff87c","tx_irretutorial_1nff_hotel",8,"offers",,,,0,0,"tx_irretutorial_1nff_offer",12,,,,,
,"9472e354e3d184330c365c2d28841095","tx_irretutorial_1nff_hotel",8,"offers",,,,1,0,"tx_irretutorial_1nff_offer",13,,,,,
,"8533721c12fa2a6d3ead3d44e85818db","tt_content",299,"tx_irretutorial_1nff_hotels",,,,1,0,"tx_irretutorial_1nff_hotel",8,,,,,
Expand Up @@ -538,4 +538,14 @@ public function modifyAndDiscardAndModifyParentWithHotelChild()
self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
->setTable(self::TABLE_Hotel)->setField('title')->setValues('Testing #2'));
}

/**
* @test
* Publish, PublishAll and Discard currently not implemented - they make little sense
*/
public function inlineLocalizeSynchronizeLocalizeMissing(): void
{
parent::inlineLocalizeSynchronizeLocalizeMissing();
$this->assertAssertionDataSet('inlineLocalizeSynchronizeLocalizeMissing');
}
}

0 comments on commit 72c82fe

Please sign in to comment.