Problem/Motivation

See #2833049-14: ContentEntityBase::hasTranslationChanges will compare a forward revision with the default one instead of the newest forward revision.

Right now, using the createRevision() API to prepare a new revision uses the untranslatable fields of the current default revision. This does not make a big difference currently when just using regular untranslatable fields as they are not visible on the edit form. They are however visible when looking at the saved translation draft.

Example:

Content type 'Article' has an untranslatable image field and a translatable body text field. There is an existing published version in EN and a translation in DE. Then, the user creates an EN draft with a new image and a different text. Then, he also edits the DE translation and creates a new draft, updating the text also accordingly (lets say it describes the untranslatable image). In Edit, the image is hidden, but when then saving that draft, it still shows the old image.

This becomes a bigger problem with e.g. paragraphs, but then you can for example add completely new paragraphs with new translatable fields, which are then impossible to translate until you publish the EN draft. This goes against user expectations/requirements.

Proposed resolution

Basically, the proposal is to change createRevision() and specifically use the draft versions of the untranslatable fields, However, what happens if you try to then publish the DE translation draft before the EN draft? I can imagine at least 3 variants:
1. We just publish the translatable fields. This would be the default behavior, but it's really problematic for paragraphs as you would then basically just drop translations you might have created for new paragraphs.
2. We disallow that with a validation constraint
3. We publish it including untranslatable fields. Don't quite see how that would work as it basically goes completely against the current behavior.

Maybe a combination, core would continue to do 1, but in paragraphs, we add our own validation that prevents publishing a DE draft if it is based on the EN draft with a different structure.

Remaining tasks

User interface changes

API changes

Data model changes

Issue fork drupal-3007233

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

Berdir created an issue. See original summary.

james.williams’s picture

Issue summary: View changes

The scenario you've outlined is a really helpful starting point for this discussion. I've updated the issue summary to explicitly state that the text field is translatable, as I think that was your intention? Forgive me if I'm wrong - please update it again to clarify if so!

It might also be worth adding an 'opposite' scenario though, for content like asymmetric translations, to help guide the discussion too though. If you agree, let's add this to the IS too:

Content Type 'Press release' has an untranslatable logo image field and a translatable body text field. The editors' intention is that translations of press releases are to connect 'equivalent' press releases, but realistically, their entire content may be totally different between translations for different markets. So in this scenario, creating a translation starts from the source translation's values as merely a more useful starting point than a completely empty set of fields, but is fully expected to diverge once translated. So in this scenario, it's more important to keep any existing translated values in the translations, than to use any more recent values from new drafts of the source language.

I hope this demonstrates that there are probably valid use cases for all 3 of the variants you outline. Each of these two scenarios on their own would probably make us lean to a different solution, so can we keep them both in mind? Although I'm quite open to being told that I've missed the point! :-D (I do hope we all are though, as it's too easy to misunderstand each other or not explain ourselves clearly on these kinds of issues!)

Could we work towards making the solution configurable, so different sites / bundles could be set to use a different solution variant? I realise that's possibly quite a bit of work, but we could at least start with definitely having one option working (and clearly documented), then building each other option in turn over time.

I do agree that option 1, even though it's problematic for paragraphs, would be the best option to start with. Work could progress quicker in the contrib space to produce workarounds for it whilst option 3 is worked on for core? I think that's the combination you've suggested at the end of the IS.

Here's a pragmatic thought for the meantime though: Back in D7 + entity_translation, there was the concept of flagging translations as outdated, which might be useful for the outlined scenario. If the untranslatable field was updated in the EN draft, and therefore copied out to the DE translation, that DE translation could be flagged/marked/notified as needing an update. I even wonder if that itself could be made configurable; in the sense that it only matters when there is this 'dependency' between fields, e.g. when the text field describes the image field. Maybe that's going too far, so I'll come back to the original point: if there was a clear way of flagging translations as outdated, then there would be a clearer process for manual resolution where a coded resolution is impossible, impractical, or just not available yet.
Do we have this sort of concept in D8 anywhere?

berdir’s picture

I'm struggling to understand what you mean exactly.

Asymmetric paragraphs translations don't have this problem so that's completely different, that's just an translatable field like any other that has different values in each translation.

The structure can not diverge with symmetric paragraph translation, paragraphs enforces that. It only does so temporarily as drafts are created in different languages but then they are merged together again and combined.

The result in the end is going to be the same, the question is just when the new fields are available to be filled out in the translation. Right now, you need to publish your original language to start translating new paragraphs. This issue is about allowing to prepare drafts in multiple languages and then publishing them at the same time.

james.williams’s picture

the question is just when the new fields are available to be filled out in the translation.

Ah OK, yes, I recognise that now, sorry!

StillI I hope that the similar-but-different scenario I provided helps provoke/guide the discussion/solution some more. Even if the same solution proves to be appropriate for both scenarios :-)

sam152’s picture

I've noticed this when diagnosing latest vs latest translation affected revisions in the context of displaying the current state of a translation. I wonder if we could start by implementing this and leaning on the test coverage to show us what scenarios break and why this might be desirable or undesirable.

johnchque’s picture

Status: Active » Needs review
StatusFileSize
new1.01 KB

Trying this out, @Berdir suggested me to follow this approach which certainly works as far as I've seen.

There is one problem though, didn't have time to debug it all but I saw a strange behavior.

We have a published EN node with a published DE node.
We create a draft for the EN, updating the untranslatable field.
We create a new draft for the DE translation.
When saving this DE, it keeps having the value of the untranslatable field from the published version.
However, if we update once again the DE draft, the untranslatable field is set correctly with the latest draft value.

I debugged a bit and I saw that when updating the DE published version for the first time, it does not go through Drupal\Core\Entity\ContentEntityStorageBase::createRevision(). After the first time, it works normally.

As stated, I didn't have time to debug but that's the behavior I get. Is that how it is supposed to be?

Adding patch, let's see how many tests it breaks.

Status: Needs review » Needs work

The last submitted patch, 6: draft_translations_based_on_draft-3007233-6.patch, failed testing. View results

yang_yi_cn’s picture

I have the same issue and I think the idea / direction is right. However, I think the patch in #6 doesn't work, because there are much more work needs to be done.

Let's say we have English as origin, and another language (French).

When you create translation revision, field values need to be load from latest draft revision (English) and/or default published revision (English), and/or latest draft revision (French) and/or default published revision (French), and somehow merge them. Directly inherit for one revision is not enough.

Existing core logic was to always use the default / published revision which is not really what's wanted when you need to keep both EN/FR in draft and publish them at the same time.

I think the right logic should be:

Let's say there an EN and an FR translation already published.
We want to get to EN v2 and FR v2 both published.
We created EN v2 in draft.

When creating a new FR revision
- load latest revision (EN v2), which contains all latest English content, including translatable and untranslatable fields
- we should pre-fill the FR form/values with latest revision (EN v2), instead of default revision (which has EN and FR), because the English source is changed and old FR translations don't matter anymore.
-- we lost all French translation (of FR v1) in FR v2 and you have to translate everything again. However, I think it's the better way than the current core solution (which inherits the FR v1 translations)

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

sam152’s picture

Issue tags: +content moderation multilingual bug

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

kporras07’s picture

I'm uploading an updated version of the patch that updates both $entity and $new_revision.

kporras07’s picture

Sorry, error creating patch above. Updated.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

tate.walker’s picture

StatusFileSize
new22.66 KB

If you try to revert the latest version to an older draft it reverts to a different revision than what you selected.

revert error screenshot

I have a published version of the node that has multiple draft revisions after it. If I try to revert the current draft to an older draft the current revision reverts to the latest revision and not the selected revision.

tate.walker’s picture

I noticed that when I have a draft of a translation, editing it will display the published version of the body. With columns it displays my drafted changes but in the Body it only lets me edit what is live.

The drafted changes in the body are still saved on the draft page. They are just not visible when I click edit, it loads what is in the published Body.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

timovos’s picture

There is something going wrong when there are pending revisions in the original language and the page is translated (new translation is added for the node).

The \InvalidArgumentException("The entity object refers to a removed translation ({$this->activeLangcode}) and cannot be manipulated."); is triggered when $new_revision->setRevisionTranslationAffected(TRUE); is called.

It has something to do with $new_revision->removeTranslation($langcode); (the translation is directly removed or something).

I cannot lay my hands on this, but I will keep investigating.

Parashram made their first commit to this issue’s fork.

parashram’s picture

I have some findings:

  • Moderation state of default language change as per the latest state of node either by translated node or default node.
  • Revision content on default language node get updated when we update translated node. But, While applying patch #16, Revision content for default lang don't change.
  • New revision created for default node even though we update translated node

Moderation state of default language node should not change and new revision for default lang should not create on update translated node.

liquidcms’s picture

So happy to have stumbled upon this after the other dozen or so issues i have gone through related to moderation/translation/paragraphs (and some not even with paragraphs). Came to conclusion that many of our remaining issues could be solved if translation was based on the "correct" source revision.

NOTE: I think Berdir's title here is incorrect:

"latest draft of the source language, not the published version"

i dont think this is exactly correct. I think it should be the "latest revision" (not latest draft). Sadly Drupal has messed up terminology on the revisions page so hard to really keep these straight but i think "latest" revision is the top row of the table - which may be a draft or may be the current revision (i.e. published).

eager to see what this patch does :)

liquidcms’s picture

odd results but does somewhat help the issue.

parent node
- para top (with translatable multi text field)
-- para inside (with translatable multi text field)

before this patch, as OP states, if i have a published EN rev and on a draft i create new paragraphs; when translating, translation is based on published which doesn't have those paras and therefore i can not translate them (and there are no buttons to add extra)

after this patch:
- oddly it seems to wipe out (most) of the starting source field values, including the parent node title; yes, i am likely going to enter a translated title; by why remove this? it doesnt seem as though it should be part of this patch
- the draft EN paragraphs are available but most have had source text wiped (but not all). so what i end up with is the para form is there but empty.
- as my EN draft has 2 inside para, i can see both of those in my translation form (without patch i could only see the empty first para form). Now i get empty first inside para (same as without patch) but i do get the 2nd inside para form as well (not there without patch). And, the really odd part is that the EN source text is still there for the inside 2 paragraph.

So basically i think this works but all the 1st of each level translatable text fields (node, top para and inside para) have starting values blank. But 2nd (and suspect all additional) retain the source text as they should.

As these are multi fields, how this appears is:
source:
top para
- text 1
- text 2
- text 3

translation:
top para:
- single empty text field with button to add more

but this isnt consistent for the top para. I added a 2nd top to EN draft and although translation now indicates there are 2 of them; the 2nd is not available (and no button to add it)

the above testing is on a more or less vanilla D9.3.16 site with 2nd latest rev of paragraphs and err. The only relevant patch i have is this one #3150084: Non-translatable fields can only be changed when updating the current revision. which i dont think should impact any of this.

Summary: this patch does some good things but not everywhere. It feels like moderation/translation (and paragraphs) still a long ways to go before a stable D8 release (although oddly, we are already on D10)

liquidcms’s picture

Title: Draft translations should be based on the latest draft of the source language, not the published version » Draft translations should be based on the latest revision of the source language, not the published version
Priority: Normal » Major
liquidcms’s picture

Reading through the comments here a bit closer. I think #8 is mostly along the right track.. but not quite.

I think this patch may be helping with the displaying of correct information - EN draft adds new untranslatable term value, hidden on FR edit form but new FR draft only shows live terms. But, not sure it is fixing loading the correct content. This is mostly evident with Berdir's original issue for paragraphs (and i suspect would be the same for an image field with translatable ALT field) - when EN draft adds new paragraph/image; the FR edit form does not show the new entities (and no UI to add them), and therefore no way to translate the translatable parts.

From #8 it is suggested:

When creating a new FR revision
- load latest revision (EN v2), which contains all latest English content, including translatable and untranslatable fields
- we should pre-fill the FR form/values with latest revision (EN v2), instead of default revision (which has EN and FR), because the English source is changed and old FR translations don't matter anymore.

I think this is a dangerous assumption. The EN revision might need significant changes whereas the FR may need only minor changes. So why would we remove all the existing FR content?

I think the main/only problem to deal with is to ensure the entities added in the EN revision get added to the FR draft when trying to edit them. And these, as they are new, should be pre-filled with the EN content (for those new entities ONLY).

This makes it possible to edit the pre-existing FR as it was but also provides opportunity to add translations for the new entities. I suppose deleting attached entities would need to be symmetrical as well (probably already is??).

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

joseph.olstad’s picture

Would be nice to provide additional core support for multilingual workflows with that said, I am the maintainer of two projects for simultaneous workflow solutions. The first one I mention below now has nearly 4000 installs.

Solution 1)

Do publishing with moderated_content_bulk_publish version ^2.0.19 (do not use 3.x for multilingual). Works with Drupal 8, 9, 10, and this originated from a Drupal 7 solution that exists based on vbo.

https://www.drupal.org/project/moderated_content_bulk_publish

With this module if you're using the Editorial workflow similar to what is provided with Drupal core, you can easily publish both english and french drafts or pending drafts.

solution 1 publishes the latest pending draft or the draft or archived revision and makes it published.

so make a pending draft in english and french , use the bulk publishing from admin/content and both pending revisions will get published.

Enable the prompt configuration if you want to be prompted with a summary prior to bulk publishing/ bulk unpublishing or bulk archiving

I should probably consider adding to this module a bit of custom module code I use to dress up the admin/content view so that it's easier to distinguish draft/pending-draft and archived content.

see screenshot:
custom improvements to the admin/content view

Screenshot 2: bulk publish screenshot prompting (optional prompt see configuration in module)
screenshot of bulk publishing

This module has nearly 4000 installs, I originally developed it with PCOs assistance and have curated it since 2019, version 2.0.19 is very good, 3.0.x is not for multilingual workflows so stick to 2.0.x.

Solution 2)

Caveat, paragraphs not yet fully supported. Works with Drupal 7, 8, 9, 10.

Install and configure the entity_translation_unified_form module, both english and french can be edited side by side. Content can be published, drafted, pending drafted, archived for both English and French simultaneously this way.

See screenshot.

example of etuf in action

liquidcms’s picture

Thanks for these @joseph.olstad.

I don't think solution 1 is related to this as it is related to publishing the drafts. The issue here is that the translation is based on the wrong version. It is based off the latest live release rather than the latest draft release. So the translated draft will appear wrong (for the case when adding referenced entities to the EN draft) when reviewing the draft - this is before publishing.

Will check out solution 2 as possibly this has taken this core bug into account.

joseph.olstad’s picture

Possibly can help also, we've also been using access_unpublished with content moderation and multiple languages which in our case requires this core patch to work correctly and it seems to be good for three years now:

#2951294-39: Sort out and fix language fallback inconsistencies

timovos’s picture

Small addition to the patch #16.

Saving a draft revision caused an error (The entity object refers to a removed translation (...) and cannot be manipulated.).

Update 2022-12-06: Sadly, the client reported issues with this patch.

liquidcms’s picture

@joesph_olstad, yes, the option 2 from #29 (i.e. using entity_translation_unified_form, i.e. the side by side editor). Does seem to improve this situation in that it uses the latest revision for the translation; but doesn't help the situation when using entities using a IEF widget (not really this issue though).

the patch mentioned in #31 is unrelated to this.

liquidcms’s picture

retested with D9.4.8; seems nothing has changed to improve this issue but perhaps not a core issue beyond the bug that this patch does address. I was wrong in thinking that media entities (core) supported IEF and therefore would not work due to this issue. But core only supports standard entityref autocomplete for these; so this issue does not apply.

For paragraphs or anything using IEF; this does not yet provide a solution due to the basic issue that creating a translation does not have new entities that were created in original source language (and no way to add them). So no UI to translate newly added entities. But this is not a core issue as core doesn't support IEF (that's likely an issue in itself).

and... found it. I guess just needed to look harder. This patch combined with the one here: #3004099: Allow to translate paragraphs from pending revisions seems to work (basic initial testing so far with vanilla D9.4.8 site).

liquidcms’s picture

Combining this patch (#32) with the one i mentioned above (#3004009: commerce_price_updater 8.x-1.05) seemed like a solution to moderation + translation + paragraphs; but with more testing this patch does not work quite correctly (unrelated to paragraphs).

Test cases start from having a published en and fr revision.

Issue: 2nd EN draft causes 2nd FR draft to lose 1st FR edits
- en draft 1
- en draft 2 (but i think irrelevant)
- fr draft 1
- en draft 3
- when going to create fr draft 2, the translatable fields (only ones shown) have now reverted to the fr "current version" (i.e. the live version) as opposed to using the fr draft 1 values.

Oddly enough, without the core patch; this works as expected. But without patch in #32, adding a new paragraph to the en draft and it does not show up in the fr edit form (and therefore no way to translate it).

timovos’s picture

Patches #16 and #32 are causing issues with creating a translation based on original language and the content is not copied from the original language to the new translation.

liquidcms’s picture

Seems to be little movement on this issue; despite its importance.

Some progress on my end. Before Xmas i had come up with a new version of this patch as well as a new version of the Paragraphs patch; which seemed to work well. Due to holidays and other commitments, our QA team has only recently gotten around to testing this and although they think the forward path (create draft, translate, publish, new draft, new translations, publish, etc) now works well, they noticed that reverting to old revisions is broken. I have tweaked my patch a little to possibly fix this and they will do further testing this week. If it goes well, i'll post the patches.

Yesterday, someone on Drupal's #multilingual slack channel suggested they have a working solution for translation/moderation/paragraphs but using Workbench Moderation. I did a quick test, and sure enough, this does work with WBM. :) The issue is, that module supposedly has been migrated into core as Content Moderation - but apparently has gotten broken at some point along the way.

I posted this: #3341691: Life expectancy of this module?

amaria’s picture

@liquidcms, any luck with your patches? I'd like to try them as I'm having similar issues with content moderation + multilingual + paragraphs (or ERR) + IEF.

  • Create and publish EN and SP version of content that has a Paragraph field using IEF widget, but don't populate the Paragraph field
  • Create a draft of EN version and enter content for the Paragraph
  • As, expected, the published EN and SP version does not show the Paragraph, and the Latest revision of the source (EN) translation shows the Paragraph
  • Edit the SP version and woops, the Paragraph does not show up and there's no way to add it.
  • Publish the EN version. Now you can edit the Paragraph in the SP version

This gets worse when using an ERR field that is not a Paragraph. In this case, the ERR field does not show up in the SP translation even when the Latest revision is published. Of course, this is a separate issue.

liquidcms’s picture

I have an ugly patch to core which is targeting the same method the patches here are attempting to fix: the createRevision method of cores ContentEntityStorageBase class. As well as a modified version of this patch #3004099: Allow to translate paragraphs from pending revisions

We pushed it live just last week; but as always.. some new test case discovered which fails.

After months of trying to come up with a solution (without really understanding Drupal's moderation system's inner workings), I may give Moderation Workbench a go (the D7 version of Content Moderation); which, at first glance, does seem to work.

kapil.ropalekar’s picture

Hi @liquidcms, any luck with your patches to core along with the Content moderation module ?
Facing the same issue and scenario mentioned by you.

Also tried the patched provided in on #32 and #16 but they are not working. Also this this link : https://www.drupal.org/project/paragraphs/issues/3004099 but no luck.

When node for both de and fr languages for eg are in published state where de is default language, and then de is set to draft with a newly added paragraph it does not appear for translation in the fr version.

fr version of node still points to the published version and no revision for this is created.

Tried forcefully adding a revision for the same via hook_update but while changing the content moderation state from published to draft the site crashes with Deadlock condition.

liquidcms’s picture

We are on my RC6 of piecing something together for this. We have had 2 earlier versions that our editorial team has tried but eventually came back with a new test case which failed. The new version has only been live for a couple days but each release has more test cases it has gone through so hopefully this is the last one.. as this really is a nightmare.

I suspect the bottom line is that the architecture of paragraphs simply does not support this as it is now.

I'll post the 2 patches (core/paragraphs) we are currently using and perhaps you can try them out to see if they work for you. They are not language agnostic at the moment so you may need to modify for your specific case. I should redo to use "default language" where appropriate instead of hard coding in the language we use.

There are still some "editorial caveats" required for this which our editorial team has suggested are fine - and that i will eventually add some validators to ensure are forced (we use EN/FR):
- if a new EN draft is created which adds/removes paragraphs, and a FR draft is also created, the EN must be published first.
- when, in situation described, the EN is published, the FR (previous live version) will appear incorrect - in this case i would publish both at the same time.

There is also the possibly obvious trait of paragraphs that needs to be kept in mind: the translation needs its source (this is likely the primary failing with paragraphs that makes this such a mess). So if you remove the source you can't expect the translation to maintain its translated paragraph. In other words paragraphs between languages need to line up. For our application that is always the case; so not an issue.

shrikant.dhotre’s picture

Hi,
I am facing the same problem, for paragraph translation in content moderation, using drupal 9.5.7
Translation of paragraph content is not rendering latest change done in default language. I need to re-publish the translated content then its rendering properly.

joseph.olstad’s picture

@liquidcms, are you by chance using the "conflict" module? There's a critical bug in the "conflict" module #3333138: Original language entity content got overwritten when updating translated entity for multilingual site I suggest uninstalling the "conflict" module or patching it. Not sure if this is related but it very well might be.

liquidcms’s picture

@joeseph - never heard of it. But as documented in a few places now; my issue, and others', stem from core issues with how core handles moderation and translation and then complicated with paragraphs. Would be nice if this was all just due to some rogue module messing things up. Sadly not.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

no sssweat’s picture

Issue tags: -
StatusFileSize
new1.56 KB

Re-rolled the rc1 patch so it's compatible with 9.5.11

aaron.ferris’s picture

First off, thanks for this patch/patches. Just wanted to give a heads up to anyone else who may come across similar, I was noticing that using this patch with a couple of content types on a client site that it would block translations from being edited. For some reason, the 'changed' and 'created' fields were not translatable on this particular content type, and thus new translations would receive these values from the parent = form submissions being blocked on edit (Outdated form, without digging into it id assume the constraint checks timestamps to see if something is more recent).

Removing the patch and the issue goes away, setting these fields to be translatable (with the patch) and the issue is resolved.

lpeabody’s picture

@aaron.ferris yes if you have content_translation enabled and you mark the changed field as untranslatable on content entities then you can run into the scenario where it becomes impossible to ever edit the entity again without repairing the database. I opened this related issue a while back https://www.drupal.org/project/drupal/issues/3170926. It's a sticky problem but basically with how things are currently implemented in core, I think it should be at least posting warnings somewhere that changed should never, ever be flagged as untranslatable because at some point you will become unable to edit your content (obviously a massive issue for a CMS) due to EntityChangedConstraint.

aaron.ferris’s picture

Yes indeed, thanks for linking that issue @lpeabody.

joaopauloscho’s picture

The conjunction of the patches #16 with https://www.drupal.org/project/paragraphs/issues/3004099#comment-14276955 worked for paragraphs.

elendev’s picture

I tried the patch #16 and the patch #32, with Drupal 11.2.4.
Unfortunately, while creating the translation based on the latest revision, we loose the translation metadatas in the process.
The initial code:

  $new_revision = clone $entity;

The patch #16:

    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
    $langcode = $entity->language()->getId();
    $latest_entity_revision_id = $storage->getLatestRevisionId($entity->id());
    $entity = $storage->loadRevision($latest_entity_revision_id);

    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $new_revision = $entity->hasTranslation($langcode) ?
          $entity->getTranslation($langcode) : $entity->addTranslation($langcode);

It generate an error while trying to add by hand a translation:

The website encountered an unexpected error. Try again later.

Error: Call to a member function getName() on null in Drupal\content_translation\ContentTranslationHandler->entityFormAlter() (line 317 of core/modules/content_translation/src/ContentTranslationHandler.php).
Drupal\node\NodeTranslationHandler->entityFormAlter() (Line: 366)
Drupal\content_translation\Hook\ContentTranslationHooks->formAlter() (Line: 474)
Drupal\Core\Extension\ModuleHandler->alter() (Line: 838)
Drupal\Core\Form\FormBuilder->prepareForm() (Line: 249)
Drupal\autosave_form\Form\AutosaveFormBuilder->prepareForm() (Line: 280)
Drupal\Core\Form\FormBuilder->buildForm() (Line: 97)
Drupal\autosave_form\Form\AutosaveFormBuilder->buildForm() (Line: 48)
Drupal\Core\Entity\EntityFormBuilder->getForm() (Line: 414)
Drupal\content_translation\Controller\ContentTranslationController->add()
call_user_func_array() (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext():121}() (Line: 627)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::onController():96}() (Line: 183)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 54)
Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle() (Line: 53)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 30)
Drupal\sq_rest\DynamicMaxAgeMiddleware->handle() (Line: 53)
Asm89\Stack\Cors->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 39)
Drupal\prometheusio_exporter_database\StackMiddleware\DatabaseLogging->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 53)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 715)
Drupal\Core\DrupalKernel->handle() (Line: 19)
elendev’s picture

To fix the issue of #51, I adapted the patch #32 and passed the metadata to the revisionned entity.

tibur’s picture

Hi @elendev,

We’re experiencing the same situation described here: https://www.drupal.org/project/tmgmt/issues/3403755, and I’m following your comment #4.

After applying patch #52, we’re unfortunately getting the following error:

Error: Call to undefined method Drupal\content_moderation\Entity\ContentModerationState::getChangedTime() 
in Drupal\content_translation\ContentTranslationMetadataWrapper->getChangedTime() 
(line 124 of core/modules/content_translation/src/ContentTranslationMetadataWrapper.php).

Your code calls the following method:

public function getChangedTime() {
return $this->translation->hasField('content_translation_changed')
? $this->translation->get('content_translation_changed')->value
: $this->translation->getChangedTime();
}

And in our case, however, $this->translation is an instance of
Drupal\content_moderation\Entity\ContentModerationState that doesn't have the getChangedTime() method.

tibur’s picture

StatusFileSize
new3.89 KB

I’ve created an alternative patch based on #52 that adds an additional check to ensure the entity is an instance of ContentTranslationHandlerInterface.
This allows verifying that the entity actually supports the extra metadata fields used to store translation state information.

This check prevents calling getChangedTime() on entities that don’t implement this interface — such as ContentModerationState — which avoids the fatal error mentioned above.

mayurgajar’s picture

Assigned: Unassigned » mayurgajar

mayurgajar’s picture

Assigned: mayurgajar » Unassigned
elendev’s picture

Hi @tibur88,

In your patch, the condition:

    if ($entity instanceof ContentTranslationHandlerInterface) {
      $new_revision_metadata = $contentTranslationManager->getTranslationMetadata($new_revision);

      $new_revision_metadata
        ->setChangedTime($metadata->getChangedTime())
        ->setCreatedTime($metadata->getCreatedTime())
        ->setOutdated($metadata->isOutdated())
        ->setPublished($metadata->isPublished())
        ->setSource($metadata->getSource())
      ;
    }

Will always be false, since the `$entity` is not an instance of `ContentTranslationHandlerInterface` (the entity is not of the type of the translation handler since those are two different classes).
I think the more appropriate test would be to check if the `translate` handle exist for the given entity (or maybe if `$entity` implement the expected `TranslationInterface`).
The patch #54 does break on my side the ability to add a new translation.

tibur’s picture

Hi @elendev,

Thank you for your helpful feedback.

I made a change following your advice and checked via the isSupported() method of the content_translation.manager service whether the entity supports translations.

I hope I understood your advice correctly :)

I also noticed that when creating a new translation from a node in draft, the values of some fields, including the title, were lost.

I should have covered both issues with this patch.

elendev’s picture

Hi @tibur88,

It's perfect, I encountered the same issue: since the fields were lost, I had issues creating a new translation.
I was working on exactly the same corrections before the holidays, I'll test your patch and see if I encounter any other issues.

Thanks!

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.