diff --git a/core/core.services.yml b/core/core.services.yml index 38239bc01..9fd91bc75 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -770,6 +770,10 @@ services: class: Drupal\Core\Menu\DefaultMenuLinkTreeManipulators arguments: ['@access_manager', '@current_user', '@entity_type.manager', '@module_handler'] Drupal\Core\Menu\DefaultMenuLinkTreeManipulators: '@menu.default_tree_manipulators' + menu.language_tree_manipulator: + class: Drupal\Core\Menu\LanguageMenuLinkManipulator + arguments: ['@language_manager'] + Drupal\Core\Menu\LanguageMenuLinkManipulator: '@menu.language_tree_manipulator' menu.active_trail: class: Drupal\Core\Menu\MenuActiveTrail arguments: ['@plugin.manager.menu.link', '@current_route_match', '@cache.menu', '@lock'] diff --git a/core/lib/Drupal/Core/Menu/LanguageMenuLinkManipulator.php b/core/lib/Drupal/Core/Menu/LanguageMenuLinkManipulator.php new file mode 100644 index 000000000..40292b39b --- /dev/null +++ b/core/lib/Drupal/Core/Menu/LanguageMenuLinkManipulator.php @@ -0,0 +1,57 @@ +languageManager = $language_manager; + } + + /** + * Hide menu links that do not have translation for the current language. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. + * + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. + */ + public function filterLanguage(array $tree) : array { + $current_language = $this->languageManager->getCurrentLanguage()->getId(); + + foreach ($tree as $key => $link) { + if ($link->link instanceof MenuLinkTranslationInterface) { + // If the link is translatable, but has no translation, hide it. + if ($link->link->isTranslatable() && !$link->link->hasTranslation($current_language)) { + unset($tree[$key]); + } + elseif ($link->hasChildren) { + // Recursively call this method to filter out untranslated children. + $tree[$key]->subtree = $this->filterLanguage($link->subtree); + } + } + } + return $tree; + } + +} diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTranslationInterface.php b/core/lib/Drupal/Core/Menu/MenuLinkTranslationInterface.php new file mode 100644 index 000000000..3153243e9 --- /dev/null +++ b/core/lib/Drupal/Core/Menu/MenuLinkTranslationInterface.php @@ -0,0 +1,21 @@ +getEntity()->isTranslatable(); } + /** + * {@inheritdoc} + */ + public function hasTranslation($langcode) : bool { + $entity = $this->getEntity(); + return $entity->hasTranslation($langcode) + && Url::fromUri($entity->link->uri)->access(); + } + /** * {@inheritdoc} */ diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php index 463b6800b..297fa987d 100644 --- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php @@ -189,6 +189,7 @@ public function build() { $manipulators = [ ['callable' => 'menu.default_tree_manipulators:checkAccess'], ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], + ['callable' => 'menu.language_tree_manipulator:filterLanguage'], ]; $tree = $this->menuTree->transform($tree, $manipulators); return $this->menuTree->build($tree);