Resolve "Add validation constraint similar to core's `ContentTranslationSynchronizedFieldsConstraint` to guarantee symmetrical translations have the same values as the default translation for non-translatable input keys"
Adds a Drupal validation constraint (ComponentTreeSymmetricalTranslation) that ensures non-translatable component input keys in non-default translations match the default translation, enforcing the symmetrical translation invariant at validation time.
ComponentTreeFieldSymmetricalTranslationSynchronizer (!882 (merged)) already prevents divergence at save time by synchronizing non-translatable keys. This MR adds the missing validation layer so the constraint fires if any code path bypasses the synchronizer (e.g., direct field manipulation, future import flows, or migration).
It will also unblock Add `canvas-validate-component-trees` Drupal CL... (#3591667) to confidently validate (symmetrically) translated component trees.
New files:
src/Plugin/Validation/Constraint/ComponentTreeSymmetricalTranslationConstraint(Validator).php— entity-level constraint, validates non-translatable inputs match default translation across all non-default translationssrc/Hook/ContentTranslationHooks.php— attaches the constraint to all translatable entity types viahook_entity_type_alter; guards on bothcontent_translationandcanvas_dev_translationbeing installedtests/src/Kernel/Translation/ContentComponentTreeSymmetricalTranslationTestBase.php—🆕 shared base class, lifted from the existingComponentTreeFieldSymmetricalTranslationSynchronizerTest.tests/src/Kernel/Translation/ComponentTreeSymmetricalTranslationConstraintValidatorTest.php— tests the validation constraint; 4 succinct scenarios in a single test
Modified files:
modules/canvas_dev_translation/src/Hook/ConfigTranslationSupportHooks.php— changesfield.value.linkURI schema type fromtranslatable_uritolabel— reason: !1248 (comment 1259117)tests/src/Kernel/Translation/ComponentTreeFieldSymmetricalTranslationSynchronizerTest.php— now uses the lifted base class, and updated to assert validation errors triggered by the new validation constraint before saving, because that's when the synchronizer is triggered
The hook guard has a @todo to adopt HookDependsOnModule once Canvas requires Drupal 11.5 (#3548805).
Testing instructions
- Run
composer run phpunit -- tests/src/Kernel/Translation/ComponentTreeSymmetricalTranslationConstraintValidatorTest.php— 2 tests pass - Run
composer run phpunit -- tests/src/Kernel/Translation/ComponentTreeFieldSymmetricalTranslationSynchronizerTest.php— 2 tests pass, no regressions - Run
composer run lint— no PHPCS/PHPStan errors introduced by this MR (6 pre-existing PHPStan errors unrelated to this work)
AI disclosure
This MR was developed with AI assistance (Claude Sonnet 4.6 via Claude Code) per Drupal.org's policy on AI contributions.
Closes #3591650 (closed)