From 6ed142d1f392e6f541b897598d0de23ca8599a7e Mon Sep 17 00:00:00 2001
From: Dries <dries@buytaert.net>
Date: Fri, 31 Aug 2012 11:23:58 -0400
Subject: [PATCH] - Patch #322995 by Schnitzel, c31ck, webflo, penyaskito:
 provide a distinct administration user interface language option.

---
 core/modules/language/language.module         |   9 ++
 .../modules/language/language.negotiation.inc |  30 +++++-
 .../LanguageUILanguageNegotiationTest.php     | 101 ++++++++++++++++++
 .../lib/Drupal/user/AccountFormController.php |  12 ++-
 core/modules/user/lib/Drupal/user/User.php    |   7 ++
 core/modules/user/user.install                |  20 ++++
 core/modules/user/user.module                 |  16 ++-
 7 files changed, 189 insertions(+), 6 deletions(-)

diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index f90ef93b3a6c..e91198009788 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -411,6 +411,15 @@ function language_language_negotiation_info() {
     'description' => t('Use an already detected language for URLs if none is found.'),
   );
 
+  $negotiation_info[LANGUAGE_NEGOTIATION_USER_ADMIN] = array(
+    'types' => array(LANGUAGE_TYPE_INTERFACE),
+    'callbacks' => array('negotiation' => 'language_from_user_admin'),
+    'file' => $file,
+    'weight' => 10,
+    'name' => t('Account administration pages'),
+    'description' => t('Account administration pages language setting.'),
+  );
+
   return $negotiation_info;
 }
 
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
index b78dff2ded3d..549e80ab18d4 100644
--- a/core/modules/language/language.negotiation.inc
+++ b/core/modules/language/language.negotiation.inc
@@ -30,6 +30,11 @@
  */
 const LANGUAGE_NEGOTIATION_USER = 'language-user';
 
+/**
+ * The language is set based on the user admin language settings.
+ */
+const LANGUAGE_NEGOTIATION_USER_ADMIN = 'language-user-admin';
+
 /**
  * The language is set based on the request/session parameters.
  */
@@ -150,10 +155,10 @@ function language_from_browser($languages) {
  *   A valid language code on success, FALSE otherwise.
  */
 function language_from_user($languages) {
-  // User preference (only for logged users).
+  // User preference (only for authenticated users).
   global $user;
 
-  if ($user->uid && !empty($user->preferred_langcode)) {
+  if ($user->uid && !empty($user->preferred_langcode) && isset($languages[$user->preferred_langcode])) {
     return $user->preferred_langcode;
   }
 
@@ -161,6 +166,27 @@ function language_from_user($languages) {
   return FALSE;
 }
 
+/**
+ * Identifies admin language from the user preferences.
+ *
+ * @param $languages
+ *   An array of valid language objects.
+ *
+ * @return
+ *   A valid language code on success, FALSE otherwise.
+ */
+function language_from_user_admin($languages) {
+  // User preference (only for authenticated users).
+  global $user;
+
+  if ($user->uid && !empty($user->preferred_admin_langcode) && isset($languages[$user->preferred_admin_langcode]) && path_is_admin(current_path())) {
+    return $user->preferred_admin_langcode;
+  }
+
+  // No language preference from the user or not on an admin path.
+  return FALSE;
+}
+
 /**
  * Identify language from a request/session parameter.
  *
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index 61235aa55ad9..ec8a9df1b4b2 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -197,6 +197,107 @@ function testUILanguageNegotiation() {
     $this->drupalGet("$langcode_unknown/admin/config", array(), $http_header_browser_fallback);
     $this->assertResponse(404, "Unknown language path prefix should return 404");
 
+    // Set preferred langcode for user to NULL.
+    $account = $this->loggedInUser;
+    $account->preferred_langcode = NULL;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => array(),
+        'message' => 'USER > DEFAULT: no preferred user language setting, the UI language is default',
+      ),
+    );
+
+    // Set preferred langcode for user to unknown language.
+    $account = $this->loggedInUser;
+    $account->preferred_langcode = $langcode_unknown;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => array(),
+        'message' => 'USER > DEFAULT: invalid preferred user language setting, the UI language is default',
+      ),
+    );
+
+
+    // Set preferred langcode for user to non default.
+    $account->preferred_langcode = $langcode;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $language_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_USER,
+        'http_header' => array(),
+        'message' => 'USER > DEFAULT: defined prefereed user language setting, the UI language is based on user setting',
+      ),
+    );
+
+    foreach ($tests as $test) {
+      $this->runTest($test);
+    }
+
+    // Set preferred admin langcode for user to NULL.
+    $account->preferred_admin_langcode = NULL;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => array(),
+        'message' => 'USER ADMIN > DEFAULT: no preferred user admin language setting, the UI language is default',
+      ),
+    );
+
+    // Set preferred admin langcode for user to unknown language.
+    $account->preferred_admin_langcode = $langcode_unknown;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => array(),
+        'message' => 'USER ADMIN > DEFAULT: invalid preferred user admin language setting, the UI language is default',
+      ),
+    );
+
+    // Set preferred admin langcode for user to non default.
+    $account->preferred_admin_langcode = $langcode;
+    $account->save();
+
+    $tests = array(
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $language_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_USER_ADMIN,
+        'http_header' => array(),
+        'message' => 'USER ADMIN > DEFAULT: defined prefereed user admin language setting, the UI language is based on user setting',
+      ),
+    );
+
+    foreach ($tests as $test) {
+      $this->runTest($test);
+    }
+
     // Setup for domain negotiation, first configure the language to have domain
     // URL.
     $edit = array("domain[$langcode]" => $language_domain);
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index 2c6f1820b4d1..3a3ecaacf901 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -206,6 +206,8 @@ public function form(array $form, array &$form_state, EntityInterface $account)
 
     $user_preferred_language = $register ? $language_interface : user_preferred_language($account);
 
+    $user_preferred_admin_language = $register ? $language_interface : user_preferred_language($account, 'admin');
+
     // Is default the interface language?
     include_once DRUPAL_ROOT . '/core/includes/language.inc';
     $interface_language_is_default = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_DEFAULT;
@@ -219,12 +221,20 @@ public function form(array $form, array &$form_state, EntityInterface $account)
 
     $form['language']['preferred_langcode'] = array(
       '#type' => 'language_select',
-      '#title' => t('Language'),
+      '#title' => t('Site language'),
       '#languages' => LANGUAGE_CONFIGURABLE,
       '#default_value' => $user_preferred_language->langcode,
       '#description' => $interface_language_is_default ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
     );
 
+    $form['language']['preferred_admin_langcode'] = array(
+      '#type' => 'language_select',
+      '#title' => t('Administration pages language'),
+      '#languages' => LANGUAGE_CONFIGURABLE,
+      '#default_value' => $user_preferred_admin_language->langcode,
+      '#access' => user_access('access administration pages', $account),
+    );
+
     // User entities contain both a langcode property (for identifying the
     // language of the entity data) and a preferred_langcode property (see
     // above). Rather than provide a UI forcing the user to choose both
diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/User.php
index 42f2d29f3f76..74e2bf3ecaae 100644
--- a/core/modules/user/lib/Drupal/user/User.php
+++ b/core/modules/user/lib/Drupal/user/User.php
@@ -121,6 +121,13 @@ class User extends Entity {
    */
   public $preferred_langcode = LANGUAGE_NOT_SPECIFIED;
 
+  /**
+   * The user's preferred langcode for viewing administration pages.
+   *
+   * @var string
+   */
+  public $preferred_admin_langcode = LANGUAGE_NOT_SPECIFIED;
+
   /**
    * The file ID of the user's picture.
    *
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 920214512117..67957da88a0c 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -224,6 +224,13 @@ function user_schema() {
         'default' => '',
         'description' => 'The {language}.langcode that the user prefers for receiving emails and viewing the site.',
       ),
+      'preferred_admin_langcode' => array(
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The {language}.langcode that the user prefers for viewing administration pages.',
+      ),
       'picture' => array(
         'type' => 'int',
         'not null' => TRUE,
@@ -505,6 +512,19 @@ function user_update_8004() {
   }
 }
 
+/**
+ * Creates a preferred_admin_langcode column.
+ */
+function user_update_8005() {
+   $spec = array(
+    'description' => 'The {language}.langcode that the user prefers for viewing administration pages.',
+    'type' => 'varchar',
+    'length' => 12,
+    'not null' => TRUE,
+    'default' => '',
+  );
+  db_add_field('users', 'preferred_admin_langcode', $spec);
+}
 /**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index f7cef205cfe2..81ad706bef0a 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -2950,14 +2950,24 @@ function theme_user_signature($variables) {
  *
  * @param $account
  *   User account to look up language for.
+ * @param $type
+ *   Optional string to define which preferred langcode should be used.
+ *   Default to 'preferred_langcode' property.
+ *   If set 'preferred_$type_langcode' is used.
  * @param $default
  *   Optional default language object to return if the account
  *   has no valid language.
  */
-function user_preferred_language($account, $default = NULL) {
+function user_preferred_language($account, $type = NULL, $default = NULL) {
   $language_list = language_list();
-  if (!empty($account->preferred_langcode) && isset($language_list[$account->preferred_langcode])) {
-    return $language_list[$account->preferred_langcode];
+  if (isset($type)) {
+    $preferred_langcode = $account->{'preferred_' . $type . '_langcode'};
+  }
+  else {
+    $preferred_langcode = $account->preferred_langcode;
+  }
+  if (!empty($preferred_langcode) && isset($language_list[$preferred_langcode])) {
+    return $language_list[$preferred_langcode];
   }
   else {
     return $default ? $default : language_default();
-- 
GitLab