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
- Enable content translation for a node type and install Display Builder entity_view_override on that bundle
- Create a node in the default language (e.g., English) and add a translation (e.g., French)
- Open the Display Builder for the French translation (/fr/node/{nid}/display/default)
- Make layout changes and click Publish
- 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
Issue fork display_builder-3611826
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
Comment #3
mogtofu33 commentedComment #4
pdureau commentedComment #5
ipumpkinupdate status Needs review
Comment #6
ipumpkinComment #7
ipumpkinComment #8
mogtofu33 commentedComment #9
ipumpkinrebase and test
Comment #10
mogtofu33 commentedComment #11
pdureau commentedThanks a lot ZiQiang for the ticket and the proposal 🙏
Overview
So, if my understanding is right, the issue is about
EntityViewOverridebuildable only, so the main work is indisplay_builder_entity_view:EntityViewOverridesController::title()update to print languageentity_deletehook and a newentity_translation_deletehook: 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?EntityViewOverridebuildable plugin. Let's check once the Instance entity ID change is clear.InstanceEntityViewDisplayOverrideAccessControlTest::testInstanceEntityViewDisplayAccess(), only about the Instance entity ID changeOutside
display_builder_entity_view:src/Controller/IntegrationControllerBase.php: may not be directly related to the change, but it is a nice precautionsrc/DisplayBuildablePluginBase.php: feeding the existinglangcodefield when creating an instance was missingInstance::label(): related to the Instance entity ID changesrc/HtmxEvents.phpdisplay_builder_update_11105: why not adisplay_builder_update_11105display_builder_entity_view_update_11101? And this instance ID change again.Instance entity ID change
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:enandnode:54:zhand the overrides stored infield_teaser. It will generate a single instance entity with 2 translations: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.
Comment #12
ipumpkin@pdureau Thank you for your detailed review comments.I will re-examine my code scheme.
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.
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.
Comment #13
ipumpkinUsing 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.
Comment #14
mogtofu33 commentedThat'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.
Comment #15
pdureau commentedIf 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:
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.
Comment #16
pdureau commentedThat's interesting, thanks for the explanation, but let's hope the new direction will prevent us to send this info to Javascript.
Comment #17
ipumpkinI 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...