diff --git a/core/modules/config_translation/migrations/d7_taxonomy_vocabulary_translation.yml b/core/modules/config_translation/migrations/d7_taxonomy_vocabulary_translation.yml
new file mode 100644
index 0000000000..86081f8613
--- /dev/null
+++ b/core/modules/config_translation/migrations/d7_taxonomy_vocabulary_translation.yml
@@ -0,0 +1,31 @@
+id: d7_taxonomy_vocabulary_translation
+label: Taxonomy vocabulary translations
+migration_tags:
+  - Drupal 7
+  - Configuration
+  - Multilingual
+source:
+  plugin: d7_taxonomy_vocabulary_translation
+process:
+  vid:
+    -
+      plugin: migration_lookup
+      migration: d7_taxonomy_vocabulary
+      source: vid
+    -
+      plugin: skip_on_empty
+      method: row
+  langcode: language
+  property:
+    plugin: static_map
+    source: property
+    map:
+      name: name
+      description: description
+  translation: translation
+destination:
+  plugin: entity:taxonomy_vocabulary
+  destination_module: config_translation
+migration_dependencies:
+  required:
+    - d7_taxonomy_vocabulary
diff --git a/core/modules/content_translation/migrations/d7_taxonomy_term_translation.yml b/core/modules/content_translation/migrations/d7_taxonomy_term_translation.yml
new file mode 100644
index 0000000000..206df0e46b
--- /dev/null
+++ b/core/modules/content_translation/migrations/d7_taxonomy_term_translation.yml
@@ -0,0 +1,54 @@
+id: d7_taxonomy_term_translation
+label: Taxonomy terms
+migration_tags:
+  - Drupal 7
+  - Content
+  - Multilingual
+source:
+  plugin: d7_taxonomy_term_translation
+  translations: true
+process:
+  skip:
+    -
+      plugin: static_map
+      source: i18n_mode
+      default_value: 0
+      map:
+        1: 0
+        2: 2
+        4: 4
+    -
+      plugin: skip_on_empty
+      method: row
+  # If you are using this file to build a custom migration consider removing
+  # the tid field to allow incremental migrations.
+  tid: tid
+  langcode: language
+  vid:
+    plugin: migration
+    migration: d7_taxonomy_vocabulary
+    source: vid
+  name: name
+  'description/value': description
+  'description/format': format
+  weight: weight
+  # Only attempt to stub real (non-zero) parents.
+  parent_id:
+    -
+      plugin: skip_on_empty
+      method: process
+      source: parent
+    -
+      plugin: migration
+      migration: d7_taxonomy_term
+  parent:
+    plugin: default_value
+    default_value: 0
+    source: '@parent_id'
+  changed: timestamp
+destination:
+  plugin: entity:taxonomy_term
+  destination_module: content_translation
+migration_dependencies:
+  required:
+    - d7_taxonomy_term
diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
index f68df74203..3fd411cbe8 100644
--- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
@@ -18721,16 +18721,8 @@
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '85',
-  'translation' => 'fr - VocabLocalized',
-  'language' => 'fr',
-  'plid' => '0',
-  'plural' => '0',
-  'i18n_status' => '0',
-))
-->values(array(
-  'lid' => '86',
-  'translation' => 'fr - Vocabulary localize option',
+  'lid' => '87',
+  'translation' => 'fr - VocabFixed',
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
@@ -18738,7 +18730,7 @@
 ))
 ->values(array(
   'lid' => '89',
-  'translation' => 'fr - VocabFixed',
+  'translation' => 'fr - VocabLocalized',
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
@@ -18746,39 +18738,7 @@
 ))
 ->values(array(
   'lid' => '90',
-  'translation' => 'fr - Vocabulary fixed option',
-  'language' => 'fr',
-  'plid' => '0',
-  'plural' => '0',
-  'i18n_status' => '0',
-))
-->values(array(
-  'lid' => '91',
-  'translation' => 'fr - Jupiter Station',
-  'language' => 'fr',
-  'plid' => '0',
-  'plural' => '0',
-  'i18n_status' => '0',
-))
-->values(array(
-  'lid' => '92',
-  'translation' => 'fr - Holographic research.',
-  'language' => 'fr',
-  'plid' => '0',
-  'plural' => '0',
-  'i18n_status' => '0',
-))
-->values(array(
-  'lid' => '93',
-  'translation' => 'fr - DS9',
-  'language' => 'fr',
-  'plid' => '0',
-  'plural' => '0',
-  'i18n_status' => '0',
-))
-->values(array(
-  'lid' => '94',
-  'translation' => 'Terok Nor',
+  'translation' => 'fr - Vocabulary localize option',
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
@@ -18798,7 +18758,7 @@
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
-  'i18n_status' => '0',
+  'i18n_status' => '1',
 ))
 ->values(array(
   'lid' => '163',
@@ -18814,7 +18774,7 @@
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
-  'i18n_status' => '0',
+  'i18n_status' => '1',
 ))
 ->values(array(
   'lid' => '684',
@@ -18822,7 +18782,7 @@
   'language' => 'fr',
   'plid' => '0',
   'plural' => '0',
-  'i18n_status' => '0',
+  'i18n_status' => '1',
 ))
 ->values(array(
   'lid' => '761',
@@ -18913,23 +18873,23 @@
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '687',
-  'translation' => 'is - Off',
+  'lid' => '89',
+  'translation' => 'is - VocabLocalized',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '688',
-  'translation' => 'is - 1',
+  'lid' => '90',
+  'translation' => 'is - Vocabulary localize option',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '87',
+  'lid' => '91',
   'translation' => 'is - VocabTranslate',
   'language' => 'is',
   'plid' => '0',
@@ -18937,7 +18897,7 @@
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '88',
+  'lid' => '92',
   'translation' => 'is - Vocabulary translate option',
   'language' => 'is',
   'plid' => '0',
@@ -18945,48 +18905,56 @@
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '93',
-  'translation' => 'is - DS9',
+  'lid' => '95',
+  'translation' => 'is - Some helpful text.',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '94',
-  'translation' => 'is - Terok Nor',
+  'lid' => '96',
+  'translation' => 'is - Email',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '95',
-  'translation' => 'is - Some helpful text.',
+  'lid' => '97',
+  'translation' => 'is - The email help text.',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '96',
-  'translation' => 'is - Email',
+  'lid' => '128',
+  'translation' => 'is - Term Reference',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '97',
-  'translation' => 'is - The email help text.',
+  'lid' => '687',
+  'translation' => 'is - Off',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
   'i18n_status' => '0',
 ))
 ->values(array(
-  'lid' => '128',
-  'translation' => 'is - Term Reference',
+  'lid' => '688',
+  'translation' => 'is - 1',
+  'language' => 'is',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '758',
+  'translation' => 'is field - vocab_localize',
   'language' => 'is',
   'plid' => '0',
   'plural' => '0',
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 287dd4037e..b4b2e109ac 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\node\Kernel\Migrate\d7;
 
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\taxonomy\Entity\Term;
 use Drupal\Tests\file\Kernel\Migrate\d7\FileMigrationSetupTrait;
 use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
 use Drupal\node\Entity\Node;
@@ -51,14 +52,19 @@ protected function setUp() {
 
     $this->migrateUsers();
     $this->migrateFields();
+    $this->migrateTaxonomyTerms();
     $this->executeMigrations([
       'language',
+      'd7_language_content_taxonomy_vocabulary_settings',
+      'd7_taxonomy_term_localized_translation',
+      'd7_taxonomy_term_translation',
       'd7_language_content_settings',
       'd7_comment_field',
       'd7_comment_field_instance',
       'd7_node',
       'd7_node_translation',
       'd7_entity_translation_settings',
+      'd7_taxonomy_term_entity_translation',
       'd7_node_entity_translation',
     ]);
   }
@@ -180,6 +186,18 @@ public function testNode() {
     $this->assertEquals('internal:/', $node->field_link->uri);
     $this->assertEquals('Home', $node->field_link->title);
     $this->assertEquals(CommentItemInterface::OPEN, $node->comment_node_article->status);
+    $term_ref = $node->get('field_vocab_localize')->target_id;
+    $this->assertSame('20', $term_ref);
+    $this->assertSame('DS9', Term::load($term_ref)->getName());
+
+    $term_ref = $node->get('field_vocab_translate')->target_id;
+    $this->assertSame('21', $term_ref);
+    $this->assertSame('High council', Term::load($term_ref)->getName());
+
+    // The field_vocab_fixed is NULL in the Icelandic translation and since
+    // that is migrated last all the term references for this field are NULL.
+    $term_ref = $node->get('field_vocab_fixed')->target_id;
+    $this->assertNulL($term_ref);
     $this->assertTrue($node->hasTranslation('is'), "Node 2 has an Icelandic translation");
 
     $translation = $node->getTranslation('is');
@@ -189,6 +207,16 @@ public function testNode() {
     $this->assertEquals('internal:/', $translation->field_link->uri);
     $this->assertEquals(CommentItemInterface::OPEN, $translation->comment_node_article->status);
     $this->assertEquals('Home', $translation->field_link->title);
+    $term_ref = $translation->get('field_vocab_localize')->target_id;
+    $this->assertSame('20', $term_ref);
+    $this->assertSame('DS9', Term::load($term_ref)->getName());
+
+    $term_ref = $translation->get('field_vocab_translate')->target_id;
+    $this->assertSame('23', $term_ref);
+    $this->assertSame('is - High council', Term::load($term_ref)->getName());
+
+    $term_ref = $node->get('field_vocab_fixed')->target_id;
+    $this->assertNulL($term_ref);
 
     // Test that content_translation_source is set.
     $manager = $this->container->get('content_translation.manager');
diff --git a/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php b/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php
new file mode 100644
index 0000000000..b738c93067
--- /dev/null
+++ b/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\taxonomy\Plugin\migrate\source\d7;
+
+use Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait;
+use Drupal\migrate\Row;
+
+/**
+ * Gets i18n taxonomy terms from source database.
+ *
+ * @MigrateSource(
+ *   id = "d7_taxonomy_term_translation",
+ *   source_module = "i18n_taxonomy"
+ * )
+ */
+class TermTranslation extends Term {
+
+  use I18nQueryTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = parent::query();
+    if ($this->database->schema()->fieldExists('taxonomy_term_data', 'language')) {
+      $query->addField('td', 'language', 'td_language');
+    }
+    if ($this->database->schema()->fieldExists('taxonomy_vocabulary', 'i18n_mode')) {
+      $query->addField('tv', 'i18n_mode');
+    }
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    parent::prepareRow($row);
+    $row->setSourceProperty('language', $row->getSourceProperty('td_language'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    $fields = [
+      'language' => $this->t('Language for this term.'),
+      'name_translated' => $this->t('Term name translation.'),
+      'description_translated' => $this->t('Term description translation.'),
+    ];
+    return parent::fields() + $fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['language']['type'] = 'string';
+    $ids['language']['alias'] = 'td';
+    return parent::getIds() + $ids;
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php b/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php
new file mode 100644
index 0000000000..c15c3aa657
--- /dev/null
+++ b/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Drupal\taxonomy\Plugin\migrate\source\d7;
+
+use Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait;
+use Drupal\migrate\Row;
+
+/**
+ * Drupal 7 vocabulary translations from source database.
+ *
+ * @MigrateSource(
+ *   id = "d7_taxonomy_vocabulary_translation",
+ *   source_module = "i18n_taxonomy"
+ * )
+ */
+class VocabularyTranslation extends Vocabulary {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = parent::query();
+    $query->leftjoin('i18n_string', 'i18n', 'v.vid = i18n.objectid');
+    $query->innerJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
+    $query
+      ->condition('type', 'vocabulary')
+      ->fields('lt')
+      ->fields('i18n');
+    $query->addField('lt', 'language', 'lt.language');
+    $query->addField('lt', 'lid', 'lt_lid');
+
+    if ($this->getDatabase()
+      ->schema()
+      ->fieldExists('taxonomy_vocabulary', 'language')) {
+      $query->addField('v', 'language');
+    }
+    if ($this->getDatabase()
+      ->schema()
+      ->fieldExists('taxonomy_vocabulary', 'i18n_mode')) {
+      $query->addField('v', 'i18n_mode');
+    }
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    $fields = [
+      'i18n_mode' => $this->t('Internationalization mode.'),
+      'language' => $this->t('Language for this field.'),
+      'property' => $this->t('Name of property being translated.'),
+      'type' => $this->t('Name of property being translated.'),
+      'objectid' => $this->t('Name of property being translated.'),
+      'lt_lid' => $this->t('Name of property being translated.'),
+      'translation' => $this->t('Translation of either the name or the description.'),
+      'lid' => $this->t('Language string ID'),
+      'textgroup' => $this->t('A module defined group of translations'),
+      'context' => $this->t('Full string ID for quick search: type:objectid:property.'),
+      'objectindex' => $this->t('Integer value of Object ID'),
+      'format' => $this->t('The {filter_format}.format of the string'),
+      'ltlanguage' => $this->t('Language code from locales_source table'),
+      'plid' => $this->t('Parent lid'),
+      'plural' => $this->t('Plural index number'),
+      'i18n_status' => $this->t('Translation needs update'),
+    ];
+    return parent::fields() + $fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    parent::prepareRow($row);
+    // For ease of reading the migration use 'language' as the property name for
+    // the language.
+    $language = $row->getSourceProperty('ltlanguage');
+    $row->setSourceProperty('language', $language);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids = [];
+    $ids['language']['type'] = 'string';
+    $ids['language']['alias'] = 'lt';
+    return parent::getIds() + $ids;
+  }
+
+}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyTermTranslationTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyTermTranslationTest.php
new file mode 100644
index 0000000000..68f12435ce
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyTermTranslationTest.php
@@ -0,0 +1,168 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
+
+use Drupal\taxonomy\Entity\Term;
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+use Drupal\taxonomy\TermInterface;
+
+/**
+ * Test migration of translated taxonomy terms.
+ *
+ * @group migrate_drupal_7
+ */
+class MigrateTaxonomyTermTranslationTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'comment',
+    'content_translation',
+    'datetime',
+    'image',
+    'language',
+    'link',
+    'menu_ui',
+    // Required for translation migrations.
+    'migrate_drupal_multilingual',
+    'node',
+    'taxonomy',
+    'telephone',
+    'text',
+  ];
+
+  /**
+   * The cached taxonomy tree items, keyed by vid and tid.
+   *
+   * @var array
+   */
+  protected $treeData = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('comment');
+    $this->installEntitySchema('file');
+    $this->installEntitySchema('taxonomy_term');
+    $this->migrateFields();
+
+    $this->executeMigrations([
+      'language',
+      'd7_language_content_taxonomy_vocabulary_settings',
+      'd7_taxonomy_vocabulary',
+      'd7_taxonomy_term',
+      'd7_entity_translation_settings',
+      'd7_taxonomy_term_entity_translation',
+      'd7_taxonomy_term_localized_translation',
+      'd7_taxonomy_term_translation',
+    ]);
+  }
+
+  /**
+   * Validates a migrated term contains the expected values.
+   *
+   * @param int $id
+   *   Entity ID to load and check.
+   * @param string $expected_language
+   *   The language code for this term.
+   * @param string $expected_label
+   *   The label the migrated entity should have.
+   * @param string $expected_vid
+   *   The parent vocabulary the migrated entity should have.
+   * @param string $expected_description
+   *   The description the migrated entity should have.
+   * @param string $expected_format
+   *   The format the migrated entity should have.
+   * @param int $expected_weight
+   *   The weight the migrated entity should have.
+   * @param array $expected_parents
+   *   The parent terms the migrated entity should have.
+   * @param int $expected_field_integer_value
+   *   The value the migrated entity field should have.
+   * @param int $expected_term_reference_tid
+   *   The term reference ID the migrated entity field should have.
+   */
+  protected function assertEntity($id, $expected_language, $expected_label, $expected_vid, $expected_description = '', $expected_format = NULL, $expected_weight = 0, array $expected_parents = [], $expected_field_integer_value = NULL, $expected_term_reference_tid = NULL) {
+    /** @var \Drupal\taxonomy\TermInterface $entity */
+    $entity = Term::load($id);
+    $this->assertInstanceOf(TermInterface::class, $entity);
+    $this->assertSame($expected_language, $entity->language()->getId());
+    $this->assertSame($expected_label, $entity->label());
+    $this->assertSame($expected_vid, $entity->bundle());
+    $this->assertSame($expected_description, $entity->getDescription());
+    $this->assertSame($expected_format, $entity->getFormat());
+    $this->assertSame($expected_weight, $entity->getWeight());
+    $this->assertHierarchy($expected_vid, $id, $expected_parents);
+  }
+
+  /**
+   * Asserts that a term is present in the tree storage, with the right parents.
+   *
+   * @param string $vid
+   *   Vocabulary ID.
+   * @param int $tid
+   *   ID of the term to check.
+   * @param array $parent_ids
+   *   The expected parent term IDs.
+   */
+  protected function assertHierarchy($vid, $tid, array $parent_ids) {
+    if (!isset($this->treeData[$vid])) {
+      $tree = \Drupal::entityTypeManager()
+        ->getStorage('taxonomy_term')
+        ->loadTree($vid);
+      $this->treeData[$vid] = [];
+      foreach ($tree as $item) {
+        $this->treeData[$vid][$item->tid] = $item;
+      }
+    }
+
+    $this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
+    $term = $this->treeData[$vid][$tid];
+    $this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
+  }
+
+  /**
+   * Tests the Drupal i18n  taxonomy term to Drupal 8 migration.
+   */
+  public function testTaxonomyTermTranslation() {
+    // Forums vocabulary, no multilingual option.
+    $this->assertEntity(1, 'en', 'General discussion', 'forums', NULL, NULL, '2', []);
+    $this->assertEntity(5, 'en', 'Custom Forum', 'forums', 'Where the cool kids are.', NULL, '3', []);
+    $this->assertEntity(6, 'en', 'Games', 'forums', NULL, NULL, '4', []);
+    $this->assertEntity(7, 'en', 'Minecraft', 'forums', NULL, NULL, '1', ['6']);
+    $this->assertEntity(8, 'en', 'Half Life 3', 'forums', NULL, NULL, '0', ['6']);
+
+    // Test vocabulary, field translation.
+    $this->assertEntity(2, 'en', 'Term1 (This is a real field!)', 'test_vocabulary', 'The first term. (This is a real field!)', 'filtered_html', '0', []);
+    $this->assertEntity(3, 'en', 'Term2', 'test_vocabulary', 'The second term.', 'filtered_html', '0', []);
+    $this->assertEntity(4, 'en', 'Term3 in plain old English', 'test_vocabulary', 'The third term in plain old English.', 'full_html', '0', ['3']);
+
+    // Tags vocabulary, no multilingual option.
+    $this->assertEntity(9, 'en', 'Benjamin Sisko', 'tags', 'Portrayed by Avery Brooks', 'filtered_html', '0', []);
+    $this->assertEntity(10, 'en', 'Kira Nerys', 'tags', 'Portrayed by Nana Visitor', 'filtered_html', '0', []);
+    $this->assertEntity(11, 'en', 'Dax', 'tags', 'Portrayed by Terry Farrell', 'filtered_html', '0', []);
+    $this->assertEntity(12, 'en', 'Jake Sisko', 'tags', 'Portrayed by Cirroc Lofton', 'filtered_html', '0', []);
+    $this->assertEntity(13, 'en', 'Gul Dukat', 'tags', 'Portrayed by Marc Alaimo', 'filtered_html', '0', []);
+    $this->assertEntity(14, 'en', 'Odo', 'tags', 'Portrayed by Rene Auberjonois', 'filtered_html', '0', []);
+    $this->assertEntity(15, 'en', 'Worf', 'tags', 'Portrayed by Michael Dorn', 'filtered_html', '0', []);
+    $this->assertEntity(16, 'en', "Miles O'Brien", 'tags', 'Portrayed by Colm Meaney', 'filtered_html', '0', []);
+    $this->assertEntity(17, 'en', 'Quark', 'tags', 'Portrayed by Armin Shimerman', 'filtered_html', '0', []);
+    $this->assertEntity(18, 'en', 'Elim Garak', 'tags', 'Portrayed by Andrew Robinson', 'filtered_html', '0', []);
+
+    // Localized.
+    $this->assertEntity(19, 'en', 'Jupiter Station', 'vocablocalized', 'Holographic research.', 'filtered_html', '0', []);
+    $this->assertEntity(20, 'en', 'DS9', 'vocablocalized', 'Terok Nor', 'filtered_html', '0', []);
+
+    // Translate.
+    $this->assertEntity(21, 'en', 'High council', 'vocabtranslate', NULL, NULL, '0', []);
+    $this->assertEntity(22, 'fr', 'fr - High council', 'vocabtranslate', NULL, NULL, '0', []);
+    $this->assertEntity(23, 'is', 'is - High council', 'vocabtranslate', NULL, NULL, '0', []);
+
+    // Fixed.
+    $this->assertEntity(24, 'fr', 'FR - Crewman', 'vocabfixed', NULL, NULL, '0', []);
+  }
+
+}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyVocabularyTranslationTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyVocabularyTranslationTest.php
new file mode 100644
index 0000000000..19b62b780b
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d7/MigrateTaxonomyVocabularyTranslationTest.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Kernel\Migrate\d7;
+
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+
+/**
+ * Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
+ *
+ * @group migrate_drupal_7
+ */
+class MigrateTaxonomyVocabularyTranslationTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'config_translation',
+    'language',
+    // Required for translation migrations.
+    'migrate_drupal_multilingual',
+    'taxonomy',
+    'text',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->executeMigrations([
+      'd7_taxonomy_vocabulary',
+      'd7_taxonomy_vocabulary_translation',
+    ]);
+  }
+
+  /**
+   * Tests the Drupal 7 i18n taxonomy vocabularies to Drupal 8 migration.
+   */
+  public function testTaxonomyVocabularyTranslation() {
+    /** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
+    $language_manager = \Drupal::service('language_manager');
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.sujet_de_discussion');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.tags');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.test_vocabulary');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.test_vocabulary');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocabulary_name_clearly_diffe');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabulary_name_clearly_diffe');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabfixed');
+    $this->assertSame('fr - VocabFixed', $config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocablocalized');
+    $this->assertSame('fr - VocabLocalized', $config_translation->get('name'));
+    $this->assertSame('fr - Vocabulary localize option', $config_translation->get('description'));
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocablocalized');
+    $this->assertSame('is - VocabLocalized', $config_translation->get('name'));
+    $this->assertSame('is - Vocabulary localize option', $config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'taxonomy.vocabulary.vocabtranslate');
+    $this->assertNull($config_translation->get('name'));
+    $this->assertNull($config_translation->get('description'));
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'taxonomy.vocabulary.vocabtranslate');
+    $this->assertSame('is - VocabTranslate', $config_translation->get('name'));
+    $this->assertSame('is - Vocabulary translate option', $config_translation->get('description'));
+  }
+
+}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Plugin/migrate/source/d7/VocabularyTranslationTest.php b/core/modules/taxonomy/tests/src/Kernel/Plugin/migrate/source/d7/VocabularyTranslationTest.php
new file mode 100644
index 0000000000..58ed7a50bd
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Kernel/Plugin/migrate/source/d7/VocabularyTranslationTest.php
@@ -0,0 +1,168 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Kernel\Plugin\migrate\source\d7;
+
+use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
+
+/**
+ * Tests D7 i18n vocabulary source plugin.
+ *
+ * @covers \Drupal\taxonomy\Plugin\migrate\source\d7\VocabularyTranslation
+ * @group taxonomy
+ */
+class VocabularyTranslationTest extends MigrateSqlSourceTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['taxonomy', 'migrate_drupal'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function providerSource() {
+    $tests = [];
+
+    // The source data.
+    $tests[0][0]['i18n_string'] = [
+      [
+        'lid' => '1',
+        'textgroup' => 'taxonomy',
+        'context' => 'vocabulary:1:name',
+        'objectid' => '1',
+        'type' => 'vocabulary',
+        'property' => 'name',
+        'objectindex' => '1',
+        'format' => '',
+      ],
+      [
+        'lid' => '2',
+        'textgroup' => 'taxonomy',
+        'context' => 'vocabulary:1:description',
+        'objectid' => '1',
+        'type' => 'vocabulary',
+        'property' => 'description',
+        'objectindex' => '1',
+        'format' => '',
+      ],
+      [
+        'lid' => '764',
+        'textgroup' => 'field',
+        'context' => 'field_color:blog:label',
+        'objectid' => 'blog',
+        'type' => 'field_color',
+        'property' => 'label',
+        'objectindex' => '0',
+        'format' => '',
+      ],
+    ];
+
+    $tests[0][0]['locales_target'] = [
+      [
+        'lid' => 1,
+        'language' => 'fr',
+        'translation' => 'fr - vocabulary 1',
+        'plid' => 0,
+        'plural' => 0,
+        'i18n_status' => 0,
+      ],
+      [
+        'lid' => 2,
+        'language' => 'fr',
+        'translation' => 'fr - description of vocabulary 1',
+        'plid' => 0,
+        'plural' => 0,
+        'i18n_status' => 0,
+      ],
+      [
+        'lid' => '764',
+        'translation' => 'Color',
+        'language' => 'fr',
+        'plid' => '0',
+        'plural' => '0',
+        'i18n_status' => '0',
+      ],
+    ];
+
+    $tests[0][0]['taxonomy_vocabulary'] = [
+      [
+        'vid' => 1,
+        'name' => 'vocabulary 1',
+        'machine_name' => 'vocabulary_1',
+        'description' => 'description of vocabulary 1',
+        'hierarchy' => 1,
+        'module' => 'taxonomy',
+        'weight' => 4,
+        'language' => 'und',
+        'i18n_mode' => '4',
+
+      ],
+      [
+        'vid' => 2,
+        'name' => 'vocabulary 2',
+        'machine_name' => 'vocabulary_1',
+        'description' => 'description of vocabulary 2',
+        'hierarchy' => 1,
+        'module' => 'taxonomy',
+        'weight' => 4,
+        'language' => 'und',
+        'i18n_mode' => '4',
+      ],
+    ];
+
+    $tests[0]['expected_results'] = [
+      [
+        'vid' => 1,
+        'name' => 'vocabulary 1',
+        'machine_name' => 'vocabulary_1',
+        'description' => 'description of vocabulary 1',
+        'hierarchy' => 1,
+        'module' => 'taxonomy',
+        'weight' => 4,
+        'i18n_mode' => '4',
+        'lid' => '1',
+        'type' => 'vocabulary',
+        'property' => 'name',
+        'objectid' => '1',
+        'lt_lid' => '1',
+        'translation' => 'fr - vocabulary 1',
+        'language' => 'fr',
+        'textgroup' => 'taxonomy',
+        'context' => 'vocabulary:1:name',
+        'objectindex' => '1',
+        'format' => '',
+        'ltlanguage' => 'fr',
+        'plid' => '0',
+        'plural' => '0',
+        'i18n_status' => '0',
+      ],
+      [
+        'vid' => 1,
+        'name' => 'vocabulary 1',
+        'machine_name' => 'vocabulary_1',
+        'description' => 'description of vocabulary 1',
+        'hierarchy' => 1,
+        'module' => 'taxonomy',
+        'weight' => 4,
+        'i18n_mode' => '4',
+        'lid' => '2',
+        'type' => 'vocabulary',
+        'property' => 'description',
+        'objectid' => '1',
+        'lt_lid' => '2',
+        'translation' => 'fr - description of vocabulary 1',
+        'language' => 'fr',
+        'textgroup' => 'taxonomy',
+        'context' => 'vocabulary:1:description',
+        'objectindex' => '1',
+        'format' => '',
+        'ltlanguage' => 'fr',
+        'plid' => '0',
+        'plural' => '0',
+        'i18n_status' => '0',
+      ],
+    ];
+    return $tests;
+  }
+
+}
