Problem/Motivation

When editing a Display Builder node override on a translated node page (e.g., French translation) and publishing, the layout data is written to the default language (e.g., English) node's field instead of the translation being edited.
The frontend rendering reads from the correct translation's field (since the node entity in the rendering context is the correct translation), so the published layout appears correct on the frontend. But the working copy (Instance entity) is shared across translations, and publishing overwrites whichever language's field the reconstructed plugin happens to load — always the default.

Steps to reproduce

  1. Enable content translation for a node type and install Display Builder entity_view_override on that bundle
  2. Create a node in the default language (e.g., English) and add a translation (e.g., French)
  3. Open the Display Builder for the French translation (/fr/node/{nid}/display/default)
  4. Make layout changes and click Publish
  5. Check the English translation's Display Builder — the French layout data has been written to the English node's field

Proposed resolution

The display_builder_instance entity ID for entity_view_override overrides follows this format:
entity_override__{entity_type}__{entity_id}__{field_name}
This ID contains no language information, so all translations of the same entity share a single Instance entity as their working copy.
When publish() is called (Instance::publish() → getBuildablePlugin() → EntityViewOverride::__construct()), the plugin is reconstructed from the stored buildable.configuration, which only contained entity_id (node ID, e.g. 123). No langcode was stored. The constructor then calls:
$entity = $storage->load($this->configuration['entity_id']);
This always loads the default translation of the entity in the current language context, regardless of which translation was being edited. Consequently, saveSources() writes to the default language node's field.

Remaining tasks

User interface changes

API changes

Data model changes

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

ipumpkin created an issue. See original summary.

mogtofu33’s picture

pdureau’s picture

ipumpkin’s picture

Status: Active » Needs review

update status Needs review

ipumpkin’s picture

Status: Needs review » Needs work
ipumpkin’s picture

Status: Needs work » Needs review
mogtofu33’s picture

Assigned: Unassigned » pdureau
ipumpkin’s picture

rebase and test

mogtofu33’s picture

pdureau’s picture

Assigned: pdureau » Unassigned
Status: Needs review » Needs work

Thanks a lot ZiQiang for the ticket and the proposal 🙏

Overview

So, if my understanding is right, the issue is about EntityViewOverride buildable only, so the main work is in display_builder_entity_view:

  • EntityViewOverridesController::title() update to print language
  • ⚠️ Update of entity_delete hook and a new entity_translation_delete hook: the logic seems a bit complex, so I am not sure I understand well, but I guess it is to delete all overrides of a specific language when the display config of the same language is deleted? Am I right? That's all or something else happens here?
  • ⚠️ A few updated methods in EntityViewOverride buildable plugin. Let's check once the Instance entity ID change is clear.
  • ⚠️ A little change in InstanceEntityViewDisplayOverrideAccessControlTest::testInstanceEntityViewDisplayAccess(), only about the Instance entity ID change

Outside display_builder_entity_view:

  • ✅ a little check in src/Controller/IntegrationControllerBase.php: may not be directly related to the change, but it is a nice precaution
  • src/DisplayBuildablePluginBase.php: feeding the existing langcode field when creating an instance was missing
  • ⚠️ Instance::label(): related to the Instance entity ID change
  • ⚠️I don''t understand why are we also modifying src/HtmxEvents.php
  • ⚠️ display_builder_update_11105: why not a display_builder_update_11105 display_builder_entity_view_update_11101? And this instance ID change again.

Instance entity ID change

The display_builder_instance entity ID for entity_view_override overrides follows this format:
entity_override__{entity_type}__{entity_id}__{field_name}
This ID contains no language information, so all translations of the same entity share a single Instance entity as their working copy.

Instance entity is translatable using the standard content translation API of Drupal. So I don't understand why we need to put the language code in the entity ID.

Let's take a 1 unique node with 2 translations (node:54:en and node:54:zh and the overrides stored in field_teaser. It will generate a single instance entity with 2 translations:

  • display_builder_instance:entity_override__node__54__field_teaser:en
  • display_builder_instance:entity_override__node__54__field_teaser:fr

Do we really for 2 different instance entities, one for each language ?

Because of the upcoming #3555110: Symmetric translation, it would be nice if Christian do the final review of this ticket.

ipumpkin’s picture

@pdureau Thank you for your detailed review comments.I will re-examine my code scheme.

Instance entity is translatable using the standard content translation API of Drupal. So I don't understand why we need to put the language code in the entity ID.

Let's take a 1 unique node with 2 translations (node:54:en and node:54:zh and the overrides stored in field_teaser. It will generate a single instance entity with 2 translations:

display_builder_instance:entity_override__node__54__field_teaser:en
display_builder_instance:entity_override__node__54__field_teaser:fr
Do we really for 2 different instance entities, one for each language

The reason for adding langcode in ID was that their historical steps were indistinguishable and would get mixed up; I will take a closer look at this later.

I don''t understand why are we also modifying src/HtmxEvents.php

Because some language codes contain hyphens(zh-hans), adding language codes to the ID causes JavaScript to fail to parse the ID correctly, resulting in a page error. Therefore, this was modified.

ipumpkin’s picture

Using translation to solve this problem would require a complete overhaul of the current history handling mechanism, as the history mechanism based on revision and default vision, as well as the undo and redo mechanisms, would need to be completely rewritten.

mogtofu33’s picture

That's surprising as our instance entity is translatable. I do not think there is a huge rewrite, more that we need to plug to existing translation mechanism.

Translation in Drupal is not perfect, and there is work in progress in core to make it better, there is helpers like language_audit. So I guess we need to POC around a bit more and see what's the best and avoid any 'custom' system around translation.

pdureau’s picture

Using translation to solve this problem would require a complete overhaul of the current history handling mechanism, as the history mechanism based on revision and default vision, as well as the undo and redo mechanisms, would need to be completely rewritten.

If we must reorganize InstanceStorage::redo(), ::undo(), ::getPast() and ::getFuture() to make them aware of translations, let's propose a change there.

I have the feeling it is better than tweaking the Instance ID.

For your information, we did a little mistake during the early days of the development: instead of considering Instance entity ID as an opaque string, we have put meaning into it, and we rely on this meaning in DisplayBuildableInterface::checkInstanceId(), ::getDisplayUrlFromInstanceId(), ::getUrlFromInstanceId().

It is not necessary anymore since the introduction of this field in Instance entity:

    $fields['buildable'] = BaseFieldDefinition::create('plugin')
      ->setSetting('plugin_manager_id', 'plugin.manager.display_buildable')
      ->setRequired(TRUE)
      ->setReadOnly(TRUE);

And we may be happen to remove the legacy methods some day: #3573905: Simplify DisplayBuildableInterface.

So, let's not add more meaning in Instance entity ID strings.

pdureau’s picture

I don''t understand why are we also modifying src/HtmxEvents.php

Because some language codes contain hyphens(zh-hans), adding language codes to the ID causes JavaScript to fail to parse the ID correctly, resulting in a page error. Therefore, this was modified.

That's interesting, thanks for the explanation, but let's hope the new direction will prevent us to send this info to Javascript.

ipumpkin’s picture

I have tried using instance translation mechanism to achieve multilingual support. It is completely certain that if a translation mechanism is used, the existing historical mechanism will need to be completely rewritten.

My overall thoughts on the translation are posted here; please point out any errors.
https://www.drupal.org/project/display_builder/issues/3615902#comment-16...