I'm migrating multilingual content to Drupal 8 from a group of CSV files, and I'm about 95% of the way there. I have an image field attached to an article content type that shares the image among all translations, but the alt attribute is translatable. The remaining 5% problem is in configuring the migration to use a single common image file fid
for all languages but a different alt
text for other languages.
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
English Content Migration w/ Image & Alt text
My default English content migration works great with images being imported and attached to nodes.
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
French Content Translation w/ different alt text
However, every configuration I try to make the foreign language translations use the same FID but a different alt text fails.
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: { }
Running the French data migration, I get an error message.
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)
French Content Translation w/ basic image sharing
I've also tried processing just the field_image to copy over to the the foreign translations, but it gives the same error:
field_image:
plugin: migration
migration: articles_images
source: image
no_stub: true
Adding or leaving off the language: fr
parameter from any of the field processors seems to make no difference -- the error is the same either way.
The intended resulting data structure
Inspecting a field_image
attached to a node that was created and translated manually through Drupal UI at node/X/devel
shows the following structure:
[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
)
)
)
Additional Resources
These blog posts and example repositories have been helpful in the lead up to where I'm currently stuck:
- https://www.mtech-llc.com/blog/lucas-hedding/migrating-using-csv
- https://www.mtech-llc.com/blog/ada-hernandez/how-migrate-images-drupal-8-using-csv-source
- https://github.com/heddn/d8_custom_migrate
- https://github.com/wunderkraut/migrate_source_example/tree/8.2.x/modules/migrate_source_example_csv
- https://blog.liip.ch/archive/2017/01/05/drupal-8-multilingual-content.html
- https://drupal.stackexchange.com/a/220424/3167
- https://www.drupal.org/node/2733431
- https://www.drupal.org/node/2677202
migration: article_images
looks like a typo. That should bemigration: articles_images
, right?