From 2eaf108be422dc8fd900e9f39aa77edfc926e3a3 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Thu, 17 Dec 2015 12:58:00 +0000
Subject: [PATCH] Issue #2625782 by alexpott: Infinite loop in
 ConfigurableLanguageManager->getLanguages() on language config entities
 import

---
 core/lib/Drupal/Core/Language/Language.php    | 14 ++++-
 .../LocaleConfigurableLanguageManagerTest.php | 51 +++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)
 create mode 100644 core/modules/locale/src/Tests/LocaleConfigurableLanguageManagerTest.php

diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php
index 46fb892f8a59..675ca477773f 100644
--- a/core/lib/Drupal/Core/Language/Language.php
+++ b/core/lib/Drupal/Core/Language/Language.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Language;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * An object containing the information for an interface language.
  *
@@ -151,7 +153,17 @@ public static function sort(&$languages) {
       $a_weight = $a->getWeight();
       $b_weight = $b->getWeight();
       if ($a_weight == $b_weight) {
-        return strnatcasecmp($a->getName(), $b->getName());
+        $a_name = $a->getName();
+        $b_name = $b->getName();
+        // If either name is a TranslatableMarkup object it can not be converted
+        // to a string. This is because translation requires a sorted list of
+        // languages thereby causing an infinite loop. Determine the order based
+        // on ID if this is the case.
+        if ($a_name instanceof TranslatableMarkup || $b_name instanceof TranslatableMarkup) {
+          $a_name = $a->getId();
+          $b_name = $b->getId();
+        }
+        return strnatcasecmp($a_name, $b_name);
       }
       return ($a_weight < $b_weight) ? -1 : 1;
     });
diff --git a/core/modules/locale/src/Tests/LocaleConfigurableLanguageManagerTest.php b/core/modules/locale/src/Tests/LocaleConfigurableLanguageManagerTest.php
new file mode 100644
index 000000000000..6bdbc4373143
--- /dev/null
+++ b/core/modules/locale/src/Tests/LocaleConfigurableLanguageManagerTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\locale\Tests\LocaleConfigurableLanguageManagerTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\simpletest\KernelTestBase;
+
+
+/**
+ * Tests that the configurable language manager and locale operate correctly.
+ *
+ * @group locale
+ */
+class LocaleConfigurableLanguageManagerTest extends KernelTestBase {
+
+  /**
+   * A list of modules to install for this test.
+   *
+   * @var array
+   */
+  public static $modules = ['language', 'locale'];
+
+  public function testGetLanguages() {
+    $this->installSchema('locale', ['locales_source', 'locales_target', 'locales_location']);
+    $default_language = new ConfigurableLanguage(['label' => $this->randomMachineName(), 'id' => 'default', 'weight' => 0], 'configurable_language');
+    $default_language->save();
+
+    // Set new default language.
+    \Drupal::service('language.default')->set($default_language);
+    \Drupal::service('string_translation')->setDefaultLangcode($default_language->getId());
+
+    $languages = \Drupal::service('language_manager')->getLanguages(LanguageInterface::STATE_ALL);
+    $this->assertEqual(['default', 'und', 'zxx'], array_keys($languages));
+
+    $configurableLanguage = new ConfigurableLanguage(['label' => $this->randomMachineName(), 'id' => 'test', 'weight' => 1], 'configurable_language');
+    // Simulate a configuration sync by setting the flag otherwise the locked
+    // language weights would be updated whilst saving.
+    // @see \Drupal\language\Entity\ConfigurableLanguage::postSave()
+    $configurableLanguage->setSyncing(TRUE)->save();
+
+    $languages = \Drupal::service('language_manager')->getLanguages(LanguageInterface::STATE_ALL);
+    $this->assertEqual(['default', 'test', 'und', 'zxx'], array_keys($languages));
+  }
+
+}
-- 
GitLab