web-dev-qa-db-fra.com

Comment migrer des champs alt d'image multilingue à partir de CSV?

Je migre du contenu multilingue vers Drupal 8 à partir d'un groupe de fichiers CSV, et j'en suis à environ 95% du chemin. J'ai un champ d'image attaché à un type de contenu d'article qui partage l'image parmi toutes les traductions, mais l'attribut alt est traduisible. Le problème restant de 5% réside dans la configuration de la migration pour utiliser un seul fichier d'image commun fid pour toutes les langues, mais un texte alt différent pour autres langues.

articles.csv

id,title_en,title_fr,body_en,body_fr,image,alt_en,alt_fr
1,Title 1,Titre 1,<p>English Body paragraph text 1</p>,<p>French Body paragraph text 1</p>,image1.jpg,Alt text English 1,Alt text French 1
2,Title 2,Titre 2,<p>English Body paragraph text 2</p>,<p>French Body paragraph text 1</p>,image2.jpg,Alt text English 2,Alt text French 2
3,Title 3,Titre 3,<p>English Body paragraph text 3</p>,<p>French Body paragraph text 1</p>,image3.jpg,Alt text English 3,Alt text French 3

images.csv

image
image1.jpg
image2.jpg
image3.jpg

Migration du contenu anglais avec image et texte alternatif

Ma migration de contenu en anglais par défaut fonctionne très bien avec les images importées et attachées aux nœuds.

migrate_plus.migration.articles_images.yml

id: articles_images
status: true
dependencies:
  module:
    - file
migration_tags:
  - CSV
migration_group: default
label: Article Images
source:
  constants:
    source_base_path: ../import/images
    uri_file: 'public://images/imported'
  plugin: csv
  track_changes: true
  path: ../import/images.csv
  header_row_count: 1
  keys:
    - image
  column_names:
    -
      image: Image
process:
  source_full_path:
    -
      plugin: concat
      delimiter: /
      source:
        - constants/source_base_path
        - image
    -
      plugin: urlencode
  uri_file:
    -
      plugin: concat
      delimiter: /
      source:
        - constants/uri_file
        - image
    -
      plugin: urlencode
  filename:
    -
      plugin: skip_on_empty
      method: row
      source: image
    -
      plugin: get
      source: image
  uri:
    plugin: file_copy
    source:
      - '@source_full_path'
      - '@uri_file'
destination:
  plugin: 'entity:file'
migration_dependencies:
  required: {  }
  optional: {  }

migrate_plus.migration.articles_en.yml

id: articles_en
status: true
migration_tags:
  - CSV
migration_group: default
label: Articles
source:
  plugin: csv
  path: ../import/articles.csv
  header_row_count: 1
  keys:
    - id
  column_names:
    -
      id: Id
    -
      title_en: 'Title EN'
    -
      title_fr: 'Titre FR'
    -
      body_en: 'Text EN'
    -
      body_fr: 'Texte FR'
    -
      image: Image
    -
      alt_en: 'Alt Text EN'
    -
      alt_fr: 'Alt Text FR'
process:
  type:
    plugin: default_value
    default_value: article
  title: title_en
  body/value: body_en
  body/format:
    plugin: default_value
    default_value: basic_html
  field_image/target_id:
    -
      plugin: skip_on_empty
      method: process
      source: image
    - 
      plugin: migration
      migration: articles_images
      source: image
      no_stub: true
  field_image/alt:
    -
      plugin: skip_on_empty
      method: process
      source: image
    -
      plugin: skip_on_empty
      method: process
      source: alt_en
    -
      plugin: get
      source: alt_en
destination:
  plugin: 'entity:node'
migration_dependencies:
  optional:
    - articles_images

Traduction de contenu français avec un texte alternatif différent

Cependant, chaque configuration que j'essaie de faire utiliser les traductions en langue étrangère utilise le même FID mais un texte différent alt échoue.

migrate_plus.migration.articles_fr.yml

id: articles_fr
status: true
migration_tags:
  - CSV
migration_group: default
label: Articles French
source:
  plugin: csv
  path: ../import/articles.csv
  header_row_count: 1
  keys:
    - id
  column_names:
    -
      id: Id
    -
      title_en: 'Title EN'
    -
      title_fr: 'Titre FR'
    -
      body_en: 'Text EN'
    -
      body_fr: 'Texte FR'
    -
      image: Image
    -
      alt_en: 'Alt Text EN'
    -
      alt_fr: 'Alt Text FR'
process:
  type:
    plugin: default_value
    default_value: article
  nid:
    plugin: migration
    source: id
    migration: articles_en
  langcode:
    plugin: default_value
    default_value: fr
  title:
    -
      plugin: skip_on_empty
      method: row
      source: title_fr
    -
      plugin: get
      source: title_fr
      language: fr
  body/value:
    -
      plugin: skip_on_empty
      method: row
      source: body_fr
    -
      plugin: get
      source: body_fr
      language: fr
  body/format:
    plugin: default_value
    default_value: basic_html
  field_image/target_id:
    plugin: migration
    migration: articles_images
    source: image
    language: fr
  field_image/alt:
    -
      plugin: skip_on_empty
      method: process
      source: image
    -
      plugin: skip_on_empty
      method: process
      source: alt_fr
    -
      plugin: get
      source: alt_fr
      language: fr
destination:
  plugin: 'entity:node'
  translations: true
migration_dependencies:
  required:
    - articles_en
  optional: {  }

En exécutant la migration des données en français, je reçois un message d'erreur.

InvalidArgumentException: Invalid translation language (und) specified.
in Drupal\Core\Entity\ContentEntityBase->getTranslation() (line 745 of
web/core/lib/Drupal/Core/Entity/ContentEntityBase.php).
Invalid translation language (und) specified.
(web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:770)

Traduction de contenu français avec partage d'images de base

J'ai également essayé de traiter uniquement l'image field_image pour la copier dans les traductions étrangères, mais cela donne la même erreur:

field_image:
  plugin: migration
  migration: articles_images
  source: image
  no_stub: true

Ajout ou suppression de language: fr le paramètre de l'un des processeurs de terrain ne fait aucune différence - l'erreur est la même dans les deux cas.

La structure de données résultante prévue

Inspection d'un field_image attaché à un nœud qui a été créé et traduit manuellement via Drupal UI at node/X/devel montre la structure suivante:

[field_image] => array(
  [x-default] => array(
    [0] => array(
      [target_id] => 123
      [alt] => English Alt text
      [title] => 
      [width] => 480
      [height] => 360
    )
  )
  [fr] => array(
    [0] => array(
      [target_id] => 123
      [alt] => French alt text.
      [title] => 
      [width] => 480
      [height] => 360
    )
  )
)

Ressources additionnelles

Ces articles de blog et exemples de référentiels ont été utiles à l'approche de l'endroit où je suis actuellement bloqué:

6
JamesWilson

Je pense que j'ai compris cela. Vous devez définir la propriété 'content_translation_source' sur le nœud traduit, afin que Drupal sache de quelle langue il provient.

Par exemple:

migrate_plus.migration.articles_fr.yml

process:
  #...
  content_translation_source:
    plugin: default_value
    default_value: en
  #...

(Assurez-vous de substituer la valeur en à la langue que vous avez importée pour la première fois - l'exemple de l'OP utilise l'anglais, mais cela peut être n'importe quoi).


On m'a demandé comment j'ai compris cela:

Je suis le gars qui a obtenu des migrations multilingues dans le noyau D8, donc je connais un peu la question :)

Dans ce cas, j'ai utilisé xdebug et mis un point d'arrêt où l'exception a été levée (ContentEntityBase.php ligne 745). Il semblait étrange d'utiliser "und" comme langcode, plutôt que "en" - j'ai donc recherché la pile d'appels pour voir d'où cela venait. Il s'agit de content_translation_entity_presave (), qui s'exécute:

$ source_langcode =! $ entity-> original-> hasTranslation ($ langcode)? $ manager-> getTranslationMetadata ($ entity) -> getSource (): NULL;

Dans ce cas, $manager->getTranslationMetadata($entity)->getSource() est fondamentalement équivalent à $entity->content_translation_source->value.

Je me demandais, pourquoi cela donnerait-il "und"? J'ai vérifié ce qui se passe lorsque je traduis une entité dans le navigateur, et dans ce cas, cela me donne "en". Quelque chose doit définir la langue source! En effet, ContentTranslationHandler :: entityFormEntityBuild () appelle setSource () lorsque nous traduisons dans le navigateur.

Donc, j'ai pensé que je reproduirais simplement ce comportement dans la migration, en définissant content_translation_source dans le processus. Cela explique également pourquoi la migration D6 -> D8 des traductions fonctionne, car d6_node_translation.yml a content_translation_source dans le processus.

7
vasi

Merci @vasi, ceux qui sont toujours confrontés au problème peuvent mettre à jour le script de traduction comme:

process:
  content_translation_source: source_langcode

où code_source correspond aux nœuds par défaut code_langue

0
Subhash