web-dev-qa-db-ja.com

現在の言語に翻訳されたメニュー項目のみを表示するようにメニューをフィルタリングするにはどうすればよいですか?

私のDrupal 8プロジェクトでは、メニュー項目を英語で含むメニューがあります。一部の項目にはドイツ語の翻訳があります。サイトを表示しているときにドイツ語の項目のみを表示するようにメニューをフィルタリングするにはどうすればよいですか。ドイツ人?

現在MenuLinkTreeを使用してメニューをフェッチしています。現在の言語に翻訳されていないMenuLinkContentアイテムを除外するために、独自のMenuLinkTreeManipulator変換を作成しました。しかし、MenuLinkContentオブジェクトからエンティティを取得するメソッドは保護されているため、基になるエンティティの言語プロパティにアクセスできません。

MenuLinkContentオブジェクトの言語を見つける他の方法はありますか?または、現在の言語でメニューをフィルタリングする別の方法?

編集:

以下は、MenuLinkTreeサービスを介してメニューを取得するときに現在(変換として)使用しているメソッドです。

_public function currentLanguage($tree) {
  $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();

  return array_filter($tree, function($item) use($lang) {
    return $item->link->getEntity()->language()->getId() === $lang;
  });
}
_

上記の_$item->link_は_\Drupal\menu_link_content\Plugin\Menu\MenuLinkContent_のインスタンスです。 $item->link->getEntity()は保護されたメソッドであるため、上記のコードは機能しません。公開すると、上記のコードが機能します。コアをハッキングせずに、基盤となるエンティティにアクセスする方法はありません。それは何らかの方法で可能ですか?このモジュールをカスタムモジュールの独自の実装に「スワップアウト」することは可能ですか?

4
reekris

私はこれを解決する別の方法を見つけました。これははるかに簡単で、MenuLinkTreeマニピュレータ全体をバイパスすることができます。代わりに、単に_hook_node_access_を追加し、現在表示されている言語で$node->language()を使用して翻訳されていない場合は、ノードへのアクセスを制限します。 MenuLinkTreeサービスは各メニュー項目を取得するときにノードアクセスをチェックするため、これによりメニュー項目が非表示になります。

注:これは、ノードに接続されているコンテンツメニュー項目に対してのみ機能します。私の場合、それは私が必要としていたことです。

@Berdirによってこの回答からアイデアを得ました: 言語に基づいてエンティティ参照フィールドをフィルタリングするにはどうすればよいですか?

これが私のソリューションの要点です。これには、言語による段落のフィルタリングとカスタムinline_entityも含まれます。 https://Gist.github.com/reekris/e6f64de799df75d724c2

0
reekris

次のコードを使用して、翻訳されていないメニュー項目を非表示にできました。

use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;

/**
* Implements hook_preprocess_menu().
*/
function MY_MODULE_preprocess_menu(&$variables) {
  if ($variables['menu_name'] == 'main') {
   $language = Drupal::languageManager()->getCurrentLanguage()->getId();

    foreach ($variables['items'] as $key => &$item) {
      $menuLinkEntity = MY_MODULE_load_link_entity_by_link($item['original_link']);

      if ($menuLinkEntity != NULL) {
        $languages = $menuLinkEntity->getTranslationLanguages();
        // Remove links which is not translated to current language.
        if (!array_key_exists($language, $languages)) {
          unset($variables['items'][$key]);
        }
      }
    }
  }
}

function MY_MODULE_load_link_entity_by_link(MenuLinkInterface $menuLinkContentPlugin) {
  $entity = NULL;

  if ($menuLinkContentPlugin instanceof MenuLinkContent) {
    list($entity_type, $uuid) = explode(':', $menuLinkContentPlugin->getPluginId(), 2);
    $entity = \Drupal::entityManager()->loadEntityByUuid($entity_type, $uuid);
  }
  return $entity;
}

おそらくもっと良い方法がありますが、これは私にとってはうまくいきました。ここからインスピレーションを得ました: http://www.agoradesign.at/blog/add-custom-menu-item-attributes-drupal-8

6
Sockiplast

簡単に言えば、それはできません。

より長い答えはあなたができるということですが、それは依存します。

背景情報

メニュー項目のトリッキーなことは、一部は.ymlファイルを介して作成され、一部はビューを介して作成され、一部はコンテンツエンティティとして作成されることです。

つまり、メニュー項目の翻訳方法は、

  • インターフェース翻訳
  • 構成変換
  • コンテンツ翻訳

私はこの問題をベータ6〜8の周りで見て、ガボールと話しました(翻訳イニシアチブのリーダー)。オープンチケットがあります( https://www.drupal.org/node/246655 )が、作業は行われていません。これを実際に修正できるかどうかはわかりません。

可能な解決策/回避策

メニューがコンテンツメニュー項目(インターフェースで作成されたメニュー項目)のみで存在することを確認すると、解決策を作成できます。基本的には、ビューを使用してメニュー項目を表示する必要があります。ビューのインターフェースでは、言語にフィルターをかけ、翻訳されていないメニュー項目を除外できます。メニューを展開する必要がある場合、どれだけうまく機能するかわかりません。しかし、一部のユースケースでは、これは簡単な解決策になります。

メニュー項目を拡張する必要がある場合は、おそらくビューを使用してこれを行うこともできますが、アクティブなメニュー項目の下のメニュー項目を取得するには、さらに多くの作業とおそらくカスタムコードが必要になると思います。

1
googletorp

@ Sockiplast のコードスニペットを更新して、機能が低下した関数 entityManager() を削除しました。ツリー全体からメニュー項目を削除するための改善も行われ、第1レベルのメニューの深さだけではありません。

use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;

/**
* Implements hook_preprocess_menu().
*/
function MY_MODULE_preprocess_menu(&$variables) {

  if ($variables['menu_name'] == 'main') {
    // Get context language.
    $language = Drupal::languageManager()->getCurrentLanguage()->getId();

    if (isset($variables['items'])) {
      MY_MODULE_menu_item_cleanup($variables['items'], $language);
    }
  }
}

/**
 * Recursive function to remove menu items with different language
 * than context language.
 *
 * @param $items
 *   Menu items for current menu depth.
 * @param $language
 *   The context language.
 */
function MY_MODULE_menu_item_cleanup(&$items, $language) {

  // Check language for current menu depth.
  foreach ($items as $key => &$item) {
    $menuLinkEntity = MY_MODULE_load_link_entity_by_link($item['original_link']);

    // Ignore if we don´t have a menu object.
    if ($menuLinkEntity != NULL) {
      $languages = $menuLinkEntity->getTranslationLanguages();

      // Remove links with different language than context.
      if (!array_key_exists($language, $languages)) {
        unset($items[$key]);
      }
      // Recursive call until no more below items exists.
      else if (isset($items[$key]['below'])) {
        MY_MODULE_menu_item_cleanup($items[$key]['below'], $language);
      }
    }
  }
}

function MY_MODULE_load_link_entity_by_link(MenuLinkInterface $menuLinkContentPlugin) {
  $entity = NULL;

  if ($menuLinkContentPlugin instanceof MenuLinkContent) {
    list($entity_type, $uuid) = explode(':', $menuLinkContentPlugin->getPluginId(), 2);
    $entity = \Drupal::service('entity.repository')->loadEntityByUuid($entity_type, $uuid);
  }
  return $entity;
}
0
Kleve

現在使用している別の解決策は、モジュール Menu Multilingual です。各メニューブロックで多言語オプションを取得します。

enter image description here

また、選択したオプションを使用すると、メニューは、現在の言語での翻訳または中立言語設定のアイテムのみで構成されます。

0
RWAM