In Drupal 8 there is only one unified way of translating content to different languages. However, in Drupal 7, there were two different ways to do it:
- Using core's Content Translation module: this will create separate nodes per language.
- Using the contributed Entity Translation module: this maintains a single node and the translation happens at a field level.
However, that was a while ago, and there are updated ways to do proceed with entity translation migration. We'll go over those updated methods in this article.
Before We Start
- If you are new to migrations in Drupal 8, you may want to read about migrating basic data to Drupal 8 first.
- You can follow the sample code for this tutorial: Migrate example: Entity Translation module on GitHub.
- You need to have migrate_tools and migrate_plus modules to follow this tutorial.
- You need to have Drush installed to run migrations as described in this article.
Our imaginary client has provided a database dump for their Drupal 7 site containing some nodes. These nodes might have translations in English, Spanish and French, but there could also be some non-translatable nodes. We need to migrate those nodes to Drupal 8 while preserving the translations.
Setting up the Migration
Create the migration module
We need to create a module for our migrations. In this example, we're naming it
We then need to add the following modules as dependencies in the module declaration:
Create a migration group
To group the migrations, we also need to create a migration group. To do so, we’ll create a fairly simple configuration file so that the group gets created when the module is installed. The file’s contents should be as follows:
id: entity_translation label: Entity Translation Group source_type: Drupal 7 shared_configuration: source: key: migrate_d7
Define a new database connection
Next, you need to load the Drupal 7 database into your Drupal 8 installation. To do so, you need to define a new database connection in your settings.php file like this:
$databases['migrate_d7']['default'] = array( 'driver' => 'mysql', 'database' => 'migrate_d7', 'username' => 'user', 'password' => 'password', 'host' => 'db', 'prefix' => '', );
And then you can import the database dump into this new database connection using your preferred method.
Writing the Migrations
Next thing to do is to write the actual migrations. Per our requirements, we need to write two different migrations: one for the base nodes and one for the translations.
Since Drupal 8.1.x, migrations are plugins that should be stored in a migrations folder inside any module. You can still make them configuration entities as part of the migrate_plus module but I personally prefer to follow the core recommendation because it's easier to develop (you can make an edit and just rebuild cache to update it).
Write the base nodes migration
The first migration to write is the base nodes migration. This will be just a simple migration without anything special related to entity translation.
The full migration file will look like this:
id: example_creature_base label: Creature base data migration_group: entity_translation migration_tags: - node - Drupal 7 source: plugin: d7_node node_type: article destination: plugin: entity:node process: type: plugin: default_value default_value: article title: title status: status langcode: language created: created changed: changed promote: promote sticky: sticky revision_log: log field_one_liner: field_one_liner body/value: body/value body/format: plugin: default_value default_value: full_html
Write the translations migration
Now we should write the translations migration. We start by creating the migration file. In this case, we'll name it example_creature_translations.yml. The source section of this migration will look like this:
source: plugin: d7_node_entity_translation node_type: article
In the plugin, we're using d7_node_entity_translation; this is a plugin already included in core to handle this type of migration.
The destination for this plugin will be pretty similar to the destination for the base migration. It will look like this:
destination: plugin: entity:node translations: true destination_module: content_translation
Now it's time to write the process section for this migration. It will be pretty similar to the base migration. You only need to keep in mind that you need to migrate two new properties: content_translation_source and content_translation_outdated. So, your process section will look like this:
process: nid: plugin: migration_lookup migration: example_creature_base source: entity_id type: plugin: default_value default_value: article title: title status: status langcode: language created: created changed: changed promote: promote sticky: sticky revision_log: log field_one_liner: field_one_liner body/value: body/value body/format: plugin: default_value default_value: full_html content_translation_source: source content_translation_outdated: translate
Finally you can setup migration dependencies to ensure your migrations run in the right order:
migration_dependencies: required: - example_creature_base
You can look at the full migration file in the code samples repo.
Running the Migrations
Since we have set dependencies, we can instruct Drupal to run the migration group and it will run the migrations in the right order.
To do so, execute
drush mim --group=entity_translation and the output will look like this:
[notice] Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_base' [notice] Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_translations'
You can also run
drush ms to see current migration status:
--------------------- ----------------------------------- -------- ------- ---------- ------------- --------------------- Group Migration ID Status Total Imported Unprocessed Last Imported --------------------- ----------------------------------- -------- ------- ---------- ------------- --------------------- Entity Translation example_creature_base Idle 9 9 0 2020-11-09 15:54:06 Entity Translation example_creature_tran Idle 9 9 0 2020-11-09 15:54:07