Problem/Motivation

CommentLazyBuilders always check the default entity language. Even when you view a comment translation you will get links to the default language instead of the translation you are viewing.

Steps to reproduce

  1. Install drupal using standard install profile
  2. Make your comment type translatable
  3. Create a comment and then translate it
  4. View the comment translation, e.g. visit /fr/comment/1
  5. Inspect the local tasks links, you will see that they point to the default language, like /comment/1/edit instead of the translation /fr/comment/1/edit

Proposed resolution

  • Make sure correct language version of the comment entity is loaded before links are rendered. At least Edit and Delete links should be directed to the displayed entity language.

Remaining tasks

  • Decide how to handle Reply, Approve and Translate.
  • Review and commit patch.

User interface changes

  • Comment entity links will direct to correct language version.

API changes

  • None.

Data model changes

  • None.

Release notes snippet

Issue fork drupal-3134223

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

matsbla created an issue. See original summary.

matsbla’s picture

StatusFileSize
new2.24 KB

Just missed one link.

matsbla’s picture

Status: Active » Needs review
andypost’s picture

Interesting catch, btw maybe language should be passed as argument?

matsbla’s picture

andypost’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Thanks, then let's keep it consistent!

NW for tests, probably node already have examples

matsbla’s picture

matsbla’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
matsbla’s picture

Status: Needs review » Needs work
matsbla’s picture

Status: Needs work » Needs review
jibran’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Bug Smash Initiative

Thanks, the patch looks good now.

andypost’s picture

+++ b/core/modules/comment/src/CommentLazyBuilders.php
@@ -144,6 +144,7 @@ public function renderLinks($comment_entity_id, $view_mode, $langcode, $is_in_pr
       $entity = $this->entityTypeManager->getStorage('comment')->load($comment_entity_id);
+      $entity = $entity->getTranslation($langcode);
       $commented_entity = $entity->getCommentedEntity();

when translation is missing (whatever reason) this code will throw exception now

larowlan’s picture

Status: Reviewed & tested by the community » Needs work

For #13 can we add a try/catch there to be safe?

We have unit-test coverage of that class - can we extend CommentLinkBuilderTest for these cases too?

jungle’s picture

Version: 8.9.x-dev » 9.1.x-dev
+++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
@@ -233,4 +233,64 @@ protected function doTestTranslationEdit() {
+      foreach ($links as $label => $expected_href) {
+        $this->assertSession()->elementExists('xpath', "//article[@id='comment-$comment_id']//a[text()='$label']");

One nitpick/micro-optimization:

To avoid calling $this->assert Session() multiple times in the loop. Every call returns a new instance.

   * @return \Drupal\Tests\WebAssert
   *   A new web-assert option for asserting the presence of elements with.
   */
  abstract public function assertSession($name = NULL);

Suggestion:

      $assert_session = $this->assertSession();
      foreach ($links as $label => $expected_href) {
        $assert_session->elementExists('xpath', "//article[@id='comment-$comment_id']//a[text()='$label']");

Changing the target version to 9.1.x.

deepak goyal’s picture

Assigned: Unassigned » deepak goyal
deepak goyal’s picture

StatusFileSize
new3.51 KB
new954 bytes

Hi @jungle
Made changes as you suggested please review.

deepak goyal’s picture

Assigned: deepak goyal » Unassigned
Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 17: 3134223-16.patch, failed testing. View results

matsbla’s picture

StatusFileSize
new5.24 KB

Added try / catch to check if translation exists.

Should that also be done in NodeViewBuilder?
https://git.drupalcode.org/project/drupal/-/blob/8.9.x/core/modules/node/src/NodeViewBuilder.php#L100

Also updated test.

matsbla’s picture

Status: Needs work » Needs review
pratik_kamble’s picture

Assigned: Unassigned » pratik_kamble
jungle’s picture

Thanks @matsbla for the new patch. Would be great to attach an interdiff when possible. See https://www.drupal.org/documentation/git/interdiff

matsbla’s picture

StatusFileSize
new1.85 KB
pratik_kamble’s picture

@matsbla, I have tested patch in the comment #20. Patch LGTM just one minor change.

+++ b/core/modules/comment/src/CommentLazyBuilders.php
@@ -137,6 +137,11 @@ public function renderLinks($comment_entity_id, $view_mode, $langcode, $is_in_pr
+      }

Please add the description in the catch block. Say "Invalid translation language ($langcode) specified." or similarly something more descriptive.

      catch (\InvalidArgumentException $exception) {
        // Invalid translation language ($langcode) specified.
      }
pratik_kamble’s picture

Assigned: pratik_kamble » Unassigned
Status: Needs review » Needs work
matsbla’s picture

StatusFileSize
new5.3 KB
new603 bytes

Thanks for feedback!

matsbla’s picture

Status: Needs work » Needs review
pratik_kamble’s picture

Assigned: Unassigned » pratik_kamble

Assigning for review.

pratik_kamble’s picture

Assigned: pratik_kamble » Unassigned
Status: Needs review » Reviewed & tested by the community

Tested patch in comment #27. Local task link for comments points to respective translation if present. It LGMT.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. There's another issue about multi-lingual comments - ah yes it is linked in the issue summary - #2751269-57: Submitting a comment in the non default language redirects you to the default language - which ponders how multilingual comments are supposed to work. I think that we need to do some thinking about what is supposed to happen in the different set-ups:
    • Node has content translation enabled but comment does not
    • Comment has content translation enabled but node does not
    • Node and comment both have content translation enabled

    But I'm not sure that that should block the work here as this change is inline with how entity translations are supposed to work. It's just more evidence that multilingual comments are not well supported or thought about from a core perspective.

  2. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +238,65 @@ protected function doTestTranslationEdit() {
    +      $translation = $comment->addTranslation($langcode, $values[$langcode]);
    

    No need to assign $translation here. It is never used.

  3. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +238,65 @@ protected function doTestTranslationEdit() {
    +    // Need to check from the beginning, including the base_path, in the url
    +    // since the pattern for the default language might be a substring of
    +    // the strings for other languages.
    +    $base_path = base_path();
    

    Can be removed see below.

  4. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +238,65 @@ protected function doTestTranslationEdit() {
    +      $this->drupalGet("comment/$comment_id", ['language' => \Drupal::languageManager()->getLanguage($langcode)]);
    +      $links = [];
    +      if ($langcode == $default_langcode) {
    +        // Site default language does not have langcode prefix in the URL.
    +        $links = [
    +          'Edit' => $base_path . 'comment/' . $comment_id . '/edit',
    +          'Delete' => $base_path . 'comment/' . $comment_id . '/delete',
    +          'Translate' => $base_path . 'comment/' . $comment_id . '/translations',
    +          'Reply' => $base_path . 'comment/reply/node/' . $node_id . '/comment_article/' . $comment_id,
    +          'Approve' => $base_path . 'comment/' . $comment_id . '/approve',
    +        ];
    +      }
    +      else {
    +        $links = [
    +          'Edit' => $base_path . $langcode . '/comment/' . $comment_id . '/edit',
    +          'Delete' => $base_path . $langcode . '/comment/' . $comment_id . '/delete',
    +          'Translate' => $base_path . $langcode . '/comment/' . $comment_id . '/translations',
    +          'Reply' => $base_path . $langcode . '/comment/reply/node/' . $node_id . '/comment_article/' . $comment_id,
    +          'Approve' => $base_path . $langcode . '/comment/' . $comment_id . '/approve',
    +        ];
    +      }
    

    This could be written as

          $options = ['language' => \Drupal::languageManager()->getLanguage($langcode)];
          $this->drupalGet("comment/$comment_id", $options);
          $links = [
            'Edit' => $comment->toUrl('edit-form', $options)->toString(),
            'Delete' => $comment->toUrl('delete-form', $options)->toString(),
            'Translate' => $comment->toUrl('drupal:content-translation-overview', $options)->toString(),
            'Reply' => Url::fromRoute('comment.reply', ['entity_type' => 'node', 'entity' => $node_id, 'field_name' => 'comment_article', 'pid' => $comment_id], $options)->toString(),
            'Approve' => Url::fromRoute('comment.approve' , ['comment' => $comment_id], $options)->toString(),
          ];
          // Strip the CSRF token.
          $links['Approve'] = substr($links['Approve'], 0, strpos($links['Approve'], 'token='));
    

    And then we can remove the base_path stuff above -I think this is a bit neater.

  5. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +238,65 @@ protected function doTestTranslationEdit() {
    +      $assert_session = $this->assertSession();
    +      foreach ($links as $label => $expected_href) {
    +        $assert_session->elementExists('xpath', "//article[@id='comment-$comment_id']//a[text()='$label']");
    +        $pattern = '|^' . $expected_href . '.*$|';
    +        $num_match_found = 0;
    +        foreach ($this->xpath("//article[@id='comment-$comment_id']//a[text()='$label']") as $link) {
    +          if (preg_match($pattern, $link->getAttribute('href'), $matches) == TRUE) {
    +            $num_match_found++;
    +          }
    +        }
    +        $this->assertTrue($num_match_found == 1, 'When you view the comment there is 1 ' . $label . ' link, ' . $expected_href . ', for the ' . $langcode . ' translation. (Found ' . $num_match_found . '.)');
    +      }
    

    These assertions can be written like:

          foreach ($links as $label => $expected_href) {
            $links = $this->assertSession()->elementExists('xpath', "//article[@id='comment-$comment_id']")
              ->findAll('xpath', "//a[text()='$label']");
            $this->assertCount(1, $links);
            $this->assertRegExp('|^' . $expected_href . '.*$|', $links[0]->getAttribute('href'));
          }
    

    Using phpunit's more specific assertions over assertTrue is generally preferred.

    And note it's no longer necessary to do $assert_session = $this->assertSession();

manisha111’s picture

Assigned: Unassigned » manisha111
manisha111’s picture

Assigned: manisha111 » Unassigned
Status: Needs work » Needs review
StatusFileSize
new4.24 KB
new4.15 KB

According to the comment #31, patch added for point 2, 3, 4 and 5.

Please review.

Thanks & Regards
Manisha Bhawsar

Status: Needs review » Needs work

The last submitted patch, 33: 3134223-33.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

hardik_patel_12’s picture

Assigned: Unassigned » hardik_patel_12
hardik_patel_12’s picture

Status: Needs work » Needs review
StatusFileSize
new5.16 KB
new564 bytes

Solving failed test cases.

Status: Needs review » Needs work

The last submitted patch, 36: 3134223-36.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

hardik_patel_12’s picture

Assigned: hardik_patel_12 » Unassigned
matsbla’s picture

StatusFileSize
new4.55 KB
new2.11 KB

Thanks a lot for the feedbacks, I think now all the mentioned issues should be fixed.

matsbla’s picture

Status: Needs work » Needs review
quietone’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update, +Needs tests

Thanks everyone, there is getting there.

I started my review by reading the Issue Summary. It is nice to see there are steps to reproduce. They could be improved by starting from the install of Drupal whereas this starts from an existing comment type. If I were to test this my first question would be, what profile was used for the install? Next I was looking for some idea of what the fix is. That is not explained nor is there a 'proposed resolution' section. Also missing is 'remaining tasks', so as a reviewer I need to start from scratch. Please use dreditor and insert the issue summary template and complete it. Tagging needs issue summary update.

I have read through the issue and found that #15.1 is still to do. Setting NW for that.

The test creates two translations, 'it' and 'fr' and then tests rendering those translations. Without the fix the test fails because it has not loaded the 'it' translation. That is good to see. What I don't see is a test of case where the translation does not exist. A test for that needs to be added. Adding 'needs tests' for that.

And I have some of my own questions/comments.

  1. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -6,6 +6,7 @@
    +use Drupal\Core\Url;
    

    Please add in alphabetical order as much is possible.

  2. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +239,45 @@ protected function doTestTranslationEdit() {
    +    // Check that each of the local tasks links to correct translation.
    

    This is a tough read. Should it be 'Check that each local task links to the correct translation'?

  3. +++ b/core/modules/comment/src/CommentLazyBuilders.php
    @@ -137,6 +137,12 @@ public function renderLinks($comment_entity_id, $view_mode, $langcode, $is_in_pr
    +      catch (\InvalidArgumentException $e) {
    +        // Invalid translation language ($langcode) specified.
    

    Feels like this comment needs more information and $langcode is redundant. Maybe 'Ignore invalid translation language because ...'

  4. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +239,45 @@ protected function doTestTranslationEdit() {
    +      $links = [];
    

    Can be removed. $links is set in the third line below.

matsbla’s picture

Issue summary: View changes
StatusFileSize
new4.56 KB
new1.88 KB

Thank you for the review.

Adding summary template.

Fixed #41.1-4.

In #31 @alexpott wrote

And note it's no longer necessary to do $assert_session = $this->assertSession();

So from my understanding I don't think #15.1 is still to do.

matsbla’s picture

Issue summary: View changes
matsbla’s picture

matsbla’s picture

Issue summary: View changes
Issue tags: -Needs tests
StatusFileSize
new4.53 KB
new10.4 KB

I'm attaching tests for when the translation does not exists.

However, I wonder how we in these cases should handle Reply, Approve and Translate links? I think it makes sense that Edit and Delete link directs you to the form in correct language. However, maybe the other mentioned links should stay in current interface language?

matsbla’s picture

Issue summary: View changes
matsbla’s picture

StatusFileSize
new2.89 KB

Sorry, here is correct interdiff

matsbla’s picture

Status: Needs work » Needs review
andypost’s picture

I looks great! Just minor nitpics

Please file separate test-only.patch to prove that test catching the bug

  1. +++ b/core/modules/comment/src/CommentLazyBuilders.php
    @@ -137,6 +137,12 @@ public function renderLinks($comment_entity_id, $view_mode, $langcode, $is_in_pr
    +      try {
    +        $entity = $entity->getTranslation($langcode);
    +      }
    

    Maybe if ($entity->hasTranslation($langcode)) {..} will be less expensive instead of exception

  2. +++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
    @@ -238,4 +239,49 @@ protected function doTestTranslationEdit() {
    +      // Strip the CSRF token.
    +      $links['Approve'] = substr($links['Approve'], 0, strpos($links['Approve'], 'token='));
    

    Should tell why token is stripped

matsbla’s picture

StatusFileSize
new4.49 KB
new3.11 KB
new2.54 KB

Fixing 49.1-2

Thank you!

Status: Needs review » Needs work

The last submitted patch, 50: 3134223-50-test-only.patch, failed testing. View results

andypost’s picture

Status: Needs work » Needs review

Known test failure, btw test-only should be uploaded before fixed one to not change status on failure

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.

viappidu’s picture

StatusFileSize
new4.52 KB

Rewrite for 9.1.x

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.

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.

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.

borisson_’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

This patch needs to be rerolled.

In #31, @alexpott mentioned the work going on in #2751269, that issue is still going on so I think we can still get this in when it is rerolled.

jungle’s picture

mrinalini9’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new4.54 KB

Rerolled patch #54 for 9.5.x, please review it.

Status: Needs review » Needs work

The last submitted patch, 60: 3134223-60.patch, failed testing. View results

ravi.shankar’s picture

Status: Needs work » Needs review
StatusFileSize
new4.57 KB
new841 bytes

Trying to fix failed tests of patch #60.

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.

larowlan’s picture

Status: Needs review » Needs work
+++ b/core/modules/comment/tests/src/Functional/CommentTranslationUITest.php
@@ -234,4 +235,49 @@ protected function doTestTranslationEdit() {
+      if (!$comment->hasTranslation($langcode)) {
+        $options = ['language' => \Drupal::languageManager()->getLanguage($default_langcode)];
+      }

I think we should also assert that $options['language'] doesn't equal the default langcode for all except $default_langcode and $not_translated_langcode

prem suthar’s picture

StatusFileSize
new4.56 KB

Re-roll the patch For 10.1

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.

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

acbramley’s picture

Rolled #65 into an MR, the test was failing on missing Reply links. I've removed that for now assuming that something has changed and this isn't expected anymore. #64 still needs actioning.

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.