diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 2c62589fa2..0343cf3274 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -90,6 +90,16 @@ protected $defaultLangcode; /** + * Local cache for the original default language code. + * + * This additional property is needed to retrieve the original default + * language code in case the default language code is changed. + * + * @var string + */ + protected $originalDefaultLangcode; + + /** * An array of entity translation metadata. * * An associative array keyed by translation language code. Every value is an @@ -679,6 +689,13 @@ protected function setDefaultLangcode() { } } + // Populate the property holding the original default language code, but + // only if it isn't already set as subsequent calls of + // ::setDefaultLangcode() might alter the default language code. + if (!isset($this->originalDefaultLangcode)) { + $this->originalDefaultLangcode = $this->defaultLangcode; + } + // This needs to be initialized manually as it is skipped when instantiating // the language field object to avoid infinite recursion. if (!empty($this->fields[$this->langcodeKey])) { @@ -831,6 +848,7 @@ protected function initializeTranslation($langcode) { $translation->typedData = NULL; $translation->loadedRevisionId = &$this->loadedRevisionId; $translation->isDefaultRevision = &$this->isDefaultRevision; + $translation->originalDefaultLangcode = &$this->originalDefaultLangcode; return $translation; } @@ -930,6 +948,13 @@ public function getTranslationLanguages($include_default = TRUE) { } /** + * {@inheritdoc} + */ + public function getOriginalDefaultLangcode() { + return $this->originalDefaultLangcode; + } + + /** * Updates the original values with the interim changes. */ public function updateOriginalValues() { @@ -1098,7 +1123,8 @@ public function __clone() { // Ensure that the following properties are actually cloned by // overwriting the original references with ones pointing to copies of // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys, - // translatableEntityKeys, values and isDefaultRevision. + // translatableEntityKeys, values, isDefaultRevision and + // originalDefaultLangcode. $enforce_is_new = $this->enforceIsNew; $this->enforceIsNew = &$enforce_is_new; @@ -1123,6 +1149,9 @@ public function __clone() { $default_revision = $this->isDefaultRevision; $this->isDefaultRevision = &$default_revision; + $original_default_langcode = $this->originalDefaultLangcode; + $this->originalDefaultLangcode = &$original_default_langcode; + foreach ($this->fields as $name => $fields_by_langcode) { $this->fields[$name] = []; // Untranslatable fields may have multiple references for the same field diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index d045152f6a..d7bc1d3eaa 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -71,4 +71,11 @@ public function getLoadedRevisionId(); */ public function updateLoadedRevisionId(); + /** + * Returns the original default language code. + * + * @return string + */ + public function getOriginalDefaultLangcode(); + } diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php index 2fb171dadb..ab71f6559d 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php @@ -15,7 +15,7 @@ class EntityChangedConstraintValidator extends ConstraintValidator { */ public function validate($entity, Constraint $constraint) { if (isset($entity)) { - /** @var \Drupal\Core\Entity\EntityInterface $entity */ + /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ if (!$entity->isNew()) { $saved_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id()); // Ensure that all the entity translations match their current version @@ -32,11 +32,16 @@ public function validate($entity, Constraint $constraint) { // and is currently being saved. // @see \Drupal\node\NodeForm::form(). if ($saved_entity) { + /** @var \Drupal\Core\Entity\ContentEntityInterface $saved_entity */ foreach (array_keys($entity->getTranslationLanguages()) as $langcode) { // If the translation has been removed in the meanwhile we have to // prevent adding it back. $translation = $entity->getTranslation($langcode); - if (!$saved_entity->hasTranslation($langcode) && !$translation->isNewTranslation()) { + $saved_entity_langcode = $langcode; + if ($translation->isDefaultTranslation() && ($translation->getOriginalDefaultLangcode() != $translation->language()->getId())) { + $saved_entity_langcode = $translation->getOriginalDefaultLangcode(); + } + if (!$saved_entity->hasTranslation($saved_entity_langcode) && !$translation->isNewTranslation()) { $this->context->addViolation($constraint->message); break; } @@ -44,7 +49,7 @@ public function validate($entity, Constraint $constraint) { // translations is not sufficient since other translations may have // been edited and saved in the meanwhile. Therefore, compare the // changed timestamps of each entity translation individually. - if ($saved_entity->getTranslation($langcode)->getChangedTime() > $translation->getChangedTime()) { + if ($saved_entity->getTranslation($saved_entity_langcode)->getChangedTime() > $translation->getChangedTime()) { $this->context->addViolation($constraint->message); break; }