diff --git a/core/composer.json b/core/composer.json
index a2d59b6a77..a5ba5ec8b0 100644
--- a/core/composer.json
+++ b/core/composer.json
@@ -137,6 +137,7 @@
         "drupal/menu_ui": "self.version",
         "drupal/migrate": "self.version",
         "drupal/migrate_drupal": "self.version",
+        "drupal/migrate_drupal_multilingual": "self.version",
         "drupal/migrate_drupal_ui": "self.version",
         "drupal/node": "self.version",
         "drupal/options": "self.version",
diff --git a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php
index e9f1e87ef4..d087060a28 100644
--- a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php
+++ b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockContentTranslationTest.php
@@ -26,6 +26,7 @@ class MigrateBlockContentTranslationTest extends MigrateDrupal6TestBase {
     'language',
     'statistics',
     'taxonomy',
+    'migrate_drupal_multilingual',
   ];
 
   /**
diff --git a/core/modules/block_content/tests/src/Kernel/Migrate/d6/MigrateCustomBlockContentTranslationTest.php b/core/modules/block_content/tests/src/Kernel/Migrate/d6/MigrateCustomBlockContentTranslationTest.php
index 5ff40526a6..bee3633251 100644
--- a/core/modules/block_content/tests/src/Kernel/Migrate/d6/MigrateCustomBlockContentTranslationTest.php
+++ b/core/modules/block_content/tests/src/Kernel/Migrate/d6/MigrateCustomBlockContentTranslationTest.php
@@ -19,6 +19,7 @@ class MigrateCustomBlockContentTranslationTest extends MigrateDrupal6TestBase {
     'block_content',
     'content_translation',
     'language',
+    'migrate_drupal_multilingual',
   ];
 
   /**
diff --git a/core/modules/config_translation/migrations/d6_system_maintenance_translation.yml b/core/modules/config_translation/migrations/d6_system_maintenance_translation.yml
index b370914f79..5a3593c27e 100644
--- a/core/modules/config_translation/migrations/d6_system_maintenance_translation.yml
+++ b/core/modules/config_translation/migrations/d6_system_maintenance_translation.yml
@@ -3,6 +3,7 @@ label: Maintenance page configuration
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: variable_translation
   variables:
diff --git a/core/modules/config_translation/migrations/d6_system_site_translation.yml b/core/modules/config_translation/migrations/d6_system_site_translation.yml
index 066038338a..a246aa97d3 100644
--- a/core/modules/config_translation/migrations/d6_system_site_translation.yml
+++ b/core/modules/config_translation/migrations/d6_system_site_translation.yml
@@ -3,6 +3,7 @@ label: Site configuration
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: variable_translation
   constants:
diff --git a/core/modules/config_translation/migrations/d6_user_mail_translation.yml b/core/modules/config_translation/migrations/d6_user_mail_translation.yml
index 801f5678d1..2fb3429e6f 100644
--- a/core/modules/config_translation/migrations/d6_user_mail_translation.yml
+++ b/core/modules/config_translation/migrations/d6_user_mail_translation.yml
@@ -3,6 +3,7 @@ label: User mail configuration
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: variable_translation
   variables:
diff --git a/core/modules/config_translation/migrations/d6_user_profile_field_instance_translation.yml b/core/modules/config_translation/migrations/d6_user_profile_field_instance_translation.yml
index 0f728f6658..b8a88f43f6 100644
--- a/core/modules/config_translation/migrations/d6_user_profile_field_instance_translation.yml
+++ b/core/modules/config_translation/migrations/d6_user_profile_field_instance_translation.yml
@@ -3,6 +3,7 @@ label: User profile field instance configuration
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: d6_profile_field_translation
   constants:
diff --git a/core/modules/config_translation/migrations/d6_user_settings_translation.yml b/core/modules/config_translation/migrations/d6_user_settings_translation.yml
index 05ecb15939..f947ff9276 100644
--- a/core/modules/config_translation/migrations/d6_user_settings_translation.yml
+++ b/core/modules/config_translation/migrations/d6_user_settings_translation.yml
@@ -3,6 +3,7 @@ label: User configuration
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: variable_translation
   variables:
diff --git a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemMaintenanceTranslationTest.php b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemMaintenanceTranslationTest.php
index 37cd4a9ec2..f67ba87dda 100644
--- a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemMaintenanceTranslationTest.php
+++ b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemMaintenanceTranslationTest.php
@@ -12,7 +12,11 @@
  */
 class MigrateSystemMaintenanceTranslationTest extends MigrateDrupal6TestBase {
 
-  public static $modules = ['language', 'config_translation'];
+  public static $modules = [
+    'language',
+    'config_translation',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemSiteTranslationTest.php b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemSiteTranslationTest.php
index 326e1bb7e4..5e84616eb6 100644
--- a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemSiteTranslationTest.php
+++ b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateSystemSiteTranslationTest.php
@@ -12,7 +12,11 @@
  */
 class MigrateSystemSiteTranslationTest extends MigrateDrupal6TestBase {
 
-  public static $modules = ['language', 'config_translation'];
+  public static $modules = [
+    'language',
+    'config_translation',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserConfigsTranslationTest.php b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserConfigsTranslationTest.php
index bc622e1b6a..c7a065091e 100644
--- a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserConfigsTranslationTest.php
+++ b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserConfigsTranslationTest.php
@@ -15,7 +15,12 @@ class MigrateUserConfigsTranslationTest extends MigrateDrupal6TestBase {
 
   use SchemaCheckTestTrait;
 
-  public static $modules = ['language', 'locale', 'config_translation'];
+  public static $modules = [
+    'language',
+    'locale',
+    'config_translation',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserProfileFieldInstanceTranslationTest.php b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserProfileFieldInstanceTranslationTest.php
index c941e41282..cd53f44ef9 100644
--- a/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserProfileFieldInstanceTranslationTest.php
+++ b/core/modules/config_translation/tests/src/Kernel/Migrate/d6/MigrateUserProfileFieldInstanceTranslationTest.php
@@ -15,7 +15,13 @@ class MigrateUserProfileFieldInstanceTranslationTest extends MigrateDrupal6TestB
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['config_translation', 'locale', 'language', 'field'];
+  public static $modules = [
+    'config_translation',
+    'locale',
+    'language',
+    'field',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * Tests migration of translated user profile fields.
diff --git a/core/modules/content_translation/migrations/d6_block_translation.yml b/core/modules/content_translation/migrations/d6_block_translation.yml
index 3f8810cbfa..a27fcfd9e5 100644
--- a/core/modules/content_translation/migrations/d6_block_translation.yml
+++ b/core/modules/content_translation/migrations/d6_block_translation.yml
@@ -3,6 +3,7 @@ label: Block translations
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: d6_block_translation
   constants:
diff --git a/core/modules/content_translation/migrations/d6_custom_block_translation.yml b/core/modules/content_translation/migrations/d6_custom_block_translation.yml
index 7a6d3685b8..a240667b94 100644
--- a/core/modules/content_translation/migrations/d6_custom_block_translation.yml
+++ b/core/modules/content_translation/migrations/d6_custom_block_translation.yml
@@ -3,6 +3,7 @@ label: Custom block translations
 migration_tags:
   - Drupal 6
   - Content
+  - Multilingual
 source:
   plugin: d6_box_translation
 process:
diff --git a/core/modules/content_translation/migrations/d6_menu_links_translation.yml b/core/modules/content_translation/migrations/d6_menu_links_translation.yml
index 71e55992e8..34e4290235 100644
--- a/core/modules/content_translation/migrations/d6_menu_links_translation.yml
+++ b/core/modules/content_translation/migrations/d6_menu_links_translation.yml
@@ -3,6 +3,7 @@ label: Menu links
 migration_tags:
   - Drupal 6
   - Content
+  - Multilingual
 source:
   plugin: d6_menu_link_translation
 process:
diff --git a/core/modules/content_translation/migrations/d6_taxonomy_term_translation.yml b/core/modules/content_translation/migrations/d6_taxonomy_term_translation.yml
index 0b42dcfdb9..96ccd8d569 100644
--- a/core/modules/content_translation/migrations/d6_taxonomy_term_translation.yml
+++ b/core/modules/content_translation/migrations/d6_taxonomy_term_translation.yml
@@ -3,6 +3,7 @@ label: Taxonomy terms
 migration_tags:
   - Drupal 6
   - Content
+  - Multilingual
 source:
   plugin: d6_taxonomy_term
   translations: true
@@ -34,6 +35,7 @@ process:
   changed: timestamp
 destination:
   plugin: entity:taxonomy_term
+  destination_module: content_translation
 migration_dependencies:
   required:
     - d6_taxonomy_vocabulary
diff --git a/core/modules/content_translation/migrations/d7_entity_translation_settings.yml b/core/modules/content_translation/migrations/d7_entity_translation_settings.yml
index 1a8e526c3c..bd82446339 100644
--- a/core/modules/content_translation/migrations/d7_entity_translation_settings.yml
+++ b/core/modules/content_translation/migrations/d7_entity_translation_settings.yml
@@ -3,6 +3,7 @@ label: Drupal 7 Entity Translation settings
 migration_tags:
   - Drupal 7
   - Configuration
+  - Multilingual
 source:
   plugin: d7_entity_translation_settings
 process:
diff --git a/core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php b/core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php
index 1674cfa5b7..27e83ea504 100644
--- a/core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php
+++ b/core/modules/content_translation/tests/src/Kernel/Migrate/d6/MigrateTaxonomyTermTranslationTest.php
@@ -20,6 +20,7 @@ class MigrateTaxonomyTermTranslationTest extends MigrateDrupal6TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'taxonomy',
   ];
diff --git a/core/modules/content_translation/tests/src/Kernel/Migrate/d7/MigrateEntityTranslationSettingsTest.php b/core/modules/content_translation/tests/src/Kernel/Migrate/d7/MigrateEntityTranslationSettingsTest.php
index 5fb6ddde60..10e22bd3ff 100644
--- a/core/modules/content_translation/tests/src/Kernel/Migrate/d7/MigrateEntityTranslationSettingsTest.php
+++ b/core/modules/content_translation/tests/src/Kernel/Migrate/d7/MigrateEntityTranslationSettingsTest.php
@@ -20,6 +20,7 @@ class MigrateEntityTranslationSettingsTest extends MigrateDrupal7TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'taxonomy',
     'text',
diff --git a/core/modules/menu_link_content/migrations/node_translation_menu_links.yml b/core/modules/menu_link_content/migrations/node_translation_menu_links.yml
index 4028c7a3f6..837a99b47a 100644
--- a/core/modules/menu_link_content/migrations/node_translation_menu_links.yml
+++ b/core/modules/menu_link_content/migrations/node_translation_menu_links.yml
@@ -5,6 +5,7 @@ migration_tags:
   - Drupal 6
   - Drupal 7
   - Content
+  - Multilingual
 source:
   plugin: menu_link
   constants:
diff --git a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTest.php b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTest.php
index 36e4f30dc0..2c920bbdce 100644
--- a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTest.php
+++ b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTest.php
@@ -20,6 +20,7 @@ class MigrateMenuLinkTest extends MigrateNodeTestBase {
     'content_translation',
     'language',
     'menu_link_content',
+    'migrate_drupal_multilingual',
     'menu_ui',
   ];
 
diff --git a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTranslationTest.php b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTranslationTest.php
index 4863dde76f..d590018749 100644
--- a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTranslationTest.php
+++ b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d6/MigrateMenuLinkTranslationTest.php
@@ -20,6 +20,7 @@ class MigrateMenuLinkTranslationTest extends MigrateDrupal6TestBase {
     'menu_link_content',
     'language',
     'content_translation',
+    'migrate_drupal_multilingual',
   ];
 
   /**
diff --git a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
index ab21f2c611..219122fb3f 100644
--- a/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
+++ b/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
@@ -24,6 +24,7 @@ class MigrateMenuLinkTest extends MigrateDrupal7TestBase {
     'link',
     'menu_ui',
     'menu_link_content',
+    'migrate_drupal_multilingual',
     'node',
     'text',
   ];
diff --git a/core/modules/migrate_drupal/migrate_drupal.install b/core/modules/migrate_drupal/migrate_drupal.install
index ed60201f7e..820bcdc870 100644
--- a/core/modules/migrate_drupal/migrate_drupal.install
+++ b/core/modules/migrate_drupal/migrate_drupal.install
@@ -24,3 +24,10 @@ function migrate_drupal_update_8502() {
     ->set('follow_up_migration_tags', ['Follow-up migration'])
     ->save();
 }
+
+/**
+ * Install migrate_drupal_multilingual since migrate_drupal is installed.
+ */
+function migrate_drupal_update_8601() {
+  \Drupal::service('module_installer')->install(['migrate_drupal_multilingual']);
+}
diff --git a/core/modules/migrate_drupal/migrations/d6_entity_reference_translation.yml b/core/modules/migrate_drupal/migrations/d6_entity_reference_translation.yml
index 3188820739..74a586b823 100644
--- a/core/modules/migrate_drupal/migrations/d6_entity_reference_translation.yml
+++ b/core/modules/migrate_drupal/migrations/d6_entity_reference_translation.yml
@@ -2,6 +2,7 @@ id: d6_entity_reference_translation
 label: Entity reference translations
 migration_tags:
   - Drupal 6
+  - Multilingual
   - Follow-up migration
 deriver: Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver
 # Supported target types for entity reference translation migrations. The array
diff --git a/core/modules/migrate_drupal/migrations/d7_entity_reference_translation.yml b/core/modules/migrate_drupal/migrations/d7_entity_reference_translation.yml
index 7e59a9a0c7..af5bef9490 100644
--- a/core/modules/migrate_drupal/migrations/d7_entity_reference_translation.yml
+++ b/core/modules/migrate_drupal/migrations/d7_entity_reference_translation.yml
@@ -2,6 +2,7 @@ id: d7_entity_reference_translation
 label: Entity reference translations
 migration_tags:
   - Drupal 7
+  - Multilingual
   - Follow-up migration
 deriver: Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver
 # Supported target types for entity reference translation migrations. The array
diff --git a/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php b/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php
index 0aca5be244..10c113aeb8 100644
--- a/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php
+++ b/core/modules/migrate_drupal/src/MigrationConfigurationTrait.php
@@ -110,6 +110,12 @@ protected function getMigrations($database_state_key, $drupal_version) {
       if (!empty(array_intersect($migration->getMigrationTags(), $this->getFollowUpMigrationTags()))) {
         continue;
       }
+      // Multilingual migrations require migrate_drupal_multilingual.
+      $tags = $migration->getMigrationTags() ?: [];
+      if (in_array('Multilingual', $tags, TRUE) && (!\Drupal::service('module_handler')->moduleExists('migrate_drupal_multilingual'))) {
+        throw new RequirementsException("The module migrate_drupal_multilingual is not enabled on the new site.");
+      }
+
       try {
         // @todo https://drupal.org/node/2681867 We should be able to validate
         //   the entire migration at this point.
diff --git a/core/modules/migrate_drupal/tests/src/Kernel/d6/FollowUpMigrationsTest.php b/core/modules/migrate_drupal/tests/src/Kernel/d6/FollowUpMigrationsTest.php
index e02254a5e5..46fc15f351 100644
--- a/core/modules/migrate_drupal/tests/src/Kernel/d6/FollowUpMigrationsTest.php
+++ b/core/modules/migrate_drupal/tests/src/Kernel/d6/FollowUpMigrationsTest.php
@@ -19,6 +19,7 @@ class FollowUpMigrationsTest extends MigrateNodeTestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
   ];
 
   /**
diff --git a/core/modules/migrate_drupal/tests/src/Kernel/d7/FollowUpMigrationsTest.php b/core/modules/migrate_drupal/tests/src/Kernel/d7/FollowUpMigrationsTest.php
index b9b38c2f73..a36db17510 100644
--- a/core/modules/migrate_drupal/tests/src/Kernel/d7/FollowUpMigrationsTest.php
+++ b/core/modules/migrate_drupal/tests/src/Kernel/d7/FollowUpMigrationsTest.php
@@ -26,6 +26,7 @@ class FollowUpMigrationsTest extends MigrateDrupal7TestBase {
     'language',
     'link',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'taxonomy',
     'telephone',
diff --git a/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.info.yml b/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.info.yml
new file mode 100644
index 0000000000..75a79dc285
--- /dev/null
+++ b/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.info.yml
@@ -0,0 +1,7 @@
+name: 'Migrate Drupal Multilingual'
+type: module
+description: 'Provides a requirement for multilingual migrations.'
+package: 'Core (Experimental)'
+core: 8.x
+dependencies:
+  - migrate_drupal
diff --git a/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.module b/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.module
new file mode 100644
index 0000000000..490bdbb7ce
--- /dev/null
+++ b/core/modules/migrate_drupal_multilingual/migrate_drupal_multilingual.module
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Provides a requirement for multilingual content and configuration migrations.
+ */
+
+use Drupal\Core\Routing\RouteMatchInterface;
+
+/**
+ * Implements hook_help().
+ */
+function migrate_drupal_multilingual_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.migrate_drupal_multilingual':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Migrate Drupal i18n module is a requirement for migrating translations. It does not provide a user interface. For more information, see the <a href=":migrate_drupal_multilingual">online documentation for the Migrate Drupal Multilingual module</a>.', [':migrate_drupal_multilingual' => 'https://www.drupal.org/docs/8/core/modules/experimental-migrate-drupal-i18n']) . '</p>';
+      return $output;
+  }
+}
diff --git a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php
index 403ef351f3..37117fc02c 100644
--- a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php
+++ b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php
@@ -81,7 +81,6 @@ class ReviewForm extends MigrateUpgradeFormBase {
       'fieldgroup',
       'filefield_meta',
       'help',
-      'i18n',
       'i18nstrings',
       'imageapi',
       'imageapi_gd',
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nReviewPageTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nReviewPageTest.php
index b70fe436aa..a4deaa25cf 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nReviewPageTest.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nReviewPageTest.php
@@ -59,7 +59,6 @@ protected function getAvailablePaths() {
       'filefield',
       'filter',
       'forum',
-      'i18ntaxonomy',
       'imagecache',
       'imagefield',
       'language',
@@ -103,7 +102,6 @@ protected function getAvailablePaths() {
       'fieldgroup',
       'filefield_meta',
       'help',
-      'i18n',
       'i18nstrings',
       'imageapi',
       'imageapi_gd',
@@ -135,6 +133,7 @@ protected function getMissingPaths() {
       'devel',
       'devel_generate',
       'devel_node_access',
+      'i18n',
       'i18nblocks',
       'i18ncck',
       'i18ncontent',
@@ -142,6 +141,7 @@ protected function getMissingPaths() {
       'i18npoll',
       'i18nprofile',
       'i18nsync',
+      'i18ntaxonomy',
       'i18nviews',
       'phone',
       'views',
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nTest.php
new file mode 100644
index 0000000000..dbea5df07f
--- /dev/null
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6I18nTest.php
@@ -0,0 +1,354 @@
+<?php
+
+namespace Drupal\Tests\migrate_drupal_ui\Functional\d6;
+
+use Drupal\node\Entity\Node;
+use Drupal\Tests\migrate_drupal_ui\Functional\MigrateUpgradeExecuteTestBase;
+use Drupal\user\Entity\User;
+use Drupal\Tests\WebAssert;
+
+/**
+ * Tests Drupal 6 upgrade via the UI without translations.
+ *
+ * The test method is provided by the MigrateUpgradeTestBase class.
+ *
+ * @group migrate_drupal_ui
+ */
+class MigrateUpgrade6I18nTest extends MigrateUpgradeExecuteTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'language',
+    'migrate_drupal_ui',
+    'telephone',
+    'aggregator',
+    'book',
+    'forum',
+    'statistics',
+    'migration_provider_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->loadFixture(drupal_get_path('module', 'migrate_drupal') . '/tests/fixtures/drupal6.php');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSourceBasePath() {
+    return __DIR__ . '/files';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCounts() {
+    return [
+      'aggregator_item' => 1,
+      'aggregator_feed' => 2,
+      'block' => 35,
+      'block_content' => 2,
+      'block_content_type' => 1,
+      'comment' => 6,
+      // The 'standard' profile provides the 'comment' comment type, and the
+      // migration creates 12 comment types, one per node type.
+      'comment_type' => 13,
+      'contact_form' => 5,
+      'configurable_language' => 5,
+      'editor' => 2,
+      'field_config' => 89,
+      'field_storage_config' => 63,
+      'file' => 8,
+      'filter_format' => 7,
+      'image_style' => 5,
+      'language_content_settings' => 3,
+      'migration' => 105,
+      'node' => 17,
+      // The 'book' module provides the 'book' node type, and the migration
+      // creates 12 node types.
+      'node_type' => 13,
+      'rdf_mapping' => 7,
+      'search_page' => 2,
+      'shortcut' => 2,
+      'shortcut_set' => 1,
+      'action' => 23,
+      'menu' => 8,
+      'taxonomy_term' => 8,
+      'taxonomy_vocabulary' => 7,
+      'tour' => 4,
+      'user' => 7,
+      'user_role' => 6,
+      'menu_link_content' => 8,
+      'view' => 16,
+      'date_format' => 11,
+      'entity_form_display' => 29,
+      'entity_form_mode' => 1,
+      'entity_view_display' => 55,
+      'entity_view_mode' => 14,
+      'base_field_override' => 38,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCountsIncremental() {
+    $counts = $this->getEntityCounts();
+    $counts['block_content'] = 3;
+    $counts['comment'] = 7;
+    $counts['file'] = 9;
+    $counts['menu_link_content'] = 9;
+    $counts['node'] = 18;
+    $counts['taxonomy_term'] = 9;
+    $counts['user'] = 8;
+    $counts['view'] = 16;
+    return $counts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getAvailablePaths() {
+    return [
+      'aggregator',
+      'block',
+      'book',
+      'comment',
+      'contact',
+      'content',
+      'date',
+      'dblog',
+      'email',
+      'filefield',
+      'filter',
+      'forum',
+      'imagecache',
+      'imagefield',
+      'language',
+      'link',
+      'locale',
+      'menu',
+      'node',
+      'nodereference',
+      'optionwidgets',
+      'path',
+      'profile',
+      'search',
+      'statistics',
+      'system',
+      'taxonomy',
+      'text',
+      'upload',
+      'user',
+      'userreference',
+      // Include modules that do not have an upgrade path and are enabled in the
+      // source database, defined in the $noUpgradePath property
+      // in MigrateUpgradeForm.
+      'date_api',
+      'date_timezone',
+      'event',
+      'i18nstrings',
+      'imageapi',
+      'number',
+      'php',
+      'profile',
+      'variable_admin',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getMissingPaths() {
+    return [
+      'i18n',
+      'i18nblocks',
+      'i18ncck',
+      'i18ncontent',
+      'i18nmenu',
+      'i18nprofile',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testMigrateUpgradeExecute() {
+    $connection_options = $this->sourceDatabase->getConnectionOptions();
+    $this->drupalGet('/upgrade');
+    $session = $this->assertSession();
+    $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');
+
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
+    $session->fieldExists('mysql[host]');
+
+    $driver = $connection_options['driver'];
+    $connection_options['prefix'] = $connection_options['prefix']['default'];
+
+    // Use the driver connection form to get the correct options out of the
+    // database settings. This supports all of the databases we test against.
+    $drivers = drupal_get_database_types();
+    $form = $drivers[$driver]->getFormOptions($connection_options);
+    $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
+    $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
+    $edit = [
+      $driver => $connection_options,
+      'source_private_file_path' => $this->getSourceBasePath(),
+      'version' => $version,
+    ];
+    if ($version == 6) {
+      $edit['d6_source_base_path'] = $this->getSourceBasePath();
+    }
+    else {
+      $edit['source_base_path'] = $this->getSourceBasePath();
+    }
+    if (count($drivers) !== 1) {
+      $edit['driver'] = $driver;
+    }
+    $edits = $this->translatePostValues($edit);
+
+    // Ensure submitting the form with invalid database credentials gives us a
+    // nice warning.
+    $this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
+    $session->pageTextContains('Resolve all issues below to continue the upgrade.');
+
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    // Ensure we get errors about missing modules.
+    $session->pageTextContains(t('Resolve all issues below to continue the upgrade.'));
+    $session->pageTextContains(t('The no_source_module plugin must define the source_module property.'));
+
+    // Uninstall the module causing the missing module error messages.
+    $this->container->get('module_installer')
+      ->uninstall(['migration_provider_test'], TRUE);
+
+    // Test the file sources.
+    $this->drupalGet('/upgrade');
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    if ($version == 6) {
+      $paths['d6_source_base_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    else {
+      $paths['source_base_path'] = 'https://example.com/wrong-path';
+      $paths['source_private_file_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    $this->drupalPostForm(NULL, $paths + $edits, t('Review upgrade'));
+    if ($version == 6) {
+      $session->responseContains('Unable to read from Files directory.');
+    }
+    else {
+      $session->responseContains('Unable to read from Public files directory.');
+      $session->responseContains('Unable to read from Private files directory.');
+    }
+
+    // Restart the upgrade process.
+    $this->drupalGet('/upgrade');
+    $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');
+
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
+    $session->fieldExists('mysql[host]');
+
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    $this->assertIdConflict($session);
+
+    $this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
+    $session->statusCodeEquals(200);
+
+    // Ensure there are no errors about missing modules from the test module.
+    $session->pageTextNotContains(t('Source module not found for migration_provider_no_annotation.'));
+    $session->pageTextNotContains(t('Source module not found for migration_provider_test.'));
+    // Ensure there are no errors about any other missing migration providers.
+    $session->pageTextNotContains(t('module not found'));
+
+    // Test the upgrade paths.
+    $available_paths = $this->getAvailablePaths();
+    $missing_paths = $this->getMissingPaths();
+    $this->assertReviewPage($session, $available_paths, $missing_paths);
+
+    $this->drupalPostForm(NULL, [], t('Perform upgrade'));
+    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
+    $this->assertMigrationResults($this->getEntityCounts(), $version);
+
+    \Drupal::service('module_installer')->install(['forum']);
+    \Drupal::service('module_installer')->install(['book']);
+
+    // Test incremental migration.
+    $this->createContentPostUpgrade();
+
+    $this->drupalGet('/upgrade');
+    $session->pageTextContains('An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal 8. Rollbacks are not yet supported through the user interface.');
+    $this->drupalPostForm(NULL, [], t('Import new configuration and content from old site'));
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    $session->pageTextContains('WARNING: Content may be overwritten on your new site.');
+    $session->pageTextContains('There is conflicting content of these types:');
+    $session->pageTextContains('comments');
+    $session->pageTextContains('content item revisions');
+    $session->pageTextContains('content items');
+    $session->pageTextContains('custom blocks');
+    $session->pageTextContains('custom menu links');
+    $session->pageTextContains('files');
+    $session->pageTextContains('taxonomy terms');
+    $session->pageTextContains('users');
+
+    $this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
+    $session->statusCodeEquals(200);
+
+    // Need to update available and missing path lists.
+    $all_available = $this->getAvailablePaths();
+    $all_available[] = 'aggregator';
+    $all_missing = $this->getMissingPaths();
+    $all_missing = array_diff($all_missing, ['aggregator']);
+    $this->assertReviewPage($session, $all_available, $all_missing);
+    $this->drupalPostForm(NULL, [], t('Perform upgrade'));
+    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
+    $this->assertMigrationResults($this->getEntityCountsIncremental(), $version);
+
+    // Ensure migrated users can log in.
+    $user = User::load(2);
+    $user->passRaw = 'john.doe_pass';
+    $this->drupalLogin($user);
+    $this->assertFollowUpMigrationResults();
+  }
+
+  /**
+   * Tests that follow-up migrations have been run successfully.
+   */
+  protected function assertFollowUpMigrationResults() {
+    $node = Node::load(10);
+    $this->assertSame('13', $node->get('field_reference')->target_id);
+    $this->assertSame('13', $node->get('field_reference_2')->target_id);
+    $this->assertFalse($node->hasTranslation('fr'));
+
+    $node = Node::load(12);
+    $this->assertFalse($node->hasTranslation('en'));
+    $this->assertNull($node->get('field_reference')->target_id);
+    $this->assertNull($node->get('field_reference_2')->target_id);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function assertIdConflict(WebAssert $session) {
+    $session->pageTextContains('WARNING: Content may be overwritten on your new site.');
+    $session->pageTextContains('There is conflicting content of these types:');
+    $session->pageTextContains('aggregator feed items');
+    $session->pageTextContains('aggregator feeds');
+    $session->pageTextContains('files');
+    $session->pageTextContains('comments');
+    $session->pageTextContains('content item revisions');
+    $session->pageTextContains('content items');
+    $session->pageTextContains('custom blocks');
+    $session->pageTextContains('custom menu links');
+    $session->pageTextContains('files');
+    $session->pageTextContains('taxonomy terms');
+    $session->pageTextContains('users');
+  }
+
+}
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6ReviewPageTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6ReviewPageTest.php
index c62df12df4..c8b6f71fcd 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6ReviewPageTest.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6ReviewPageTest.php
@@ -18,6 +18,7 @@ class MigrateUpgrade6ReviewPageTest extends MigrateUpgradeReviewPageTestBase {
   public static $modules = [
     'language',
     'content_translation',
+    'config_translation',
     'telephone',
     'aggregator',
     'book',
@@ -26,6 +27,7 @@ class MigrateUpgrade6ReviewPageTest extends MigrateUpgradeReviewPageTestBase {
     'syslog',
     'tracker',
     'update',
+    'migrate_drupal_multilingual',
   ];
 
   /**
@@ -60,7 +62,11 @@ protected function getAvailablePaths() {
       'filefield',
       'filter',
       'forum',
+      'i18n',
       'i18nblocks',
+      'i18nmenu',
+      'i18nprofile',
+      'i18nstrings',
       'i18ntaxonomy',
       'imagecache',
       'imagefield',
@@ -105,9 +111,6 @@ protected function getAvailablePaths() {
       'fieldgroup',
       'filefield_meta',
       'help',
-      'i18n',
-      'i18nmenu',
-      'i18nstrings',
       'imageapi',
       'imageapi_gd',
       'imageapi_imagemagick',
@@ -141,7 +144,6 @@ protected function getMissingPaths() {
       'i18ncck',
       'i18ncontent',
       'i18npoll',
-      'i18nprofile',
       'i18nsync',
       'i18nviews',
       'phone',
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6Test.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6Test.php
index 80bc22126f..2d657eb8e7 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6Test.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/MigrateUpgrade6Test.php
@@ -23,6 +23,7 @@ class MigrateUpgrade6Test extends MigrateUpgradeExecuteTestBase {
   public static $modules = [
     'language',
     'content_translation',
+    'config_translation',
     'migrate_drupal_ui',
     'telephone',
     'aggregator',
@@ -30,6 +31,7 @@ class MigrateUpgrade6Test extends MigrateUpgradeExecuteTestBase {
     'forum',
     'statistics',
     'migration_provider_test',
+    'migrate_drupal_multilingual',
   ];
 
   /**
@@ -83,7 +85,7 @@ protected function getEntityCounts() {
       'menu' => 8,
       'taxonomy_term' => 8,
       'taxonomy_vocabulary' => 7,
-      'tour' => 4,
+      'tour' => 5,
       'user' => 7,
       'user_role' => 6,
       'menu_link_content' => 10,
@@ -132,9 +134,11 @@ protected function getAvailablePaths() {
       'filefield',
       'filter',
       'forum',
+      'i18n',
       'i18nblocks',
       'i18nmenu',
-      'i18nblocks',
+      'i18nprofile',
+      'i18nstrings',
       'i18ntaxonomy',
       'imagecache',
       'imagefield',
@@ -161,8 +165,6 @@ protected function getAvailablePaths() {
       'date_api',
       'date_timezone',
       'event',
-      'i18n',
-      'i18nstrings',
       'imageapi',
       'number',
       'php',
@@ -178,9 +180,6 @@ protected function getMissingPaths() {
     return [
       'i18ncck',
       'i18ncontent',
-      // This module is in the missing path list because it is installed on the
-      // source site but it is not installed on the destination site.
-      'i18nprofile',
     ];
   }
 
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7I18nTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7I18nTest.php
new file mode 100644
index 0000000000..b5e16dddd3
--- /dev/null
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7I18nTest.php
@@ -0,0 +1,358 @@
+<?php
+
+namespace Drupal\Tests\migrate_drupal_ui\Functional\d7;
+
+use Drupal\node\Entity\Node;
+use Drupal\Tests\migrate_drupal_ui\Functional\MigrateUpgradeExecuteTestBase;
+use Drupal\user\Entity\User;
+use Drupal\Tests\WebAssert;
+
+/**
+ * Tests Drupal 7 upgrade via the UI without translations.
+ *
+ * The test method is provided by the MigrateUpgradeTestBase class.
+ *
+ * @group migrate_drupal_ui
+ */
+class MigrateUpgrade7I18nTest extends MigrateUpgradeExecuteTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'file',
+    'language',
+    'migrate_drupal_ui',
+    'telephone',
+    'aggregator',
+    'book',
+    'forum',
+    'statistics',
+    'migration_provider_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->loadFixture(drupal_get_path('module', 'migrate_drupal') . '/tests/fixtures/drupal7.php');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSourceBasePath() {
+    return __DIR__ . '/files';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCounts() {
+    return [
+      'aggregator_item' => 11,
+      'aggregator_feed' => 1,
+      'block' => 25,
+      'block_content' => 1,
+      'block_content_type' => 1,
+      'comment' => 1,
+      // The 'standard' profile provides the 'comment' comment type, and the
+      // migration creates 6 comment types, one per node type.
+      'comment_type' => 7,
+      // Module 'language' comes with 'en', 'und', 'zxx'. Migration adds 'is'.
+      'configurable_language' => 4,
+      'contact_form' => 3,
+      'editor' => 2,
+      'field_config' => 67,
+      'field_storage_config' => 50,
+      'file' => 3,
+      'filter_format' => 7,
+      'image_style' => 6,
+      'language_content_settings' => 2,
+      'migration' => 73,
+      'node' => 5,
+      'node_type' => 6,
+      'rdf_mapping' => 7,
+      'search_page' => 2,
+      'shortcut' => 6,
+      'shortcut_set' => 2,
+      'action' => 17,
+      'menu' => 6,
+      'taxonomy_term' => 18,
+      'taxonomy_vocabulary' => 4,
+      'tour' => 4,
+      'user' => 4,
+      'user_role' => 3,
+      'menu_link_content' => 10,
+      'view' => 16,
+      'date_format' => 11,
+      'entity_form_display' => 17,
+      'entity_form_mode' => 1,
+      'entity_view_display' => 28,
+      'entity_view_mode' => 14,
+      'base_field_override' => 9,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCountsIncremental() {
+    $counts = $this->getEntityCounts();
+    $counts['block_content'] = 2;
+    $counts['comment'] = 2;
+    $counts['file'] = 4;
+    $counts['menu_link_content'] = 11;
+    $counts['node'] = 6;
+    $counts['taxonomy_term'] = 19;
+    $counts['user'] = 5;
+    return $counts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getAvailablePaths() {
+    return [
+      'aggregator',
+      'block',
+      'book',
+      'color',
+      'comment',
+      'contact',
+      'date',
+      'dblog',
+      'email',
+      'entityreference',
+      'field',
+      'field_sql_storage',
+      'file',
+      'filter',
+      'forum',
+      'image',
+      'language',
+      'link',
+      'list',
+      'locale',
+      'menu',
+      'node',
+      'number',
+      'options',
+      'path',
+      'phone',
+      'search',
+      'shortcut',
+      'statistics',
+      'system',
+      'taxonomy',
+      'text',
+      'user',
+      // Include modules that do not have an upgrade path and are enabled in the
+      // source database, defined in the $noUpgradePath property
+      // in MigrateUpgradeForm.
+      'blog',
+      'contextual',
+      'date_api',
+      'entity',
+      'field_ui',
+      'help',
+      'php',
+      'simpletest',
+      'toolbar',
+      'translation',
+      'trigger',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getMissingPaths() {
+    return [
+      'rdf',
+      // These modules are in the missing path list because they are installed
+      // on the source site but they are not installed on the destination site.
+      'syslog',
+      'tracker',
+      'update',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testMigrateUpgradeExecute() {
+
+    $connection_options = $this->sourceDatabase->getConnectionOptions();
+    $this->drupalGet('/upgrade');
+    $session = $this->assertSession();
+    $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');
+
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
+    $session->fieldExists('mysql[host]');
+
+    $driver = $connection_options['driver'];
+    $connection_options['prefix'] = $connection_options['prefix']['default'];
+
+    // Use the driver connection form to get the correct options out of the
+    // database settings. This supports all of the databases we test against.
+    $drivers = drupal_get_database_types();
+    $form = $drivers[$driver]->getFormOptions($connection_options);
+    $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
+    $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
+    $edit = [
+      $driver => $connection_options,
+      'source_private_file_path' => $this->getSourceBasePath(),
+      'version' => $version,
+    ];
+    if ($version == 6) {
+      $edit['d6_source_base_path'] = $this->getSourceBasePath();
+    }
+    else {
+      $edit['source_base_path'] = $this->getSourceBasePath();
+    }
+    if (count($drivers) !== 1) {
+      $edit['driver'] = $driver;
+    }
+    $edits = $this->translatePostValues($edit);
+
+    // Ensure submitting the form with invalid database credentials gives us a
+    // nice warning.
+    $this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
+    $session->pageTextContains('Resolve all issues below to continue the upgrade.');
+
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    // Ensure we get errors about missing modules.
+    $session->pageTextContains(t('Resolve all issues below to continue the upgrade.'));
+    $session->pageTextContains(t('The no_source_module plugin must define the source_module property.'));
+
+    // Uninstall the module causing the missing module error messages.
+    $this->container->get('module_installer')
+      ->uninstall(['migration_provider_test'], TRUE);
+
+    // Test the file sources.
+    $this->drupalGet('/upgrade');
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    if ($version == 6) {
+      $paths['d6_source_base_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    else {
+      $paths['source_base_path'] = 'https://example.com/wrong-path';
+      $paths['source_private_file_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    $this->drupalPostForm(NULL, $paths + $edits, t('Review upgrade'));
+    if ($version == 6) {
+      $session->responseContains('Unable to read from Files directory.');
+    }
+    else {
+      $session->responseContains('Unable to read from Public files directory.');
+      $session->responseContains('Unable to read from Private files directory.');
+    }
+
+    // Restart the upgrade process.
+    $this->drupalGet('/upgrade');
+    $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');
+
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
+    $session->fieldExists('mysql[host]');
+
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    $this->assertIdConflict($session);
+
+    $this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
+    $session->statusCodeEquals(200);
+
+    // Ensure there are no errors about missing modules from the test module.
+    $session->pageTextNotContains(t('Source module not found for migration_provider_no_annotation.'));
+    $session->pageTextNotContains(t('Source module not found for migration_provider_test.'));
+    // Ensure there are no errors about any other missing migration providers.
+    $session->pageTextNotContains(t('module not found'));
+
+    // Test the upgrade paths.
+    $available_paths = $this->getAvailablePaths();
+    $missing_paths = $this->getMissingPaths();
+    $this->assertReviewPage($session, $available_paths, $missing_paths);
+
+    $this->drupalPostForm(NULL, [], t('Perform upgrade'));
+    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
+    $this->assertMigrationResults($this->getEntityCounts(), $version);
+
+    \Drupal::service('module_installer')->install(['forum']);
+    \Drupal::service('module_installer')->install(['book']);
+
+    // Test incremental migration.
+    $this->createContentPostUpgrade();
+
+    $this->drupalGet('/upgrade');
+    $session->pageTextContains('An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal 8. Rollbacks are not yet supported through the user interface.');
+    $this->drupalPostForm(NULL, [], t('Import new configuration and content from old site'));
+    $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
+    $session->pageTextContains('WARNING: Content may be overwritten on your new site.');
+    $session->pageTextContains('There is conflicting content of these types:');
+    $session->pageTextContains('comments');
+    $session->pageTextContains('content item revisions');
+    $session->pageTextContains('content items');
+    $session->pageTextContains('custom blocks');
+    $session->pageTextContains('custom menu links');
+    $session->pageTextContains('files');
+    $session->pageTextContains('taxonomy terms');
+    $session->pageTextContains('users');
+
+    $this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
+    $session->statusCodeEquals(200);
+
+    // Need to update available and missing path lists.
+    $all_available = $this->getAvailablePaths();
+    $all_available[] = 'aggregator';
+    $all_missing = $this->getMissingPaths();
+    $all_missing = array_diff($all_missing, ['aggregator']);
+    $this->assertReviewPage($session, $all_available, $all_missing);
+    $this->drupalPostForm(NULL, [], t('Perform upgrade'));
+    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
+    $this->assertMigrationResults($this->getEntityCountsIncremental(), $version);
+
+    // Ensure migrated users can log in.
+    $user = User::load(2);
+    $user->passRaw = 'a password';
+    $this->drupalLogin($user);
+    $this->assertFollowUpMigrationResults();
+  }
+
+  /**
+   * Tests that follow-up migrations have been run successfully.
+   */
+  protected function assertFollowUpMigrationResults() {
+    $node = Node::load(2);
+    $this->assertSame('5', $node->get('field_reference')->target_id);
+    $this->assertSame('5', $node->get('field_reference_2')->target_id);
+    $this->assertFalse($node->hasTranslation('is'));
+
+    $node = Node::load(4);
+    $this->assertSame('3', $node->get('field_reference')->target_id);
+    $this->assertSame('3', $node->get('field_reference_2')->target_id);
+    $this->assertFalse($node->hasTranslation('en'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function assertIdConflict(WebAssert $session) {
+    $session->pageTextContains('WARNING: Content may be overwritten on your new site.');
+    $session->pageTextContains('There is conflicting content of these types:');
+    $session->pageTextContains('aggregator feed items');
+    $session->pageTextContains('aggregator feeds');
+    $session->pageTextContains('files');
+    $session->pageTextContains('comments');
+    $session->pageTextContains('content item revisions');
+    $session->pageTextContains('content items');
+    $session->pageTextContains('custom blocks');
+    $session->pageTextContains('custom menu links');
+    $session->pageTextContains('files');
+    $session->pageTextContains('taxonomy terms');
+    $session->pageTextContains('users');
+  }
+
+}
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7ReviewPageTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7ReviewPageTest.php
index 28ceaf0987..38d8a719ff 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7ReviewPageTest.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7ReviewPageTest.php
@@ -26,6 +26,7 @@ class MigrateUpgrade7ReviewPageTest extends MigrateUpgradeReviewPageTestBase {
     'syslog',
     'tracker',
     'update',
+    'migrate_drupal_multilingual',
   ];
 
   /**
@@ -57,7 +58,6 @@ protected function getAvailablePaths() {
       'date',
       'dblog',
       'email',
-      'entity_translation',
       'field',
       'field_sql_storage',
       'file',
@@ -108,6 +108,7 @@ protected function getAvailablePaths() {
       'entity_feature',
       'entity_token',
       'entityreference',
+      'entity_translation',
       'field_ui',
       'help',
       'openid',
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php
index e651af99af..f6c86662f3 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/MigrateUpgrade7Test.php
@@ -31,6 +31,7 @@ class MigrateUpgrade7Test extends MigrateUpgradeExecuteTestBase {
     'forum',
     'statistics',
     'migration_provider_test',
+    'migrate_drupal_multilingual',
   ];
 
   /**
@@ -127,7 +128,6 @@ protected function getAvailablePaths() {
       'dblog',
       'email',
       'entityreference',
-      'entity_translation',
       'field',
       'field_sql_storage',
       'file',
diff --git a/core/modules/node/migrations/d6_node_translation.yml b/core/modules/node/migrations/d6_node_translation.yml
index b1345ed065..38e6870162 100644
--- a/core/modules/node/migrations/d6_node_translation.yml
+++ b/core/modules/node/migrations/d6_node_translation.yml
@@ -4,6 +4,7 @@ migration_tags:
   - Drupal 6
   - translation
   - Content
+  - Multilingual
 class: Drupal\node\Plugin\migrate\D6NodeTranslation
 deriver: Drupal\node\Plugin\migrate\D6NodeDeriver
 source:
diff --git a/core/modules/node/migrations/d7_node_translation.yml b/core/modules/node/migrations/d7_node_translation.yml
index b5d488e268..90a101fec1 100644
--- a/core/modules/node/migrations/d7_node_translation.yml
+++ b/core/modules/node/migrations/d7_node_translation.yml
@@ -4,6 +4,7 @@ migration_tags:
   - Drupal 7
   - translation
   - Content
+  - Multilingual
 class: Drupal\node\Plugin\migrate\D7NodeTranslation
 deriver: Drupal\node\Plugin\migrate\D7NodeDeriver
 source:
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
index 693ed36ff0..6b7b212d14 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
@@ -19,7 +19,12 @@ class MigrateNodeTest extends MigrateNodeTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['language', 'content_translation', 'menu_ui'];
+  public static $modules = [
+    'language',
+    'content_translation',
+    'menu_ui',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d6/NodeTranslationRedirectTest.php b/core/modules/node/tests/src/Kernel/Migrate/d6/NodeTranslationRedirectTest.php
index 7daac88309..eb9f71d21a 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d6/NodeTranslationRedirectTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d6/NodeTranslationRedirectTest.php
@@ -20,6 +20,7 @@ class NodeTranslationRedirectTest extends MigrateDrupal6TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
   ];
 
   /**
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php b/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php
index 5b8a9ec97c..6b9ce320c6 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php
@@ -31,6 +31,7 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
     'language',
     'link',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'taxonomy',
     'telephone',
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d7/NodeTranslationRedirectTest.php b/core/modules/node/tests/src/Kernel/Migrate/d7/NodeTranslationRedirectTest.php
index 88cc2ade7b..c0c20df2f2 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d7/NodeTranslationRedirectTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d7/NodeTranslationRedirectTest.php
@@ -20,6 +20,7 @@ class NodeTranslationRedirectTest extends MigrateDrupal7TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'text',
   ];
diff --git a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
index 59cf3cb1fb..b657fcde38 100644
--- a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
+++ b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
@@ -16,7 +16,13 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['language', 'content_translation', 'path', 'menu_ui'];
+  public static $modules = [
+    'language',
+    'content_translation',
+    'path',
+    'menu_ui',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php
index dae0249500..8ce2a5b33f 100644
--- a/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php
+++ b/core/modules/path/tests/src/Kernel/Migrate/d7/MigrateUrlAliasTest.php
@@ -18,6 +18,7 @@ class MigrateUrlAliasTest extends MigrateDrupal7TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'path',
     'text',
diff --git a/core/modules/statistics/migrations/statistics_node_translation_counter.yml b/core/modules/statistics/migrations/statistics_node_translation_counter.yml
index bf8cde4092..0c11cd2114 100644
--- a/core/modules/statistics/migrations/statistics_node_translation_counter.yml
+++ b/core/modules/statistics/migrations/statistics_node_translation_counter.yml
@@ -4,6 +4,7 @@ migration_tags:
   - Drupal 6
   - Drupal 7
   - Content
+  - Multilingual
 source:
   plugin: node_counter
 process:
diff --git a/core/modules/statistics/tests/src/Kernel/Migrate/d6/MigrateNodeCounterTest.php b/core/modules/statistics/tests/src/Kernel/Migrate/d6/MigrateNodeCounterTest.php
index ea917f51a4..5ebde7d723 100644
--- a/core/modules/statistics/tests/src/Kernel/Migrate/d6/MigrateNodeCounterTest.php
+++ b/core/modules/statistics/tests/src/Kernel/Migrate/d6/MigrateNodeCounterTest.php
@@ -18,6 +18,7 @@ class MigrateNodeCounterTest extends MigrateDrupal6TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'statistics',
     'text',
diff --git a/core/modules/statistics/tests/src/Kernel/Migrate/d7/MigrateNodeCounterTest.php b/core/modules/statistics/tests/src/Kernel/Migrate/d7/MigrateNodeCounterTest.php
index 9a7317fada..f2bececc9b 100644
--- a/core/modules/statistics/tests/src/Kernel/Migrate/d7/MigrateNodeCounterTest.php
+++ b/core/modules/statistics/tests/src/Kernel/Migrate/d7/MigrateNodeCounterTest.php
@@ -18,6 +18,7 @@ class MigrateNodeCounterTest extends MigrateDrupal7TestBase {
     'content_translation',
     'language',
     'menu_ui',
+    'migrate_drupal_multilingual',
     'node',
     'statistics',
     'text',
diff --git a/core/modules/taxonomy/migrations/d6_taxonomy_vocabulary_translation.yml b/core/modules/taxonomy/migrations/d6_taxonomy_vocabulary_translation.yml
index 2ac7760eba..1fcba3e34d 100644
--- a/core/modules/taxonomy/migrations/d6_taxonomy_vocabulary_translation.yml
+++ b/core/modules/taxonomy/migrations/d6_taxonomy_vocabulary_translation.yml
@@ -3,6 +3,7 @@ label: Taxonomy vocabularies
 migration_tags:
   - Drupal 6
   - Configuration
+  - Multilingual
 source:
   plugin: d6_taxonomy_vocabulary_translation
 process:
@@ -23,6 +24,7 @@ process:
   translation: translation
 destination:
   plugin: entity:taxonomy_vocabulary
+  destination_module: config_translation
 migration_dependencies:
   required:
     - d6_taxonomy_vocabulary
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTaxonomyVocabularyTranslationTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTaxonomyVocabularyTranslationTest.php
index 3993abb98f..bed6a8fbd4 100644
--- a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTaxonomyVocabularyTranslationTest.php
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTaxonomyVocabularyTranslationTest.php
@@ -14,7 +14,11 @@ class MigrateTaxonomyVocabularyTranslationTest extends MigrateDrupal6TestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['language', 'taxonomy'];
+  public static $modules = [
+    'language',
+    'taxonomy',
+    'migrate_drupal_multilingual',
+  ];
 
   /**
    * {@inheritdoc}
