REST webservicesからノードをインポートするバッチがあります。私のアプリケーションには2つの言語、FRとEN(デフォルトはFR)があるため、FRでノードを作成しています、次に、他のすべての言語(現時点ではEN)をループして、次のようにします。
$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();
}
そして、それは500エラーでクラッシュし、レポートします:
- 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).
私は何日もこの問題を解決しており、エラーメッセージに$ langcodeが'und'
に対してvar_dump
この行が私を返す直前の'en'
。
編集:foreachをハードコードして削除しようとしました。 $ 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();
今回のエラーは次のとおりです。
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).
数日後、ようやく解決策を見つけました。明らかに、Drupal(ここでは8.4.0))のバグがあります。
hasTranslation()
メソッドが正しく機能しません。代わりに、 EntityManager :: getTranslationFromContext() を使用する必要があります(Drupal 9でも廃止予定です)。
次のような新しいメソッドを記述して置き換えることもできます。
/**
* 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;
}
したがって、私の修正したコードは次のとおりです。
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();
元の投稿のエラーは addTranslation() 自体に起因します。
_ 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}).");
}
_
したがって、関数has_translation()
を追加するソリューションは、addTranslation()
が行うのと同じチェックの一部を実行することになります。別の方法は例外をキャッチすることです:
_ try {
$node->addTranslation($langcode, $node->toArray());
}
catch (\InvalidArgumentException $e) {
// The translation already exists.
}
_
つまり、文字通りcatch
句:完全に省略するか、コメントを入力して、何かを忘れていないことを将来の自分に確信させることができます。
簡単なコードで試すことができます:
$node = Node::load(1);
if (!$node->hasTranslation('en')) {
$translation = $node->addTranslation('en', $node->toArray());
$node->save();
}
ターゲットを間違えただけでは翻訳できません。元の言語を知る必要があります。
コードは必要ありません。 Lingotek Module を使用し、新しいノードの保存または更新時に rules module でトリガーできます。条件:アップロードされている言語を確認して、別のノードを作成できるようにします。第二言語で。グーグルに注意してください、両方のノードにインデックスを付けるとペナルティが課せられます。これに対処するには、 インデックスモジュールなし または類似のものを使用できます。上記のすべてでサイトを作成し、完璧に動作します。