Entityの翻訳API
Drupal 8 では、フィールドの言語はパブリック API では提供されなくなりました。代わりに、フィールドは言語対応のエンティティにアタッチされ、言語を「継承」します。
ここでの主な利点は次のとおりです:
- フィールドの移植性について心配する必要はありません。これはエンティティオブジェクトが内部的に処理してくれるためです。
// Determine the $active_langcode somehow.
$translation = $entity->getTranslation($active_langcode);
$value = $translation->field_foo->value;
- アクティブな言語を渡す必要はもうありません。実際、EntityInterface を実装し、実際には元のエンティティのクローンであり、単に内部言語が異なる翻訳オブジェクトを渡すだけです。これは、多くの場合、結果のコードが言語を認識しない可能性があることを意味します(もちろん、言語に明示的に関連している場合を除きます)。
// Instantiate the proper translation object just once and pass it around
// wherever it is needed. This is typically taken care of by core
// subsystems and in many common cases an explicit retrieval of the
// translation object is not needed.
$langcode = Drupal::languageManager()->getLanguage(Language::TYPE_CONTENT);
$translation = $entity->getTranslation($langcode);
entity_do_stuff($translation);
function entity_do_stuff(EntityInterface $entity) {
$value = $entity->field_foo->value;
// do stuff
}
- 現在、特定のコンテキストに最も適したエンティティの翻訳を決定するために使用できる、再利用可能なエンティティ言語ネゴシエーション API があります:
// Simplified code to generate a renderable array for an entity.
function viewEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
// The EntityManagerInterface::getTranslationFromContext() method will
// apply entity language negotiation logic to the whole entity object
// and will return the proper translation object for the given context.
// The $langcode parameter is optional and indicates the language of the
// current context. If it is not specified the current content language
// is used, which is the desired behavior during the rendering phase.
// Note that field values are left alone in the process, so empty values
// will just not be displayed.
$langcode = NULL;
$translation = $this->entityManager->getTranslationFromContext($entity, $langcode);
$build = entity_do_stuff($translation, 'full');
return $build;
}
翻訳オブジェクトが使用されるコンテキストを記述するために使用できる、オプションの $context パラメータを指定することもできます:
// Simplified token replacements generation code.
function node_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
// If no language is specified for this context we just default to the
// default entity language.
if (!isset($options['langcode'])) {
$langcode = Language::LANGCODE_DEFAULT;
}
// We pass a $context parameter describing the operation being performed.
// The default operation is 'entity_view'.
$context = array('operation' => 'node_tokens');
$translation = \Drupal::service('entity.repository')->getTranslationFromContext($data['node'], $langcode, $context);
$items = $translation->get('body');
// do stuff
return $replacements;
}
返される翻訳オブジェクトを決定するために使用されるロジックは、モジュールによって変更できます。詳細については、LanguageManager::getFallbackCandidates() を参照してください。
実際のフィールドデータはすべての翻訳オブジェクト間で共有され、翻訳不可能なフィールドの値を変更すると、すべての翻訳オブジェクトに対して自動的に変更されます。
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$en_value = $entity->field_foo->value; // $en_value is 'bar'
$it_value = $translation->field_foo->value; // $it_value is 'bella'
$entity->field_untranslatable->value = 'baz';
$translation->field_untranslatable->value = 'zio';
$value = $entity->field_untranslatable->value; // $value is 'zio'
EntityInterface::getTranslation() メソッドを使用すると、元のエンティティまたは別の翻訳オブジェクトからいつでも翻訳オブジェクトのインスタンスを作成できます。アクティブな言語が明示的に必要な場合は、EntityInterface::language() を介して取得できます。元のエンティティは EntityInterface::getUntranslated() を介して取得できます。
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$langcode = $translation->language()->id; // $langcode is 'it';
$untranslated_entity = $translation->getUntranslated();
$langcode = $untranslated_entity->language()->id; // $langcode is 'en';
$identical = $entity === $untranslated_entity; // $identical is TRUE
$entity_langcode = $translation->getUntranslated()->language()->id; // $entity_langcode is 'en'
EntityInterface には、エンティティの翻訳の操作を容易にするいくつかのメソッドが追加されました。コードフラグメントが利用可能な各翻訳に対して動作する必要がある場合は、EntityInterface::getTranslationLanguages() を使用できます:
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
$translation = $entity->getTranslation($langcode);
entity_do_stuff($translation);
}
翻訳を追加、削除、または存在を確認する方法もあります:
if (!$entity->hasTranslation('fr')) {
$translation = $entity->addTranslation('fr', array('field_foo' => 'bag'));
}
// Which is equivalent to the following code, although if an invalid language
// code is specified an exception is thrown.
$translation = $entity->getTranslation('fr');
$translation->field_foo->value = 'bag';
// Accessing a field on a removed translation object causes an exception to
// be thrown.
$translation = $entity->getTranslation('it');
$entity->removeTranslation('it');
$value = $translation->field_foo->value; // throws InvalidArgumentException
エンティティの翻訳がストレージに追加されたり、ストレージから削除されたりすると、次のフックがそれぞれ起動されます:
- hook_entity_translation_insert()
- hook_entity_translation_delete()
フィールドの言語は、フィールドオブジェクト自体で対応するメソッドを呼び出して取得することもできます:
$langcode = $translation->field_foo->getLangcode();