0

In D7, if a node is translated, let say in French and if you are in the entity.node.edit_form page then you could find 2 secondary tabs: [French] and [English] pointing to the edit_form of each language.

To achieve this in D8, I looked at the derivatives, but they are loaded once during cache clear and can't evaluate the current entity.

Following the 4k4 comment I have tried to subclass LocalTaskDefault But I am stuck with the following problems:

1-How can I create a route for a defined language (eg: a route to edit a french node)

2-In .links.task.yml: should I create as many tabs as there are languages (I don't think so)

Here is my .links.task.ymlfile

translated_node_tabs:
  class: Drupal\mymodule\Plugin\Menu\TranslatedNodeTab
  title: 'Translated nodes'
  base_route: entity.node.edit_form
  route_name:  entity.node.edit_form 

And here is the very beginning of what I have understood from the 4k4 advice

class TranslatedNodeTab extends LocalTaskDefault {
  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return [
        'route'
    ];
  }
  /**
   * {@inheritdoc}
   */
  public function getRouteParameters(RouteMatchInterface $route_match) {
    $current_node = $route_match->getParameter('node');
    if ($current_node instanceof NodeInterface) {
      $nid = $current_node->id();
      return [
          'node' => $nid
      ];
    }
    return [];
  }
}
7
  • Move the code from the derivative to a plugin class, similar to this answer for menu links drupal.stackexchange.com/a/249342/47547
    – 4uk4
    Apr 13, 2020 at 18:28
  • Many thank, I think I am more close to the solution... May I ask you to look at my updated question to let me know what I should change/add to make it work... I really have no clue.
    – Baud
    Apr 14, 2020 at 21:21
  • For the language part you could use a deriver if you don't want to make a static entry for each language in the yaml file. Then you can use the derived language to build the route in the plugin class. There is no node context by the way, use route.
    – 4uk4
    Apr 15, 2020 at 6:33
  • ok, I will use one entry per language in yaml. But how can I distinguish FR and EN edit_form in yaml? And you say "Then you can use the derived language to build the route in the plugin class." => How to build a route in the plugin? I assume I have to use getRouteName()... but same question: how to provide the localized route. Thank for the context, I have updated my question with the route context
    – Baud
    Apr 15, 2020 at 7:56
  • You can use the language id as derivative id and then get the language in the plugin: $this->getDerivativeId()
    – 4uk4
    Apr 15, 2020 at 9:09

1 Answer 1

1

Add a derivative for each language:

/mymodule/src/Plugin/Derivative/TranslatedNodeTabDeriver.php

<?php

namespace Drupal\mymodule\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;

class TranslatedNodeTabDeriver extends DeriverBase {

  use StringTranslationTrait;

  /**
   * {@inheritdoc}
   */
  public function getDerivativeDefinitions($base_plugin_definition) {
    $this->derivatives = [];
    foreach (\Drupal::languageManager()->getLanguages() as $language) {
      $lang_id = $language->getId();
      $this->derivatives[$lang_id] = $base_plugin_definition;
      $this->derivatives[$lang_id]['title'] = $this->t('Translate @language', ['@language' => $language->getName()]);
    }
    return $this->derivatives;
  }

}

and then you can get the language id with $this->getDerivativeId() in the plugin class:

/mymodule/src/Plugin/Menu/TranslatedNodeTab.php

<?php

namespace Drupal\mymodule\Plugin\Menu;

use Drupal\Core\Menu\LocalTaskDefault;
use Drupal\Core\Routing\RouteMatchInterface;

class TranslatedNodeTab extends LocalTaskDefault {

  /**
   * {@inheritdoc}
   */
  public function getOptions(RouteMatchInterface $route_match) {
    $options = parent::getOptions($route_match);
    $options['language'] = \Drupal::languageManager()->getLanguage($this->getDerivativeId());
    return $options;
  }

}

/mymodule/mymodule.links.task.yml

translated_node_tabs:
  class: Drupal\mymodule\Plugin\Menu\TranslatedNodeTab
  deriver: Drupal\mymodule\Plugin\Derivative\TranslatedNodeTabDeriver
  base_route: entity.node.canonical
  route_name: entity.node.edit_form
6
  • many thanks for your precious help and your kindness, this is working so well!!! But there are 2 linked problems: 1-I put the tabs on the secondary tabs with parent_id:entity.node.edit_form unfortunately all tabs are active even if I manage to setActive in the Plugin. Looking at the code, this is the LocalTaskManager which is setting active by checking only at the route and not the language ($active = $this->isRouteActive). 2- If a node is not translated in one language, the corresponding tab should not be displayed: do you think it is possible to handle this in OO?
    – Baud
    Apr 15, 2020 at 21:09
  • 1. $active is transfered to the class is-active in getOptions(). Since this method is already overridden you can remove the first line which gets this class from the parent and replace it with our own logic. 2, You can get the node like in your first code snippet and do the check.
    – 4uk4
    Apr 16, 2020 at 6:36
  • Again many thanks... I could solve (2) thanks to your help, but for (1) as I said, the active property of the tabs is set in the calling function LocalTaskManager->getTasksBuild() in this line: $active = $this->isRouteActive. In the plugIn getOptions function, If I replace the line $options = parent::getOptions($route_match); by $this->active=false; all the tabs will stay active because of the work doing by LocalTaskManager->getTasksBuild() afterwards
    – Baud
    Apr 16, 2020 at 9:04
  • I see, this makes it impossible plugin side. You could override the plugin manager, but an easier option is probably to use hook_menu_local_tasks_alter which the plugin manager invokes after running getTasksBuild() to change #active.
    – 4uk4
    Apr 16, 2020 at 9:27
  • I will go with the hook... Do you think it is a core bug that I should create? eg: LocalTaskManager should use the child plugin logic (if any) to set the active tab property
    – Baud
    Apr 16, 2020 at 9:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.