J'ai un lot dans lequel j'importe des nœuds à partir de REST webservices. Mon application a deux langues, FR et EN (la valeur par défaut est FR). Donc, je crée le nœud en FR, ensuite, je passe en revue toutes les autres langues (juste EN pour l'instant) et j'essaye de faire comme suit:
$languages = \Drupal::languageManager()->getLanguages();
unset($languages['fr']);
foreach ($languages AS $langcode => $language) {
if ($node->hasTranslation($langcode)) {
$node_translation = $node->getTranslation($langcode);
} else {
$node_translation = $node->addTranslation($langcode, $node->toArray());
}
$node_translation->status = 1;
$node_translation->title = 'title en';
$node_translation->subtitle = 'subtitle en';
$node_translation->save();
}
Et il se bloque avec une erreur 500, signalant:
- Drupal\Core\Entity\EntityStorageException : Invalid translation language (und) specified. dans Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (ligne 805 de /.../web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).
- InvalidArgumentException : Invalid translation language (und) specified. dans Drupal\Core\Entity\ContentEntityBase->getTranslation() (ligne 783 de /.../web/core/lib/Drupal/Core/Entity/ContentEntityBase.php).
Je m'arrache les cheveux sur ce problème depuis des jours et je ne comprends pas pourquoi le message d'erreur me dit que $ langcode est égal à 'und'
alors qu'un var_dump
juste avant que cette ligne ne me renvoie 'en'
.
Edit: J'ai essayé de coder en dur et de supprimer le foreach. Donc juste après $ node-> save ():
$node_translation = $node->addTranslation('en', $node->toArray());
$node_translation->set('title', 'title en');
$node_translation->set('field_sub_title', 'subtitle en');
$node_translation->save();
Cette fois, l'erreur est la suivante:
InvalidArgumentException : Invalid translation language (en) specified.
dans Drupal\Core\Entity\ContentEntityBase->addTranslation() (ligne 863
de /var/www/drupalvm/drupal/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php).
Après plusieurs jours, j'ai finalement trouvé la solution. Évidemment, il y a un bug avec Drupal (ici 8.4.0)).
La méthode hasTranslation()
ne fonctionne pas correctement. Au lieu de cela, vous devez utiliser EntityManager :: getTranslationFromContext () (sera déprécié dans Drupal 9 cependant).
Vous pouvez également écrire une nouvelle méthode comme celle-ci pour la remplacer:
/**
* Check if a node as a translation for the given language.
*
* @param object $node
* The node object.
* @param string $langcode
* The langcode.
*
* @return bool
* True (exists) or false (does not exist).
*/
function has_translation($node, $langcode) {
$existing_translation = \Drupal::service('entity.repository')->getTranslationFromContext($node, $langcode);
return ($existing_translation->langcode->value === $langcode) ? TRUE : FALSE;
}
Donc, mon code corrigé est le suivant:
if (has_translation($node, $langcode)) {
$node_translation = $node->getTranslation($langcode);
$node_translation->title = 'title en';
$node_translation->field_sub_title = 'subtitle en';
$node_translation->status = NodeInterface::PUBLISHED;
}
else {
$node->addTranslation($langcode, $values);
}
$node->save();
L'erreur dans le message d'origine vient de addTranslation () lui-même:
if (!isset($this->languages[$langcode]) || $this
->hasTranslation($langcode) || $this->languages[$langcode]
->isLocked()) {
throw new \InvalidArgumentException("Invalid translation language ({$langcode}) specified.");
}
if ($this->languages[$this->defaultLangcode]
->isLocked()) {
throw new \InvalidArgumentException("The entity cannot be translated since it is language neutral ({$this->defaultLangcode}).");
}
Ainsi, votre solution, en ajoutant la fonction has_translation()
, revient à faire certaines des mêmes vérifications que addTranslation()
fera. Une alternative est d'attraper l'exception:
try {
$node->addTranslation($langcode, $node->toArray());
}
catch (\InvalidArgumentException $e) {
// The translation already exists.
}
Je veux dire cette clause catch
littéralement: vous pouvez la laisser entièrement ou simplement mettre un commentaire pour rassurer votre futur vous-même que vous n'avez pas oublié quelque chose.
Vous pouvez essayer avec du code simple:
$node = Node::load(1);
if (!$node->hasTranslation('en')) {
$translation = $node->addTranslation('en', $node->toArray());
$node->save();
}
Vous ne pouvez pas traduire simplement parce que vous vous trompez de cible. Vous devez connaître la langue d'origine.
Aucun code nécessaire, vous pouvez utiliser Module Lingotek et déclencher par module rules lors de la sauvegarde et/ou de la mise à jour du nouveau nœud, condition: vérifiez la langue qui est téléchargée pour pouvoir créer un autre nœud dans la deuxième langue. soyez prudent avec google, cela vous pénalisera si vous indexez les deux nœuds, pour vous en occuper vous pouvez utiliser pas de module d'index ou quelque chose de similaire. J'ai fait un site avec tout ce qui précède et fonctionne parfaitement.