Problem/Motivation

There are so many issues for these bugs already, and I'm not sure where to post this but I just want to have a starting code (it is not complete yet, just a suggetions) and discussion somewhere, so I've created this "main/meta (?) issue".
From the "real meta issue", here are the blocker issues of multilingual workflow:
#2669732: Buttons to remove and add paragraphs do not appear when changing the language of the host entity
#2692067: Trouble translating nested paragraphs
#2597201: Translation source language is not set
#2658698: Unable to use paragraphs after default language change
#2591171: Add test coverage for entities with unspecified language
#2705045: Make stale language source on language source work

Yesterday I've spent the whole day trying to figure out what/where exactly is the problem (didn't realised the time was passing so fast while debugging). I've already started with the TDD approach and uploaded the test in #2658698: Unable to use paragraphs after default language change and since the other "specific" situations/separate issues have more or less the same problem, I didn't continue to write tests and just tried to find a solution.

I and a colleague had a long discussion, tried so many things and we thought we were near the solution, but there was always some detail that is not so clear and hard to explain (tried to write a sensible comment/explanation three times yesterday, and then I was too tired and just left...).

So now I just write here a solution I think it might cover most of the problems, but first some remarks:

  • Probably most of the issue's reporter had used the paragraphs_demo module, in there we have noticed that (in admin/config/regional/content-language) every paragraph types "default language" have been set to Site's default language (whatever) and only the "Text" paragraph type has been set to English. We thought that if we set the default language to use for all the paragraph types and the content types (which have paragraph field) to Interface text language selected for page, could "help" for part of the problem (even though we are not sure what does this mean exactly, but seems closer to what we want/expect (?))
  • Combined with the configuration described at the previous point, we need a method that checks the original node langcode (cases for create, edit and translate):
    • node create: set whatever selected language as the source node langcode (e.g. if the node langcode is different than the site langcode, it should not interpret this as a translation, which it currently does)
    • node edit: somehow check if the editing node form is the original node,
      • if yes then show every buttons (no matter if the node/site langcodes are different), AND if the user changes the original node langcode, then change it also for every paragraph items*,
      • otherwise hide the remove/add more buttons.
    • node translate: simply check that it's not the original node, so hide all remove/add more buttons

*About the edit phase, correct me if I'm wrong, I'm telling this because, as far as I saw, the remove buttons are displayed/hidden "separately" because for each paragraph items when it has been added it takes the current site langcode and then this is compared with the node langcode, which then appears (with a strange/unusual langcode changing workflow) like for some paragraph items are in translation and for other are on the original node (while all of them are on the original one).

Finally, at the moment my colleague is trying something else. I think that this should be a close fix for most of these bugs, but I'm not sure so feel free to disprove my suggestion and start a discussion! ;)

Sorry for the long and probably confusing summary, but I'm thinking about these bugs since long time and couldn't wait any longer to fix it!

Proposed resolution

Remaining tasks

- after discussions/decisions, write a better summary

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#60 multilingual_workflow-2698239-60.patch29.21 KBjohnchque
#60 multilingual_workflow-2698239-60-test_only.patch23.26 KBjohnchque
#60 interdiff-2698239-56-60.txt1.62 KBjohnchque
#56 paragraphs_2698239_multi_56.patch29.22 KBmiro_dietiker
#56 paragraphs_2698239_multi_56.interdiff.txt1.29 KBmiro_dietiker
#49 multilingual_workflow-2698239-49.patch28.89 KBtduong
#49 multilingual_workflow-2698239-49-test_only.patch23.13 KBtduong
#49 interdiff-2698239-41-49.txt25.28 KBtduong
#41 multilingual_workflow-2698239-41.patch29.5 KBtduong
#41 multilingual_workflow-2698239-41-test_only.patch23.83 KBtduong
#41 interdiff-2698239-37-41.txt4.07 KBtduong
#37 multilingual_workflow-2698239-37.patch28.55 KBtduong
#37 interdiff-2698239-27-37.txt549 bytestduong
#27 multilingual_workflow-2698239-27.patch28.55 KBtduong
#27 multilingual_workflow-2698239-27-test_only.patch22.88 KBtduong
#22 interdiff-2698239-18-22.txt12.3 KBjohnchque
#22 multilingual_workflow-2698239-22-test-only.patch17.93 KBjohnchque
#22 multilingual_workflow-2698239-22.patch23.53 KBjohnchque
#18 multilingual_workflow-2698239-18.patch24.49 KBtduong
#18 multilingual_workflow-2698239-18-test_only.patch18.81 KBtduong
#18 interdiff-2698239-11-18.txt16.2 KBtduong
#11 multilingual_workflow-2698239-11.patch20.82 KBtduong
#11 multilingual_workflow-2698239-11-test_only.patch15.14 KBtduong
#11 interdiff-2698239-6-11.txt17.07 KBtduong
#6 multilingual_workflow-2698239-6.patch16.86 KBtduong
#6 multilingual_workflow-2698239-6-test_only.patch12 KBtduong
#5 multilingual_workflow-2698239-5.patch4.78 KBjohnchque
paragraphs_multilingual_workflow.patch1.67 KBtduong
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tduong created an issue. See original summary.

tduong’s picture

Issue summary: View changes
tduong’s picture

Issue summary: View changes
tduong’s picture

Issue summary: View changes
johnchque’s picture

After hours of debugging and testing we finally create a patch that has a fix for this bugs, we are still writing test coverage though.

tduong’s picture

Extended the testParagraphsTranslation() for:

  • (Case 0): Check the paragraphs buttons in TRANSLATION after changing the NODE language:
    1. default site langcode in en
    2. original node langcode in EN,
    3. translated in FR,
    4. changed node langcode to DE;

Added multilingual test coverage for:

  • Case 1: Check the paragraphs buttons after changing the NODE language (original node langcode in DE, default site langcode in en)
  • Case 2: Check the paragraphs buttons after changing the NODE language (original node langcode in EN, default site langcode in en)
  • Case 3: Check the paragraphs buttons after changing the SITE language (original node langcode in en, default site langcode in DE)

+ small refactor on the previous patch.

The last submitted patch, 6: multilingual_workflow-2698239-6-test_only.patch, failed testing.

The last submitted patch, 6: multilingual_workflow-2698239-6-test_only.patch, failed testing.

The last submitted patch, 6: multilingual_workflow-2698239-6-test_only.patch, failed testing.

miro_dietiker’s picture

Status: Needs review » Needs work
  1. +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
    @@ -36,6 +36,13 @@ use Symfony\Component\Validator\ConstraintViolationInterface;
    +   * Indicates whether the current form state is in translation.
    

    form state => widget instance

  2. +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
    @@ -1097,4 +1111,24 @@ class InlineParagraphsWidget extends WidgetBase {
    +      // If it is being rebuilt we are not translating.
    +      if ($form_state->isRebuilding()) {
    

    This is not true.

    A Rebuild can easily be triggered in the translate form. There was a better code for the second case! (needs test coverage) The fact that it's rebuilding is less important than the language values that change.

  3. +++ b/src/Tests/ParagraphsTranslationTest.php
    @@ -149,6 +157,228 @@ class ParagraphsTranslationTest extends WebTestBase {
    +   * Tests the paragraphs buttons presence in multilingual workflow.
    

    We need to have a feasible summary for such complex cases. List the sub cases we test, such as changing the source language.

  4. +++ b/src/Tests/ParagraphsTranslationTest.php
    @@ -149,6 +157,228 @@ class ParagraphsTranslationTest extends WebTestBase {
    +    // Check that the texts and the paragraphs buttons are shown when editing.
    +    $this->assertText('Title in german');
    

    Also check the language value, of node and paragraphs! I think we should build an AssertMultilingualParagraph($entity, $delta)

  5. +++ b/src/Tests/ParagraphsTranslationTest.php
    @@ -149,6 +157,228 @@ class ParagraphsTranslationTest extends WebTestBase {
    +    $this->assertFieldByName('field_paragraphs_demo_0_remove');
    +    $this->assertFieldByName('field_paragraphs_demo_1_remove');
    +    $this->assertFieldByName('field_paragraphs_demo_text_add_more');
    

    We should have an assertParagraphsButtins() that checks all.

tduong’s picture

As suggested above:

  1. done
  2. no test coverage for rebuild yet, since we have changed the approach (after another debug session with miro_dietiker and Berdir, dropped the isRebuilding() check)
  3. done
  4. done
  5. done, but somehow sometimes it does the loop correctly, but my last checks (on my local machine) do not assert for each buttons. I left the debug statement there to see what happens in testbot

The last submitted patch, 11: multilingual_workflow-2698239-11-test_only.patch, failed testing.

The last submitted patch, 11: multilingual_workflow-2698239-11-test_only.patch, failed testing.

The last submitted patch, 11: multilingual_workflow-2698239-11-test_only.patch, failed testing.

miro_dietiker’s picture

Status: Needs review » Needs work

2. the rebuild problem is a real problem. we need separate test coverage for it and make sure that we don't fall into that trap with future improvements / iterations of the code.

  1. +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
    @@ -36,6 +37,13 @@ use Symfony\Component\Validator\ConstraintViolationInterface;
    +  private $isTranslating = FALSE;
    
    @@ -207,17 +216,22 @@ class InlineParagraphsWidget extends WidgetBase {
    +      $this->initIsTranslating($form_state, $host);
    

    This should only be determined once. It is now stored on the widget but determined per formElement again.

  2. +++ b/src/Tests/ParagraphsTranslationTest.php
    @@ -149,6 +162,308 @@ class ParagraphsTranslationTest extends WebTestBase {
    +    $buttons = [
    +      'field_paragraphs_demo_0_remove',
    +      'field_paragraphs_demo_text_add_more',
    +    ];
    +    $this->assertParagraphsButtons($buttons);
    

    Drop $buttons and just write $this->assertParagraphsButtons(2) whereas 2 is the expected count of paragraphs.

miro_dietiker’s picture

+++ b/src/Tests/ParagraphsTranslationTest.php
@@ -149,6 +162,308 @@ class ParagraphsTranslationTest extends WebTestBase {
+      $this->assertEqual($node_langcode, $item->language()->getId());

Please add an assert message.

Also we should do an extra test for nested paragraphs!

miro_dietiker’s picture

FOLLOWUP: Also from issues we learned that previous situation is inconsistent, so after fixing this bug, we should offer an update function that fixes all paragraph source / default languages.

FOLLOWUP: The Drupal Core isDefaultFormLangcode() returns wrong data during a rebuild while changing the source language and needs fixing.

tduong’s picture

Rerolled.

  1. Rebuild problem: I've added the multi value text field to the Paragraphed article content type, checked for Add another item button for every test cases, but used this "refresh helper" only in the translation test. Not sure if it's fine or we should drop this button existence assertion in the multilingual test (since the refresh thing is already triggered by adding the paragraph items, so this new field is not needed in the multilingual test cases).
  2. isTranslating initialisation: not sure where we should call this initIsTranslating(). Didn't investigated too much. Any suggestion ?
  3. assertParagraphsButtons(): I think it's more reliable if we check for the exact buttons we want to assert. I've changed how I add the new buttons to be checked and now it works fine. If you still think that it's not needed (because now we know that this fix works as expected and there is no need to check for the specific cases), then I'll change that!
  4. assertMultilingualParagraph() message: added.
  5. Nested paragraph test coverage: not done yet. As I hear from the ongoing discussion here in the office, there are some problem writing this test. I'll wait for good news about this and I'll add the test (or yongt9412).

The last submitted patch, 18: multilingual_workflow-2698239-18-test_only.patch, failed testing.

The last submitted patch, 18: multilingual_workflow-2698239-18-test_only.patch, failed testing.

The last submitted patch, 18: multilingual_workflow-2698239-18-test_only.patch, failed testing.

johnchque’s picture

Tried to simplify the tests a bit, also changed some names to make it more clear. We will have soon tests for nested paragraphs! :)
- Rebuild is being tested (Dont need to assert the button)
- initialization done just once
- I agree with the AssertParagraphsButton, looks good

Status: Needs review » Needs work

The last submitted patch, 22: multilingual_workflow-2698239-22-test-only.patch, failed testing.

The last submitted patch, 22: multilingual_workflow-2698239-22-test-only.patch, failed testing.

The last submitted patch, 22: multilingual_workflow-2698239-22-test-only.patch, failed testing.

miro_dietiker’s picture

Rebuild: You must trigger a rebuild on the translate tab in the test. How do you think is this case covered now? You only have rebuilds triggered in the non-translate-tab (non-translating) case.

initIsTranslating: could be called like it is currently, with an early exit if called multiple times.

assertParagraphsButtons: no more that much code duplication and can be kept that way. My proposal was always to make a loop over the count argument and sure explicitly check for the specific button strings inside resulting in

function assertParagraphsButtonsHelper($count) {
  for($i=0; $i<$count; $i++) {
    $buttons[] = 'field_paragraphs_demo_' . $i . '_remove';
  }
  $buttons[] = 'field_paragraphs_demo_text_image_add_more';

Hope we can have nesting proof to work soon. :-)

tduong’s picture

Changes are way bigger than the patch, thus no interdiff...

  • Rebuild: as discussed, after that we've noticed that the multi value text field (separate form the paragraphs) is not rebuilding the whole form (updating also paragraphs) as we expected, so now we have decided to use the Images paragraph types. Even with this change, the rebuild thing is no properly working... I've left the check after the "upload images rebuild" anyway and see if it's different for testbot...
  • initIsTranslating: done
  • assertParagraphsButtons: done
  1. I've moved our paragraphs buttons multilingual in translation test to a new test method with:
    • Case 1: original node langcode in EN, translate in FR, change to DE
    • Case 2: original node langcode in DE, change site langcode to DE, change node langcode to EN
  2. added expected langcode as parameter of assertParagraphsLangcode

Reviewed this test too many times. Need some couple of eyes more to check if everything makes sense and also if the comments are consistent and sensible...

About the paragraph items langcode check in translation that we have discussed (it was supposed to be just a temporary additional check), it went to "Fatal error: Allowed memory size of 536878912 bytes exhausted (tried to allocate 42847834 bytes)", so I've just drop it, but if you want to work with it, here is the code:

  protected function assertParagraphsLangcodes($node_id, $source_lang = 'en', $trans_lang = NULL) {
    // Update the outdated node and check all the paragraph items langcodes.
    \Drupal::entityTypeManager()->getStorage('node')->resetCache([$node_id]);
    /** @var \Drupal\node\NodeInterface $node */
    $node = Node::load($node_id);
    $node_langcode = $node->langcode->value;
    $this->assertEqual($source_lang, $node_langcode, 'Host lang');

    foreach ($node->field_paragraphs_demo->referencedEntities() as $paragraph) {
      $paragraph_langcode = $paragraph->language()->getId();
      $message = new FormattableMarkup('Node langcode is "@node", paragraph item langcode is "@item".', ['@node' => $source_lang, '@item' => $paragraph_langcode]);
      $this->assertEqual($source_lang, $paragraph_langcode, $message);
    }

    if ($trans_lang) {
      $trans_node = $node->getTranslation($trans_lang);
      foreach ($trans_node->field_paragraphs_demo->referencedEntities() as $paragraph) {
        $item_trans = $paragraph->getTranslation($trans_lang);
        $paragraph_langcode = $item_trans->language()->getId();
        $message = new FormattableMarkup('Node langcode is "@node", paragraph item langcode is "@item".', ['@node' => $source_lang, '@item' => $paragraph_langcode]);
        $this->assertEqual($trans_node, $paragraph_langcode, $message);
      }

    }
  }

The last submitted patch, 27: multilingual_workflow-2698239-27-test_only.patch, failed testing.

The last submitted patch, 27: multilingual_workflow-2698239-27-test_only.patch, failed testing.

The last submitted patch, 27: multilingual_workflow-2698239-27-test_only.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 27: multilingual_workflow-2698239-27.patch, failed testing.

The last submitted patch, 27: multilingual_workflow-2698239-27.patch, failed testing.

The last submitted patch, 27: multilingual_workflow-2698239-27.patch, failed testing.

miro_dietiker’s picture

Oops
$this->assertEqual($trans_node, $paragraph_langcode, $message);
to
$this->assertEqual($trans_lang, $paragraph_langcode, $message);
Sometimes when string conversion and serialisation is triggered bad things happen.

tduong’s picture

The failing testParagraphsMultilingualWorkflow is related to #27-Rebuild. I wanted to ensure it does not work also for testbot and share it in d.o. So either we should just drop these checks right after the rebuild (since I've checked them anyway right after saving the changes made during the steps, knowing this would have failed) or we should think of something more reliable to have a proper rebuild form to check for the langcode changes after triggering the rebuild. Otherwise the fix works as expected

The failing testParagraphTranslationMultilingual is related to the assertion of some images (children paragraph items of a nested paragraph added from the translated node) that are supposed not to be shown in the original node, but because of the parent thing/ERR not committed/included to the patch yet, then it failed. Again just wanted to share this here, but I thing it will be a follow up or will be discussed later/somewhere else. So maybe we should remove the images checks since here we are just interested to the paragraphs buttons and the langcodes.

ahaha, really bad thing ;) didn't noticed that. I'll check it tomorrow, but for today, abort!

tduong’s picture

+++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -1097,4 +1113,26 @@ class InlineParagraphsWidget extends WidgetBase {
+  protected function initIsTranslating(FormStateInterface $form_state, Entity $host) {
+    if (isset($this->isTranslating)) {
+      return;
+    }

Oopss, maybe this should be if ($this->isTranslating != NULL) ...

tduong’s picture

Status: Needs review » Needs work

The last submitted patch, 37: multilingual_workflow-2698239-37.patch, failed testing.

The last submitted patch, 37: multilingual_workflow-2698239-37.patch, failed testing.

The last submitted patch, 37: multilingual_workflow-2698239-37.patch, failed testing.

The last submitted patch, 41: multilingual_workflow-2698239-41-test_only.patch, failed testing.

The last submitted patch, 41: multilingual_workflow-2698239-41-test_only.patch, failed testing.

The last submitted patch, 41: multilingual_workflow-2698239-41-test_only.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 41: multilingual_workflow-2698239-41.patch, failed testing.

The last submitted patch, 41: multilingual_workflow-2698239-41.patch, failed testing.

The last submitted patch, 41: multilingual_workflow-2698239-41.patch, failed testing.

tduong’s picture

Status: Needs work » Needs review

Ah, forgot to mention that while checking for the paragraphs langcode of the translated node, if you add a nested paragraph, the check does not detect and cannot check the langcode of the nested paragraph until you save the node. So if you run the test, from the assertParagraphLangcode you can see (e.g.) 2 checks of the paragraphs from the original node, but only 1 check of the paragraphs form the translated node. I guess the reason of this behaviour is that as long as you don't save the translation yet, the paragraph is still not translated, so getTranslation() cannot find the translation of that paragraph, or is there anything so special for nested paragraph (I mean the paragraph type itself, not its children) ?

Anyway, I thought that adding a new paragraph should trigger the rebuild form but saw that it actually does not update the form now. If you have changed the source langcode and then add a new paragraph, this does not change the langcode until you don't save the node. I think this worked previously (until #22) but don't know why it changes now.

BTW, now we have tests with nested paragraph (since #27), but we only check the nested langcode and not for its children langcode. Do we need to check for them too (here/now) ?

Set status to "Needs review" for feedback about the notes posted in this comment and in #35.

tduong’s picture

  • from :
    • failing testParagraphTranslationMultilingual: discussed with yongt9412 and agreed dropping the images check since it's not relevant for our issue.
    • failing testParagraphsMultilingualWorkflow: figured out it did not actually work previously as I thought/wrote above. When you change the original node langcode and then add a new paragraph, this rebuild the paragraphs form but node and paragraphs have still the previous langcode set. Only after saving the node everything is properly updated. Fixed these checks.
  • from :
    • new nested paragraph added is not detected thus no langcode check possible: saw that it doesn't work also for "Images", you need to save the node first to actually get the new paragraph entity to check for its langcode.
    • need to check for nested children paragraphs langcode?: if we want to check them as well, I guess it will be a follow up.

I've checked the code again, do some refactoring, fixed comment and other clean ups.

The last submitted patch, 49: multilingual_workflow-2698239-49-test_only.patch, failed testing.

The last submitted patch, 49: multilingual_workflow-2698239-49-test_only.patch, failed testing.

The last submitted patch, 49: multilingual_workflow-2698239-49-test_only.patch, failed testing.

boesbo’s picture

New Issue: Button "Add paragraph" removed if you create a translation node
https://www.drupal.org/node/2702947

miro_dietiker’s picture

Issue summary: View changes

Created the previously mentioned issue for the update that is needed
#2705045: Make stale language source on language source work

miro_dietiker’s picture

Status: Needs review » Needs work
+++ b/src/Tests/ParagraphsTranslationTest.php
@@ -151,4 +169,451 @@ class ParagraphsTranslationTest extends WebTestBase {
+  protected function assertParagraphsLangcode($node_id, $source_lang = 'en', $trans_lang = NULL) {
...
+    if ($node->hasTranslation($trans_lang)) {

Even if we would ask to assert for a specific translation language, no assert would fail if the translation is inexisting.

Please create the follow-ups already if needed, such as nested paragraphs checks.

miro_dietiker’s picture

Needed a reroll. Multiple conflicts.
Trying some blind assert for #55.

Status: Needs review » Needs work

The last submitted patch, 56: paragraphs_2698239_multi_56.patch, failed testing.

The last submitted patch, 56: paragraphs_2698239_multi_56.patch, failed testing.

The last submitted patch, 56: paragraphs_2698239_multi_56.patch, failed testing.

johnchque’s picture

The last submitted patch, 60: multilingual_workflow-2698239-60-test_only.patch, failed testing.

The last submitted patch, 60: multilingual_workflow-2698239-60-test_only.patch, failed testing.

The last submitted patch, 60: multilingual_workflow-2698239-60-test_only.patch, failed testing.

miro_dietiker’s picture

Status: Needs review » Fixed

Awwwesome! Committed this also.
Now back to checking all the postponed / related issues.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.