Entity Translation API
In Drupal 8 wird die Sprache von Feldern nicht mehr über die öffentliche API bereitgestellt, stattdessen sind Felder an sprachunterstützende Objekte angehängt, von denen sie ihre Sprache „erben“.
Die wichtigsten Vorteile sind dabei:
- Wir müssen uns nicht um die Sprachzuordnung der Felder kümmern, da dies vom Entity-Objekt intern gehandhabt wird.
// Bestimmen Sie auf irgendeine Weise den $active_langcode.
$translation = $entity->getTranslation($active_langcode);
$value = $translation->field_foo->value;
- Wir müssen den aktiven Sprachcode nicht mehr übergeben, sondern können einfach das Übersetzungsobjekt verwenden, das EntityInterface implementiert und im Grunde ein Klon des Original-Objekts mit anderer interner Sprache ist. Das bedeutet, dass der Code in vielen Fällen keine Kenntnis von der Sprache benötigt (außer er bezieht sich explizit darauf).
// Instanziiere das passende Übersetzungsobjekt nur einmal und übergebe es überall,
// wo es benötigt wird. Dies wird typischerweise von Core-Subsystemen erledigt,
// sodass eine explizite Abfrage meist nicht nötig ist.
$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;
// tue etwas
}
- Wir haben nun eine wiederverwendbare API für die Sprachverhandlung auf Entity-Ebene, mit der wir die passendste Übersetzung für einen bestimmten Kontext bestimmen können:
// Vereinfachter Code zur Erstellung eines renderbaren Arrays für eine Entity.
function viewEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
// Die Methode EntityManagerInterface::getTranslationFromContext() wendet
// die Sprachverhandlungslogik auf die gesamte Entity an und liefert
// das passende Übersetzungsobjekt für den gegebenen Kontext zurück.
// Der Parameter $langcode ist optional und gibt die Sprache des
// aktuellen Kontexts an. Wird er nicht angegeben, wird die
// aktuelle Inhaltssprache verwendet, was in der Renderphase gewünscht ist.
// Beachten Sie, dass Feldwerte nicht verändert werden; leere Werte
// werden einfach nicht angezeigt.
$langcode = NULL;
$translation = $this->entityManager->getTranslationFromContext($entity, $langcode);
$build = entity_do_stuff($translation, 'full');
return $build;
}
Wir können auch einen optionalen Parameter $context angeben, um den Kontext zu beschreiben, in dem das Übersetzungsobjekt verwendet wird:
// Vereinfachter Code zur Erzeugung von Token-Ersetzungen.
function node_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
// Wenn keine Sprache für diesen Kontext angegeben ist, verwenden wir
// die Standardsprache der Entity.
if (!isset($options['langcode'])) {
$langcode = Language::LANGCODE_DEFAULT;
}
// Wir übergeben einen $context-Parameter, der die durchgeführte
// Operation beschreibt. Die Standardoperation ist 'entity_view'.
$context = array('operation' => 'node_tokens');
$translation = \Drupal::service('entity.repository')->getTranslationFromContext($data['node'], $langcode, $context);
$items = $translation->get('body');
// mache etwas
return $replacements;
}
Die Logik, die das zurückgegebene Übersetzungsobjekt bestimmt, kann durch Module verändert werden. Siehe LanguageManager::getFallbackCandidates() für Details.
Die eigentlichen Feldwerte sind über alle Übersetzungsobjekte verteilt, und Änderungen an einem nicht übersetzbaren Feld wirken sich automatisch auf alle Übersetzungen aus.
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$en_value = $entity->field_foo->value; // $en_value ist 'bar'
$it_value = $translation->field_foo->value; // $it_value ist 'bella'
$entity->field_untranslatable->value = 'baz';
$translation->field_untranslatable->value = 'zio';
$value = $entity->field_untranslatable->value; // $value ist 'zio'
Jederzeit kann eine Instanz eines Übersetzungsobjekts aus dem Originalobjekt oder einem anderen Übersetzungsobjekt über die Methode EntityInterface::getTranslation() erzeugt werden. Wenn der aktive Sprachcode explizit benötigt wird, kann er über EntityInterface::language() abgefragt werden. Das Originalobjekt kann über EntityInterface::getUntranslated() abgerufen werden.
$entity->langcode->value = 'en';
$translation = $entity->getTranslation('it');
$langcode = $translation->language()->id; // $langcode ist 'it';
$untranslated_entity = $translation->getUntranslated();
$langcode = $untranslated_entity->language()->id; // $langcode ist 'en';
$identical = $entity === $untranslated_entity; // $identisch ist TRUE
$entity_langcode = $translation->getUntranslated()->language()->id; // $entity_langcode ist 'en'
EntityInterface verfügt jetzt über mehrere Methoden, die die Arbeit mit Entity-Übersetzungen erleichtern. Wenn ein Code-Abschnitt für jede verfügbare Übersetzung ausgeführt werden soll, kann EntityInterface::getTranslationLanguages() verwendet werden:
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
$translation = $entity->getTranslation($langcode);
entity_do_stuff($translation);
}
Es gibt auch Methoden zum Hinzufügen, Entfernen oder Prüfen von Übersetzungen:
if (!$entity->hasTranslation('fr')) {
$translation = $entity->addTranslation('fr', array('field_foo' => 'bag'));
}
// Das entspricht folgendem Code, wobei eine Ausnahme geworfen wird, wenn
// ein ungültiger Sprachcode angegeben wird.
$translation = $entity->getTranslation('fr');
$translation->field_foo->value = 'bag';
// Der Zugriff auf ein Feld eines entfernten Übersetzungsobjekts löst eine
// Ausnahme aus.
$translation = $entity->getTranslation('it');
$entity->removeTranslation('it');
$value = $translation->field_foo->value; // wirft InvalidArgumentException
Wenn Übersetzungen einer Entity hinzugefügt oder daraus entfernt werden, werden folgende Hooks ausgelöst:
- hook_entity_translation_insert()
- hook_entity_translation_delete()
Die Sprache eines Feldes kann weiterhin durch den entsprechenden Methodenaufruf am Feldobjekt abgefragt werden:
$langcode = $translation->field_foo->getLangcode();