滚动
Entity 翻译 API
在 Drupal 8 中,字段语言不再通过公共 API提供,而是附加到支持语言的实体对象上,并从这些对象中“继承”其语言。
这里的主要优点是:
- 我们不再需要担心字段的可移植性,因为实体对象会在内部处理。
// 以某种方式确定 $active_langcode。
$translation = $entity->getTranslation($active_langcode);
$value = $translation->field_foo->value;
- 我们不再需要传递活动语言,实际上我们可以直接传递翻译对象,该对象实现了 EntityInterface,实际上是原始对象的克隆,只是具有不同的内部语言。这意味着在很多情况下,生成的代码可能并不知道语言(当然,除非它显式与语言相关)。
// 只实例化一次合适的翻译对象,并在需要的地方传递。
// 通常由核心子系统负责,在很多常见情况下不需要显式检索翻译对象。
$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;
// 处理逻辑
}
- 现在我们有了可重用的实体语言协商 API,可以用来确定最适合某一特定上下文的实体翻译:
// 生成实体可渲染数组的简化代码。
function viewEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
// EntityManagerInterface::getTranslationFromContext() 方法将
// 对整个实体对象应用实体语言协商逻辑,并返回适用于给定上下文的正确翻译对象。
// $langcode 参数是可选的,用于指示当前上下文的语言。
// 如果未指定,则使用当前内容语言,这正是渲染阶段所需的行为。
// 注意:字段值不会在此过程中更改,因此空值不会显示。
$langcode = NULL;
$translation = $this->entityManager->getTranslationFromContext($entity, $langcode);
$build = entity_do_stuff($translation, 'full');
return $build;
}
我们还可以指定可选的 $context 参数,用于描述翻译对象将使用的上下文:
// 简化的 token 替换生成代码。
function node_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
// 如果此上下文没有指定语言,则默认使用实体的默认语言。
if (!isset($options['langcode'])) {
$langcode = Language::LANGCODE_DEFAULT;
}
// 我们传递一个 $context 参数,描述正在执行的操作。
// 默认操作是 'entity_view'。
$context = array('operation' => 'node_tokens');
$translation = \Drupal::service('entity.repository')->getTranslationFromContext($data['node'], $langcode, $context);
$items = $translation->get('body');
// 执行逻辑
return $replacements;
}
用于确定返回的翻译对象的逻辑可以被模块修改。更多详细信息请参阅 LanguageManager::getFallbackCandidates()。
字段的实际数据在所有翻译对象之间共享,更改不可翻译字段的值会自动更改所有翻译对象。
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$en_value = $entity->field_foo->value; // $en_value 是 'bar'
$it_value = $translation->field_foo->value; // $it_value 是 'bella'
$entity->field_untranslatable->value = 'baz';
$translation->field_untranslatable->value = 'zio';
$value = $entity->field_untranslatable->value; // $value 是 'zio'
任何时候都可以通过 EntityInterface::getTranslation() 方法从原始对象或其他翻译对象创建翻译对象的实例。如果显式需要活动语言,可以通过 EntityInterface::language() 获取。原始实体可以通过 EntityInterface::getUntranslated() 获取。
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$langcode = $translation->language()->id; // $langcode 是 'it';
$untranslated_entity = $translation->getUntranslated();
$langcode = $untranslated_entity->language()->id; // $langcode 是 'en';
$identical = $entity === $untranslated_entity; // $identical 是 TRUE
$entity_langcode = $translation->getUntranslated()->language()->id; // $entity_langcode 是 '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'));
}
// 等价于以下代码,不过如果指定了无效的语言代码会抛出异常。
$translation = $entity->getTranslation('fr');
$translation->field_foo->value = 'bag';
// 访问已删除翻译对象的字段会抛出异常。
$translation = $entity->getTranslation('it');
$entity->removeTranslation('it');
$value = $translation->field_foo->value; // 抛出 InvalidArgumentException
当实体翻译被添加到存储或从存储中移除时,会分别触发以下钩子:
- hook_entity_translation_insert()
- hook_entity_translation_delete()
字段的语言仍然可以通过调用字段对象本身的方法来获取:
$langcode = $translation->field_foo->getLangcode();