Commit 932a453f authored by larowlan's avatar larowlan

Issue #3035392 by quietone, Gábor Hojtsy, masipila: Migrate vocabulary...

Issue #3035392 by quietone, Gábor Hojtsy, masipila: Migrate vocabulary translations and taxonomy term references for Drupal 7 node translations
parent 3bd3a190
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
......@@ -3,6 +3,7 @@ finished:
i18nprofile: config_translation
7:
i18n_variable: config_translation
i18n_taxonomy: config_translation
not_finished:
6:
# language content comment settings.
......@@ -24,5 +25,3 @@ not_finished:
# field labels and descriptions, field options.
i18n_field: config_translation
i18n_string: config_translation
# localized. vocabulary language settings, taxonomy term language.
i18n_taxonomy: config_tanslation
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
......@@ -39,8 +39,8 @@ not_finished:
# Menu links.
# See https://www.drupal.org/project/drupal/issues/3008028
i18n_menu: content_translation
# Migrate taxonomy term references
# https://www.drupal.org/project/drupal/issues/3035392
# @TODO: Remove when taxonomy term field translations are migrated.
# See https://www.drupal.org/project/drupal/issues/3073050
i18n_taxonomy: content_translation
# Node revision translations.
# https://www.drupal.org/project/drupal/issues/2746541
......
......@@ -18790,16 +18790,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',
......@@ -18807,7 +18799,7 @@
))
->values(array(
'lid' => '89',
'translation' => 'fr - VocabFixed',
'translation' => 'fr - VocabLocalized',
'language' => 'fr',
'plid' => '0',
'plural' => '0',
......@@ -18815,39 +18807,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',
......@@ -18867,7 +18827,7 @@
'language' => 'fr',
'plid' => '0',
'plural' => '0',
'i18n_status' => '0',
'i18n_status' => '1',
))
->values(array(
'lid' => '163',
......@@ -18883,7 +18843,7 @@
'language' => 'fr',
'plid' => '0',
'plural' => '0',
'i18n_status' => '0',
'i18n_status' => '1',
))
->values(array(
'lid' => '684',
......@@ -18891,7 +18851,7 @@
'language' => 'fr',
'plid' => '0',
'plural' => '0',
'i18n_status' => '0',
'i18n_status' => '1',
))
->values(array(
'lid' => '761',
......@@ -18982,23 +18942,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',
......@@ -19006,7 +18966,7 @@
'i18n_status' => '0',
))
->values(array(
'lid' => '88',
'lid' => '92',
'translation' => 'is - Vocabulary translate option',
'language' => 'is',
'plid' => '0',
......@@ -19014,48 +18974,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',
......@@ -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,16 @@ 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());
$term_ref = $node->get('field_vocab_fixed')->target_id;
$this->assertSame('24', $term_ref);
$this->assertTrue($node->hasTranslation('is'), "Node 2 has an Icelandic translation");
$translation = $node->getTranslation('is');
......@@ -189,6 +205,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 = $translation->get('field_vocab_fixed')->target_id;
$this->assertNulL($term_ref);
// Test that content_translation_source is set.
$manager = $this->container->get('content_translation.manager');
......
<?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;
}
}
<?php
namespace Drupal\taxonomy\Plugin\migrate\source\d7;
/**
* 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', 'CAST (v.vid AS CHAR(222))= i18n.objectid');
$query->innerJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
$query
->condition('type', 'vocabulary')
->fields('lt')
->fields('i18n');
$query->addField('lt', 'lid', 'lt_lid');
if ($this->getDatabase()
->schema()
->fieldExists('taxonomy_vocabulary', 'language')) {
$query->addField('v', 'language', '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.'),
'v_language' => $this->t('Language from the taxonomy_vocabulary table.'),
'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'),
'language' => $this->t('Language code from locales_target 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 getIds() {
$ids = [];
$ids['language']['type'] = 'string';
$ids['language']['alias'] = 'lt';
$ids['property']['type'] = 'string';
return parent::getIds() + $ids;
}
}
<?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', []);
}
}
<?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 {