diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc index 245c62b..e15fc1d 100644 --- a/core/modules/language/language.admin.inc +++ b/core/modules/language/language.admin.inc @@ -6,6 +6,7 @@ */ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Drupal\Core\Language\Language; /** * User interface for the language overview screen. @@ -199,7 +200,7 @@ function language_admin_add_form($form, &$form_state) { ), ), '#validate' => array('language_admin_add_predefined_form_validate'), - '#submit' => array('language_admin_add_form_submit'), + '#submit' => array('language_admin_add_predefined_form_submit'), ); $form['custom_language'] = array( @@ -215,7 +216,7 @@ function language_admin_add_form($form, &$form_state) { '#type' => 'submit', '#value' => t('Add custom language'), '#validate' => array('language_admin_add_custom_form_validate'), - '#submit' => array('language_admin_add_form_submit'), + '#submit' => array('language_admin_add_custom_form_submit'), ); return $form; @@ -325,34 +326,35 @@ function language_admin_add_custom_form_validate($form, &$form_state) { } /** - * Process the custom and predefined language addition form submission. + * Process the custom language addition form submission. */ -function language_admin_add_form_submit($form, &$form_state) { - $langcode = $form_state['values']['predefined_langcode']; - if ($langcode == 'custom') { - $langcode = $form_state['values']['langcode']; - // Custom language form. - $language = (object) array( - 'langcode' => $langcode, - 'name' => $form_state['values']['name'], - 'direction' => $form_state['values']['direction'], - ); - } - else { - include_once DRUPAL_ROOT . '/core/includes/standard.inc'; - $predefined = standard_language_list(); - $language = (object) array( - 'langcode' => $langcode, - ); - } - // Save the language and inform the user that it happened. - $language = language_save($language); - drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => $language->name))); - - // Tell the user they have the option to add a language switcher block - // to their theme so they can switch between the languages. - drupal_set_message(t('Use one of the language switcher blocks to allow site visitors to switch between languages. You can enable these blocks on the block administration page.', array('@block-admin' => 'admin/structure/block'))); +function language_admin_add_custom_form_submit($form, &$form_state) { + $langcode = $form_state['values']['langcode']; + // Custom language form. + $language = new Language(array( + 'langcode' => $langcode, + 'name' => $form_state['values']['name'], + 'direction' => $form_state['values']['direction'], + )); + language_save($language); + drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => $form_state['values']['name']))); + $form_state['redirect'] = 'admin/config/regional/language'; +} +/** + * Process the predefined language addition form submission. + */ +function language_admin_add_predefined_form_submit($form, &$form_state) { + // Predefined language selection. + $langcode = $form_state['values']['predefined_langcode']; + include_once DRUPAL_ROOT . '/core/includes/standard.inc'; + $predefined = standard_language_list(); + $language = new Language(array( + 'langcode' => $langcode, + 'name' => NULL, + )); + language_save($language); + drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => t($predefined[$langcode][0])))); $form_state['redirect'] = 'admin/config/regional/language'; } diff --git a/core/modules/language/language.module b/core/modules/language/language.module index a94876e..968183f 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -419,6 +419,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('User admin language'), + 'description' => t("Follow the user's admin language preference."), + ); + return $negotiation_info; } diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc index 48a8083..e83adc0 100644 --- a/core/modules/language/language.negotiation.inc +++ b/core/modules/language/language.negotiation.inc @@ -31,6 +31,11 @@ const LANGUAGE_NEGOTIATION_URL_FALLBACK = 'language-url-fallback'; 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. */ const LANGUAGE_NEGOTIATION_SESSION = 'language-session'; @@ -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; } @@ -162,6 +167,27 @@ function language_from_user($languages) { } /** + * 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. * * @param $languages diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php index d12bdfa..ff6ffc4 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php @@ -196,6 +196,107 @@ class LanguageUILanguageNegotiationTest extends WebTestBase { $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 31ca843..4199c07 100644 --- a/core/modules/user/lib/Drupal/user/AccountFormController.php +++ b/core/modules/user/lib/Drupal/user/AccountFormController.php @@ -205,6 +205,8 @@ abstract class AccountFormController extends EntityFormController { $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; @@ -218,12 +220,20 @@ abstract class AccountFormController extends EntityFormController { $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 42f2d29..74e2bf3 100644 --- a/core/modules/user/lib/Drupal/user/User.php +++ b/core/modules/user/lib/Drupal/user/User.php @@ -122,6 +122,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. * * @var integer diff --git a/core/modules/user/user.install b/core/modules/user/user.install index abb985b..9f0e3b1 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, @@ -475,5 +482,19 @@ function user_update_8003() { } /** + * Creates a preferred_admin_langcode column. + */ +function user_update_8004() { + $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 44cb266..b8f5c36 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -2962,14 +2962,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();