私の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()
は保護されたメソッドであるため、上記のコードは機能しません。公開すると、上記のコードが機能します。コアをハッキングせずに、基盤となるエンティティにアクセスする方法はありません。それは何らかの方法で可能ですか?このモジュールをカスタムモジュールの独自の実装に「スワップアウト」することは可能ですか?
私はこれを解決する別の方法を見つけました。これははるかに簡単で、MenuLinkTree
マニピュレータ全体をバイパスすることができます。代わりに、単に_hook_node_access
_を追加し、現在表示されている言語で$node->language()
を使用して翻訳されていない場合は、ノードへのアクセスを制限します。 MenuLinkTree
サービスは各メニュー項目を取得するときにノードアクセスをチェックするため、これによりメニュー項目が非表示になります。
注:これは、ノードに接続されているコンテンツメニュー項目に対してのみ機能します。私の場合、それは私が必要としていたことです。
@Berdirによってこの回答からアイデアを得ました: 言語に基づいてエンティティ参照フィールドをフィルタリングするにはどうすればよいですか?
これが私のソリューションの要点です。これには、言語による段落のフィルタリングとカスタムinline_entityも含まれます。 https://Gist.github.com/reekris/e6f64de799df75d724c2
次のコードを使用して、翻訳されていないメニュー項目を非表示にできました。
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
簡単に言えば、それはできません。
より長い答えはあなたができるということですが、それは依存します。
メニュー項目のトリッキーなことは、一部は.ymlファイルを介して作成され、一部はビューを介して作成され、一部はコンテンツエンティティとして作成されることです。
つまり、メニュー項目の翻訳方法は、
私はこの問題をベータ6〜8の周りで見て、ガボールと話しました(翻訳イニシアチブのリーダー)。オープンチケットがあります( https://www.drupal.org/node/246655 )が、作業は行われていません。これを実際に修正できるかどうかはわかりません。
メニューがコンテンツメニュー項目(インターフェースで作成されたメニュー項目)のみで存在することを確認すると、解決策を作成できます。基本的には、ビューを使用してメニュー項目を表示する必要があります。ビューのインターフェースでは、言語にフィルターをかけ、翻訳されていないメニュー項目を除外できます。メニューを展開する必要がある場合、どれだけうまく機能するかわかりません。しかし、一部のユースケースでは、これは簡単な解決策になります。
メニュー項目を拡張する必要がある場合は、おそらくビューを使用してこれを行うこともできますが、アクティブなメニュー項目の下のメニュー項目を取得するには、さらに多くの作業とおそらくカスタムコードが必要になると思います。
@ 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;
}
現在使用している別の解決策は、モジュール Menu Multilingual です。各メニューブロックで多言語オプションを取得します。
また、選択したオプションを使用すると、メニューは、現在の言語での翻訳または中立言語設定のアイテムのみで構成されます。