diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index 538dffd55c4576bf0939f3574fdb81e73eabdecb..a004ebad8142fabee4c9e29145bc573f5e6a60a9 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -256,7 +256,8 @@ public function createRevision(RevisionableInterface $entity, $default = TRUE, $ /** @var \Drupal\Core\Entity\ContentEntityInterface $default_revision */ $default_revision = $this->load($entity->id()); - foreach ($default_revision->getTranslationLanguages() as $langcode => $language) { + $translation_languages = $default_revision->getTranslationLanguages(); + foreach ($translation_languages as $langcode => $language) { if ($langcode == $active_langcode) { continue; } @@ -281,6 +282,14 @@ public function createRevision(RevisionableInterface $entity, $default = TRUE, $ $keep_untranslatable_fields = TRUE; } + // Make sure we do not inadvertently recreate removed translations. + foreach (array_diff_key($new_revision->getTranslationLanguages(), $translation_languages) as $langcode => $language) { + // Allow a new revision to be created for the active language. + if ($langcode !== $active_langcode) { + $new_revision->removeTranslation($langcode); + } + } + // The "original" property is used in various places to detect changes in // field values with respect to the stored ones. If the property is not // defined, the stored version is loaded explicitly. Since the merged diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php index cc3474575f424b255acbf9da20f662d565156650..616ee1640d7c2ce9f6babb54cf2b8aede81cb450 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php @@ -553,4 +553,39 @@ protected function doTestInternalProperties(ContentEntityInterface $entity) { $this->assertTrue($new_revision->isValidationRequired()); } + /** + * Tests that deleted translations are not accidentally restored. + * + * @covers ::createRevision + */ + public function testRemovedTranslations() { + /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ + $entity = EntityTestMulRev::create(['name' => 'Test 1.1 EN']); + $this->storage->save($entity); + + /** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */ + $it_revision = $this->storage->createRevision($entity->addTranslation('it')); + $it_revision->set('name', 'Test 1.2 IT'); + $this->storage->save($it_revision); + + /** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */ + $en_revision = $this->storage->createRevision($it_revision->getUntranslated(), FALSE); + $en_revision->set('name', 'Test 1.3 EN'); + $this->storage->save($en_revision); + + /** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */ + $it_revision = $this->storage->createRevision($it_revision); + $en_revision = $it_revision->getUntranslated(); + $en_revision->removeTranslation('it'); + $this->storage->save($en_revision); + + $revision_id = $this->storage->getLatestTranslationAffectedRevisionId($entity->id(), 'en'); + $en_revision = $this->storage->loadRevision($revision_id); + $en_revision = $this->storage->createRevision($en_revision); + $en_revision->set('name', 'Test 1.5 EN'); + $this->storage->save($en_revision); + $en_revision = $this->storage->loadRevision($en_revision->getRevisionId()); + $this->assertFalse($en_revision->hasTranslation('it')); + } + }