Entity Translation API
In Drupal 8 wordt de taal van velden niet langer geleverd via de publieke API. In plaats daarvan worden velden gekoppeld aan taalspecifieke entiteitsobjecten, waarvan ze hun taal «erven».
De belangrijkste voordelen hiervan zijn:
- We hoeven ons geen zorgen meer te maken over de overdraagbaarheid van velden, omdat de entiteit dat intern afhandelt.
// Bepaal de $active_langcode op een bepaalde manier.
$translation = $entity->getTranslation($active_langcode);
$value = $translation->field_foo->value;
- We hoeven de actieve taal niet meer expliciet door te geven, we kunnen gewoon het vertaalobject doorgeven. Dit object implementeert EntityInterface en is in feite een kloon van het oorspronkelijke object, maar dan met een andere interne taal. Dit betekent dat de resulterende code in veel gevallen de taal niet hoeft te kennen (tenzij die expliciet relevant is).
// Instantieer het juiste vertaalobject slechts één keer en geef het door
// waar nodig. Dit wordt meestal door core geregeld en in veel gevallen
// is het expliciet ophalen van het vertaalobject niet nodig.
$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;
// doe iets
}
- We hebben nu een herbruikbare API voor taalonderhandeling op entity-niveau, waarmee kan worden bepaald welke vertaling het meest geschikt is voor een bepaalde context:
// Vereenvoudigde code om een renderbare array te genereren voor een entiteit.
function viewEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
// De methode EntityManagerInterface::getTranslationFromContext() past
// de taallogica toe op het hele entiteitsobject en retourneert de juiste
// vertaling voor de gegeven context.
// De parameter $langcode is optioneel en geeft de taal van de huidige
// context aan. Indien niet opgegeven, wordt de huidige contenttaal gebruikt,
// wat het gewenste gedrag is tijdens renderen.
// Let op: veldwaarden blijven onaangetast, lege waarden worden gewoon niet getoond.
$langcode = NULL;
$translation = $this->entityManager->getTranslationFromContext($entity, $langcode);
$build = entity_do_stuff($translation, 'full');
return $build;
}
We kunnen ook een optionele parameter $context opgeven, die de context beschrijft waarin het vertaalobject wordt gebruikt:
// Vereenvoudigde code voor token-vervanging.
function node_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
// Indien geen taal is opgegeven, gebruiken we de standaard entiteitstaal.
if (!isset($options['langcode'])) {
$langcode = Language::LANGCODE_DEFAULT;
}
// We geven een $context parameter mee die de uitgevoerde operatie beschrijft.
// De standaardoperatie is 'entity_view'.
$context = array('operation' => 'node_tokens');
$translation = \Drupal::service('entity.repository')->getTranslationFromContext($data['node'], $langcode, $context);
$items = $translation->get('body');
// doe iets
return $replacements;
}
De logica die bepaalt welk vertaalobject wordt teruggegeven kan door modules worden aangepast. Zie LanguageManager::getFallbackCandidates() voor meer informatie.
De eigenlijke velddata worden gedeeld tussen alle vertaalobjecten. Een wijziging in een niet-vertaalbaar veld wordt automatisch doorgevoerd in alle vertalingen.
$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'
Op elk moment kan een vertaalobject worden aangemaakt uit het oorspronkelijke object of een ander vertaalobject via de methode EntityInterface::getTranslation(). Indien de actieve taal nodig is, kan die worden opgehaald met EntityInterface::language(). Het oorspronkelijke object kan worden opgehaald via 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 heeft nu meerdere methodes die het werken met entiteitsvertalingen eenvoudiger maken. Als een codefragment voor elke beschikbare vertaling moet draaien, kan het gebruikmaken van EntityInterface::getTranslationLanguages():
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
$translation = $entity->getTranslation($langcode);
entity_do_stuff($translation);
}
Er bestaan ook methodes om een vertaling toe te voegen, te verwijderen of te controleren of ze bestaat:
if (!$entity->hasTranslation('fr')) {
$translation = $entity->addTranslation('fr', array('field_foo' => 'bag'));
}
// Dit is gelijkwaardig aan de volgende code, hoewel bij een ongeldige taalcode
// een uitzondering wordt gegooid.
$translation = $entity->getTranslation('fr');
$translation->field_foo->value = 'bag';
// Toegang tot een veld van een verwijderde vertaling veroorzaakt een uitzondering.
$translation = $entity->getTranslation('it');
$entity->removeTranslation('it');
$value = $translation->field_foo->value; // gooit InvalidArgumentException
Wanneer entiteitsvertalingen worden toegevoegd aan of verwijderd uit opslag, worden respectievelijk de volgende hooks aangeroepen:
- hook_entity_translation_insert()
- hook_entity_translation_delete()
De taal van een veld kan nog steeds worden opgehaald via de juiste methode van het veldobject zelf:
$langcode = $translation->field_foo->getLangcode();