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 translations
  • src/Hook/ContentTranslationHooks.php — attaches the constraint to all translatable entity types via hook_entity_type_alter; guards on both content_translation and canvas_dev_translation being installed
  • tests/src/Kernel/Translation/ContentComponentTreeSymmetricalTranslationTestBase.php🆕 shared base class, lifted from the existing ComponentTreeFieldSymmetricalTranslationSynchronizerTest.
  • 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 — changes field.value.link URI schema type from translatable_uri to label — 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)

Edited by Wim Leers

Merge request reports

Loading