From 61ca2c2124f89adf24f1fed0fa1ce4a9bff77b3f Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Mon, 24 Aug 2020 09:46:01 +1000
Subject: [PATCH] Issue #3112249 by quietone, shaktik, ravi.shankar,
 rajiv.singh, daffie: Migrate d7 menu translation

---
 .../migrations/d7_menu_translation.yml        |  31 +++++
 .../config_translation.migrate_drupal.yml     |   1 +
 .../migrate_drupal/tests/fixtures/drupal7.php | 112 +++++++++++++++++-
 .../tests/src/Functional/d7/Upgrade7Test.php  |   2 +-
 core/modules/system/migrations/d7_menu.yml    |   4 +
 .../system/src/Plugin/migrate/source/Menu.php |  10 +-
 .../migrate/source/d7/MenuTranslation.php     |  83 +++++++++++++
 .../src/Kernel/Migrate/d7/MigrateMenuTest.php |  16 ++-
 .../Migrate/d7/MigrateMenuTranslationTest.php |  67 +++++++++++
 .../Kernel/Plugin/migrate/source/MenuTest.php |  13 ++
 .../migrate/source/d7/MenuTranslationTest.php | 102 ++++++++++++++++
 11 files changed, 430 insertions(+), 11 deletions(-)
 create mode 100644 core/modules/config_translation/migrations/d7_menu_translation.yml
 create mode 100644 core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
 create mode 100644 core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTranslationTest.php
 create mode 100644 core/modules/system/tests/src/Kernel/Plugin/migrate/source/d7/MenuTranslationTest.php

diff --git a/core/modules/config_translation/migrations/d7_menu_translation.yml b/core/modules/config_translation/migrations/d7_menu_translation.yml
new file mode 100644
index 000000000000..129ad1807495
--- /dev/null
+++ b/core/modules/config_translation/migrations/d7_menu_translation.yml
@@ -0,0 +1,31 @@
+id: d7_menu_translation
+label: Menu translation
+migration_tags:
+  - Drupal 7
+  - Configuration
+  - Multilingual
+source:
+  plugin: d7_menu_translation
+process:
+  id:
+    -
+      plugin: migration_lookup
+      migration: d7_menu
+      source: menu_name
+    -
+      plugin: skip_on_empty
+      method: row
+  langcode: language
+  property:
+    plugin: static_map
+    source: property
+    map:
+      title: label
+      description: description
+  translation: translation
+destination:
+  plugin: entity:menu
+  destination_module: config_translation
+migration_dependencies:
+  required:
+    - d7_menu
diff --git a/core/modules/config_translation/migrations/state/config_translation.migrate_drupal.yml b/core/modules/config_translation/migrations/state/config_translation.migrate_drupal.yml
index 5c7b5fddc9e0..52552137a14e 100644
--- a/core/modules/config_translation/migrations/state/config_translation.migrate_drupal.yml
+++ b/core/modules/config_translation/migrations/state/config_translation.migrate_drupal.yml
@@ -4,6 +4,7 @@ finished:
   7:
     i18n_variable: config_translation
     i18n_taxonomy: config_translation
+    i18n_menu: config_translation
 not_finished:
   6:
     # language content comment settings.
diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
index f7d136861fc5..af0d02f34338 100644
--- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
@@ -19382,6 +19382,36 @@
   'objectindex' => '0',
   'format' => '',
 ))
+->values(array(
+  'lid' => '800',
+  'textgroup' => 'menu',
+  'context' => 'menu:main-menu:title',
+  'objectid' => 'main-menu',
+  'type' => 'menu',
+  'property' => 'title',
+  'objectindex' => '0',
+  'format' => '',
+))
+->values(array(
+  'lid' => '801',
+  'textgroup' => 'menu',
+  'context' => 'menu:main-menu:description',
+  'objectid' => 'main-menu',
+  'type' => 'menu',
+  'property' => 'description',
+  'objectindex' => '0',
+  'format' => '',
+))
+->values(array(
+  'lid' => '802',
+  'textgroup' => 'menu',
+  'context' => 'menu:menu-test-menu:description',
+  'objectid' => 'menu-test-menu',
+  'type' => 'menu',
+  'property' => 'description',
+  'objectindex' => '0',
+  'format' => '',
+))
 ->execute();
 $connection->schema()->createTable('i18n_translation_set', array(
   'fields' => array(
@@ -20950,6 +20980,46 @@
   'plural' => '0',
   'i18n_status' => '0',
 ))
+->values(array(
+  'lid' => '800',
+  'translation' => 'is - Main menu',
+  'language' => 'is',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '801',
+  'translation' => 'is - Main menu description',
+  'language' => 'is',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '800',
+  'translation' => 'fr - Main menu',
+  'language' => 'fr',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '801',
+  'translation' => 'fr - Main menu description',
+  'language' => 'fr',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '802',
+  'translation' => 'fr - Test menu description',
+  'language' => 'fr',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
 ->execute();
 $connection->schema()->createTable('menu_custom', array(
   'fields' => array(
@@ -21012,6 +21082,13 @@
   'language' => 'und',
   'i18n_mode' => '0',
 ))
+->values(array(
+  'menu_name' => 'menu-fixedlang',
+  'title' => 'FixedLang',
+  'description' => '',
+  'language' => 'is',
+  'i18n_mode' => '2',
+))
 ->values(array(
   'menu_name' => 'menu-test-menu',
   'title' => 'Test Menu',
@@ -29753,9 +29830,9 @@
   'module' => 'system',
   'hidden' => '-1',
   'external' => '0',
-  'has_children' => '0',
+  'has_children' => '1',
   'expanded' => '0',
-  'weight' => '2',
+  'weight' => '1',
   'depth' => '2',
   'customized' => '0',
   'p1' => '5',
@@ -32299,7 +32376,7 @@
   'mlid' => '479',
   'plid' => '0',
   'link_path' => 'node/2',
-  'router_path' => 'node/2',
+  'router_path' => 'node/%',
   'link_title' => 'node link test',
   'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:6:"node 2";}}',
   'module' => 'menu',
@@ -32584,6 +32661,35 @@
   'language' => 'und',
   'i18n_tsid' => '0',
 ))
+->values(array(
+  'menu_name' => 'management',
+  'mlid' => '535',
+  'plid' => '44',
+  'link_path' => 'admin/structure/menu/manage/menu-fixedlang',
+  'router_path' => 'admin/structure/menu/manage/%',
+  'link_title' => 'FixedLang',
+  'options' => 'a:0:{}',
+  'module' => 'menu',
+  'hidden' => '0',
+  'external' => '0',
+  'has_children' => '0',
+  'expanded' => '0',
+  'weight' => '0',
+  'depth' => '4',
+  'customized' => '0',
+  'p1' => '1',
+  'p2' => '20',
+  'p3' => '44',
+  'p4' => '535',
+  'p5' => '0',
+  'p6' => '0',
+  'p7' => '0',
+  'p8' => '0',
+  'p9' => '0',
+  'updated' => '0',
+  'language' => 'und',
+  'i18n_tsid' => '0',
+))
 ->execute();
 $connection->schema()->createTable('menu_router', array(
   'fields' => array(
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
index 69f7d943cd02..388e989d51ea 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
@@ -99,7 +99,7 @@ protected function getEntityCounts() {
       'shortcut' => 6,
       'shortcut_set' => 2,
       'action' => 19,
-      'menu' => 6,
+      'menu' => 7,
       'taxonomy_term' => 24,
       'taxonomy_vocabulary' => 7,
       'path_alias' => 8,
diff --git a/core/modules/system/migrations/d7_menu.yml b/core/modules/system/migrations/d7_menu.yml
index ce97f656b160..585319358d0b 100644
--- a/core/modules/system/migrations/d7_menu.yml
+++ b/core/modules/system/migrations/d7_menu.yml
@@ -17,5 +17,9 @@ process:
       user-menu: account
   label: title
   description: description
+  langcode:
+    plugin: default_value
+    source: language
+    default_value: und
 destination:
   plugin: entity:menu
diff --git a/core/modules/system/src/Plugin/migrate/source/Menu.php b/core/modules/system/src/Plugin/migrate/source/Menu.php
index a97878fa4af1..14296f1ade11 100644
--- a/core/modules/system/src/Plugin/migrate/source/Menu.php
+++ b/core/modules/system/src/Plugin/migrate/source/Menu.php
@@ -25,11 +25,19 @@ public function query() {
    * {@inheritdoc}
    */
   public function fields() {
-    return [
+    $fields = [
       'menu_name' => $this->t('The menu name. Primary key.'),
       'title' => $this->t('The human-readable name of the menu.'),
       'description' => $this->t('A description of the menu'),
     ];
+
+    if ($this->database->schema()->fieldExists('menu_custom', 'language')) {
+      $fields += [
+        'language' => $this->t('Menu language.'),
+        'i8n_mode' => $this->t('Menu i18n mode.'),
+      ];
+    }
+    return $fields;
   }
 
   /**
diff --git a/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php b/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
new file mode 100644
index 000000000000..534e47e54699
--- /dev/null
+++ b/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Drupal\system\Plugin\migrate\source\d7;
+
+use Drupal\system\Plugin\migrate\source\Menu;
+
+/**
+ * Menu translation source from database.
+ *
+ * @MigrateSource(
+ *   id = "d7_menu_translation",
+ *   source_module = "i18n_menu"
+ * )
+ */
+class MenuTranslation extends Menu {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = parent::query();
+    $query
+      ->fields('i18n', [
+        'lid',
+        'textgroup',
+        'context',
+        'objectid',
+        'type',
+        'property',
+        'objectindex',
+        'format',
+      ])
+      ->fields('lt', [
+        'lid',
+        'translation',
+        'language',
+        'plid',
+        'plural',
+        'i18n_status',
+      ])
+      ->condition('i18n.textgroup', 'menu')
+      ->isNotNull('lt.lid');
+
+    $query->addField('m', 'language', 'm_language');
+    $query->leftJoin('i18n_string', 'i18n', 'i18n.objectid = m.menu_name');
+    $query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    $fields = [
+      'lid' => $this->t('Language string ID'),
+      'language' => $this->t('Menu language'),
+      'textgroup' => $this->t('A module defined group of translations'),
+      'context' => $this->t('Full string ID for quick search: type:objectid:property.'),
+      'objectid' => $this->t('Object ID'),
+      'type' => $this->t('Object type for this string'),
+      'property' => $this->t('Object property for this string'),
+      'objectindex' => $this->t('Integer value of Object ID'),
+      'format' => $this->t('The {filter_format}.format of the string'),
+      'translation' => $this->t('Translation'),
+      'plid' => $this->t('Parent lid'),
+      'i18n_status' => $this->t('Translation needs update'),
+    ] + parent::fields();
+    return $fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids = parent::getIds();
+    $ids['language']['type'] = 'string';
+    $ids['language']['alias'] = 'lt';
+    $ids['property']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTest.php b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTest.php
index eb80f42a09aa..b0cd4ff2a906 100644
--- a/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTest.php
+++ b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTest.php
@@ -26,14 +26,17 @@ protected function setUp(): void {
    *
    * @param $id
    *   The menu ID.
+   * @param string $language
+   *   The menu language.
    * @param $label
    *   The menu label.
    * @param $description
    *   The menu description.
    */
-  protected function assertEntity($id, $label, $description) {
+  protected function assertEntity($id, $language, $label, $description) {
     $navigation_menu = Menu::load($id);
     $this->assertSame($id, $navigation_menu->id());
+    $this->assertSame($language, $navigation_menu->language()->getId());
     $this->assertSame($label, $navigation_menu->label());
     $this->assertSame($description, $navigation_menu->getDescription());
   }
@@ -42,11 +45,12 @@ protected function assertEntity($id, $label, $description) {
    * Tests the Drupal 7 menu to Drupal 8 migration.
    */
   public function testMenu() {
-    $this->assertEntity('main', 'Main menu', 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.');
-    $this->assertEntity('admin', 'Management', 'The <em>Management</em> menu contains links for administrative tasks.');
-    $this->assertEntity('menu-test-menu', 'Test Menu', 'Test menu description.');
-    $this->assertEntity('tools', 'Navigation', 'The <em>Navigation</em> menu contains links intended for site visitors. Links are added to the <em>Navigation</em> menu automatically by some modules.');
-    $this->assertEntity('account', 'User menu', 'The <em>User</em> menu contains links related to the user\'s account, as well as the \'Log out\' link.');
+    $this->assertEntity('main', 'und', 'Main menu', 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.');
+    $this->assertEntity('admin', 'und', 'Management', 'The <em>Management</em> menu contains links for administrative tasks.');
+    $this->assertEntity('menu-test-menu', 'und', 'Test Menu', 'Test menu description.');
+    $this->assertEntity('tools', 'und', 'Navigation', 'The <em>Navigation</em> menu contains links intended for site visitors. Links are added to the <em>Navigation</em> menu automatically by some modules.');
+    $this->assertEntity('account', 'und', 'User menu', 'The <em>User</em> menu contains links related to the user\'s account, as well as the \'Log out\' link.');
+    $this->assertEntity('menu-fixedlang', 'is', 'FixedLang', '');
 
     // Test that we can re-import using the ConfigEntityBase destination.
     Database::getConnection('default', 'migrate')
diff --git a/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTranslationTest.php b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTranslationTest.php
new file mode 100644
index 000000000000..165c0a579ebf
--- /dev/null
+++ b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateMenuTranslationTest.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Drupal\Tests\system\Kernel\Migrate\d7;
+
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+
+/**
+ * Tests menu translation migration.
+ *
+ * @group migrate_drupal_7
+ */
+class MigrateMenuTranslationTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'config_translation',
+    'language',
+    'locale',
+    'menu_link_content',
+    // Required for translation migrations.
+    'migrate_drupal_multilingual',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installSchema('locale',
+      ['locales_source', 'locales_target', 'locales_location']);
+    $this->executeMigrations([
+      'language',
+      'd7_menu',
+      'd7_menu_translation',
+    ]);
+  }
+
+  /**
+   * Tests migration of menu translations.
+   */
+  public function testMenuTranslation() {
+    $language_manager = \Drupal::service('language_manager');
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'system.menu.main');
+    $this->assertSame('is - Main menu', $config_translation->get('label'));
+    $this->assertSame('is - Main menu description', $config_translation->get('description'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'system.menu.main');
+    $this->assertSame('fr - Main menu', $config_translation->get('label'));
+    $this->assertSame('fr - Main menu description', $config_translation->get('description'));
+
+    // Translate and localize menu.
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'system.menu.menu-test-menu');
+    $this->assertSame('fr - Test menu description', $config_translation->get('description'));
+
+    // No translations for fixed language menu.
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'menu-fixedlang');
+    $this->assertNull($config_translation->get('description'));
+    $this->assertNull($config_translation->get('label'));
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'menu-fixedlang');
+    $this->assertNull($config_translation->get('description'));
+    $this->assertNull($config_translation->get('label'));
+  }
+
+}
diff --git a/core/modules/system/tests/src/Kernel/Plugin/migrate/source/MenuTest.php b/core/modules/system/tests/src/Kernel/Plugin/migrate/source/MenuTest.php
index 3917b37cc085..0dc4082df722 100644
--- a/core/modules/system/tests/src/Kernel/Plugin/migrate/source/MenuTest.php
+++ b/core/modules/system/tests/src/Kernel/Plugin/migrate/source/MenuTest.php
@@ -41,6 +41,19 @@ public function providerSource() {
     // The expected results are identical to the source data.
     $tests[0]['expected_data'] = $tests[0]['source_data']['menu_custom'];
 
+    $tests[1] = $tests[0];
+    $tests[1]['source_data']['menu_custom'][0] +=
+      [
+        'language' => 'it',
+        'i18n_mode' => 1,
+      ];
+    $tests[1]['source_data']['menu_custom'][1] +=
+      [
+        'language' => 'fr',
+        'i18n_mode' => 2,
+      ];
+    $tests[1]['expected_data'] = $tests[1]['source_data']['menu_custom'];
+
     return $tests;
   }
 
diff --git a/core/modules/system/tests/src/Kernel/Plugin/migrate/source/d7/MenuTranslationTest.php b/core/modules/system/tests/src/Kernel/Plugin/migrate/source/d7/MenuTranslationTest.php
new file mode 100644
index 000000000000..bb7ee5404664
--- /dev/null
+++ b/core/modules/system/tests/src/Kernel/Plugin/migrate/source/d7/MenuTranslationTest.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\Tests\system\Kernel\Plugin\migrate\source\d7;
+
+use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
+
+/**
+ * Tests the menu translation source plugin.
+ *
+ * @covers Drupal\system\Plugin\migrate\source\d7\MenuTranslation
+ * @group system
+ */
+class MenuTranslationTest extends MigrateSqlSourceTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system', 'migrate_drupal'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function providerSource() {
+    $tests = [];
+    $tests[0]['source_data']['menu_custom'] = [
+      [
+        'menu_name' => 'navigation',
+        'title' => 'Navigation',
+        'description' => 'Navigation description',
+        'language' => 'und',
+        'i18n_mode' => 0,
+      ],
+      [
+        'menu_name' => 'menu-name-2',
+        'title' => 'menu custom value 2',
+        'description' => 'menu custom description value 2',
+        'language' => 'und',
+        'i18n_mode' => 0,
+      ],
+    ];
+    $tests[0]['source_data']['i18n_string'] = [
+      [
+        'lid' => 1,
+        'textgroup' => 'menu',
+        'context' => ' menu:navigation:description',
+        'objectid' => 'navigation',
+        'type' => 'menu',
+        'property' => 'description',
+        'objectindex' => 0,
+        'format' => '',
+      ],
+      [
+        'lid' => 2,
+        'textgroup' => 'menu',
+        'context' => ' menu:navigation:title',
+        'objectid' => 'navigation',
+        'type' => 'menu',
+        'property' => 'title',
+        'objectindex' => 0,
+        'format' => '',
+      ],
+    ];
+    $tests[0]['source_data']['locales_target'] = [
+      [
+        'lid' => 1,
+        'translation' => 'navigation description translation',
+        'language' => 'fr',
+        'plid' => 0,
+        'plural' => 0,
+        'i18n_status' => 0,
+      ],
+      [
+        'lid' => 2,
+        'translation' => 'navigation translation',
+        'language' => 'fr',
+        'plid' => 0,
+        'plural' => 0,
+        'i18n_status' => 0,
+      ],
+    ];
+    $tests[0]['expected_results'] = [
+      [
+        'menu_name' => 'navigation',
+        'type' => 'menu',
+        'property' => 'description',
+        'translation' => 'navigation description translation',
+        'language' => 'fr',
+        'objectid' => 'navigation',
+      ],
+      [
+        'menu_name' => 'navigation',
+        'type' => 'menu',
+        'property' => 'title',
+        'translation' => 'navigation translation',
+        'language' => 'fr',
+        'objectid' => 'navigation',
+      ],
+    ];
+    return $tests;
+  }
+
+}
-- 
GitLab