diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php index 0044b6b4fb4..bb1a924d71c 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraint; */ class EntityUntranslatableFieldsConstraint extends Constraint { - public $message = 'Non translatable fields can only be changed when updating the current revision or the original language.'; + public $defaultRevisionMessage = 'Non-translatable fields can only be changed when updating the current revision.'; + public $defaultTranslationMessage = 'Non-translatable fields can only be changed when updating the original language.'; } diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraintValidator.php index 6ac7d034b95..5b1ad1f5c99 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraintValidator.php @@ -49,10 +49,14 @@ class EntityUntranslatableFieldsConstraintValidator extends ConstraintValidator */ public function validate($entity, Constraint $constraint) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ + /** @var \Drupal\Core\Entity\Plugin\Validation\Constraint\EntityUntranslatableFieldsConstraint $constraint */ - // Untranslatable field restrictions apply only to pending revisions of - // multilingual entities. - if ($entity->isNew() || $entity->isDefaultRevision() || !$entity->isTranslatable() || !$entity->getEntityType()->isRevisionable()) { + // Untranslatable field restrictions apply only to revisions of multilingual + // entities. + if ($entity->isNew() || !$entity->isTranslatable() || !$entity->getEntityType()->isRevisionable()) { + return; + } + if ($entity->isDefaultRevision() && !$entity->isDefaultTranslationAffectedOnly()) { return; } @@ -63,18 +67,20 @@ class EntityUntranslatableFieldsConstraintValidator extends ConstraintValidator // a pending revision contains only one affected translation. Even in this // case, multiple translations would be affected in a single revision, if we // allowed changes to untranslatable fields while editing non-default - // translations, so that is forbidden too. + // translations, so that is forbidden too. For the same reason, when changes + // to untranslatable fields affect all translations, we can only allow them + // in default revisions. if ($this->hasUntranslatableFieldsChanges($entity)) { if ($entity->isDefaultTranslationAffectedOnly()) { foreach ($entity->getTranslationLanguages(FALSE) as $langcode => $language) { if ($entity->getTranslation($langcode)->hasTranslationChanges()) { - $this->context->addViolation($constraint->message); + $this->context->addViolation($constraint->defaultTranslationMessage); break; } } } else { - $this->context->addViolation($constraint->message); + $this->context->addViolation($constraint->defaultRevisionMessage); } } } diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php index d5cc5330e65..cc3474575f4 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDecoupledTranslationRevisionsTest.php @@ -234,6 +234,7 @@ class EntityDecoupledTranslationRevisionsTest extends EntityKernelTestBase { ['en', TRUE, TRUE], ['it', FALSE, TRUE, FALSE], ['en', FALSE, TRUE], + ['it', TRUE, TRUE, FALSE], ['it', FALSE], ['it', TRUE], ['en', TRUE, TRUE], @@ -492,6 +493,35 @@ class EntityDecoupledTranslationRevisionsTest extends EntityKernelTestBase { return call_user_func_array('sprintf', $params); } + /** + * Checks that changes to multiple translations are handled correctly. + * + * @covers ::createRevision + * @covers \Drupal\Core\Entity\Plugin\Validation\Constraint\EntityUntranslatableFieldsConstraintValidator::validate + */ + public function testMultipleTranslationChanges() { + // Configure the untranslatable fields edit mode. + $this->state->set('entity_test.untranslatable_fields.default_translation_affected', TRUE); + $this->bundleInfo->clearCachedBundles(); + + $entity = EntityTestMulRev::create(); + $entity->get('name')->value = 'Test 1.1 EN'; + $entity->get('non_mul_field')->value = 'Test 1.1'; + $this->storage->save($entity); + + /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */ + $revision = $this->storage->createRevision($entity->addTranslation('it')); + $revision->get('name')->value = 'Test 1.2 IT'; + $this->storage->save($revision); + + $revision = $this->storage->createRevision($revision->getTranslation('en'), FALSE); + $revision->get('non_mul_field')->value = 'Test 1.3'; + $revision->getTranslation('it')->get('name')->value = 'Test 1.3 IT'; + $violations = $revision->validate(); + $this->assertCount(1, $violations); + $this->assertEquals('Non-translatable fields can only be changed when updating the original language.', $violations[0]->getMessage()); + } + /** * Tests that internal properties are preserved while creating a new revision. */