summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorNathaniel Catchpole <catch@35733.no-reply.drupal.org>2014-01-15 16:27:37 +0000
committerNathaniel Catchpole <catch@35733.no-reply.drupal.org>2014-01-15 16:27:37 +0000
commit0b55dcd84190efb23e9db99e9fc135979aeec9bc (patch)
treec4e4e488efb2282af2988996a9d0acebee4eb2e1
parent37723a56fbcfcbb618b7fae279a2c7150f6fc360 (diff)
downloaddrupal-0b55dcd84190efb23e9db99e9fc135979aeec9bc.tar.gz
drupal-0b55dcd84190efb23e9db99e9fc135979aeec9bc.zip
Issue #1862202 by plach, Berdir, katbailey, ParisLiakos, alexpott, chx, sun, larowlan, Gábor Hojtsy, cosmicdreams, vijaycs85, YesCT, penyaskito, andypost, Albert Volkman, joelpitett: Objectify the language system.
-rw-r--r--core/core.services.yml9
-rw-r--r--core/includes/bootstrap.inc214
-rw-r--r--core/includes/common.inc11
-rw-r--r--core/includes/install.core.inc24
-rw-r--r--core/includes/language.inc551
-rw-r--r--core/includes/theme.inc4
-rw-r--r--core/includes/update.inc13
-rw-r--r--core/lib/Drupal.php2
-rw-r--r--core/lib/Drupal/Component/Utility/UserAgent.php142
-rw-r--r--core/lib/Drupal/Core/Datetime/Date.php12
-rw-r--r--core/lib/Drupal/Core/Entity/EntityManager.php8
-rw-r--r--core/lib/Drupal/Core/Entity/EntityViewBuilder.php18
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php2
-rw-r--r--core/lib/Drupal/Core/Language/Language.php17
-rw-r--r--core/lib/Drupal/Core/Language/LanguageManager.php295
-rw-r--r--core/lib/Drupal/Core/Language/LanguageManagerInterface.php168
-rw-r--r--core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php2
-rw-r--r--core/lib/Drupal/Core/Path/AliasManager.php4
-rw-r--r--core/lib/Drupal/Core/Plugin/DefaultPluginManager.php20
-rw-r--r--core/lib/Drupal/Core/StringTranslation/TranslationManager.php31
-rw-r--r--core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php2
-rw-r--r--core/lib/Drupal/Core/StringTranslation/Translator/FileTranslation.php2
-rw-r--r--core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php4
-rw-r--r--core/lib/Drupal/Core/Utility/LinkGenerator.php10
-rw-r--r--core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php2
-rw-r--r--core/modules/block/lib/Drupal/block/BlockFormController.php23
-rw-r--r--core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php7
-rw-r--r--core/modules/block/tests/Drupal/block/Tests/BlockFormControllerTest.php4
-rw-r--r--core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php2
-rw-r--r--core/modules/comment/lib/Drupal/comment/CommentFormController.php2
-rw-r--r--core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php8
-rw-r--r--core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php1
-rw-r--r--core/modules/comment/tests/modules/comment_test/comment_test.module2
-rw-r--r--core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php6
-rw-r--r--core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php20
-rw-r--r--core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php4
-rw-r--r--core/modules/content_translation/content_translation.admin.inc2
-rw-r--r--core/modules/content_translation/content_translation.install4
-rw-r--r--core/modules/content_translation/content_translation.module6
-rw-r--r--core/modules/content_translation/content_translation.pages.inc6
-rw-r--r--core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php4
-rw-r--r--core/modules/filter/filter.module2
-rw-r--r--core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php1
-rw-r--r--core/modules/language/config/language.types.yml (renamed from core/modules/system/config/system.language.types.yml)0
-rw-r--r--core/modules/language/config/schema/language.schema.yml17
-rw-r--r--core/modules/language/language.api.php71
-rw-r--r--core/modules/language/language.install39
-rw-r--r--core/modules/language/language.module221
-rw-r--r--core/modules/language/language.negotiation.inc529
-rw-r--r--core/modules/language/language.services.yml19
-rw-r--r--core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php386
-rw-r--r--core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php86
-rw-r--r--core/modules/language/lib/Drupal/language/Entity/Language.php1
-rw-r--r--core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php (renamed from core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php)46
-rw-r--r--core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php1
-rw-r--r--core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php1
-rw-r--r--core/modules/language/lib/Drupal/language/Form/NegotiationConfigureForm.php63
-rw-r--r--core/modules/language/lib/Drupal/language/Form/NegotiationUrlForm.php14
-rw-r--r--core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php158
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageConfigSubscriber.php68
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageListController.php10
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageNegotiationMethodBase.php69
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageNegotiationMethodInterface.php65
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageNegotiationMethodManager.php38
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageNegotiator.php372
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageNegotiatorInterface.php217
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageServiceProvider.php73
-rw-r--r--core/modules/language/lib/Drupal/language/LanguageSwitcherInterface.php32
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php47
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/Condition/Language.php2
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php31
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php49
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php45
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php153
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php38
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php203
-rw-r--r--core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php76
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/Condition/LanguageConditionTest.php2
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php8
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php6
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php32
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageFallbackTest.php41
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php20
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php46
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php3
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageTestBase.php48
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php115
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php9
-rw-r--r--core/modules/language/tests/Drupal/language/Tests/LanguageNegotiationUrlTest.php165
-rw-r--r--core/modules/language/tests/language_test/language_test.module55
-rw-r--r--core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestManager.php28
-rw-r--r--core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestServiceProvider.php28
-rw-r--r--core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTest.php38
-rw-r--r--core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTestTs.php30
-rw-r--r--core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php2
-rw-r--r--core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php4
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php8
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php2
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php43
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php2
-rw-r--r--core/modules/locale/locale.bulk.inc2
-rw-r--r--core/modules/locale/locale.install88
-rw-r--r--core/modules/node/lib/Drupal/node/Controller/NodeController.php2
-rw-r--r--core/modules/node/lib/Drupal/node/Entity/Node.php2
-rw-r--r--core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php2
-rw-r--r--core/modules/node/lib/Drupal/node/NodeListController.php7
-rw-r--r--core/modules/node/lib/Drupal/node/NodeViewBuilder.php2
-rw-r--r--core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php3
-rw-r--r--core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php7
-rw-r--r--core/modules/path/path.admin.inc2
-rw-r--r--core/modules/simpletest/lib/Drupal/simpletest/TestBase.php8
-rw-r--r--core/modules/system/config/schema/system.schema.yml17
-rw-r--r--core/modules/system/language.api.php117
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php15
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Entity/EntityLanguageTestBase.php18
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php4
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php2
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php1
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php3
-rw-r--r--core/modules/system/system.install2
-rw-r--r--core/modules/toolbar/toolbar.module2
-rw-r--r--core/modules/user/lib/Drupal/user/AccountFormController.php34
-rw-r--r--core/modules/user/lib/Drupal/user/Form/UserPasswordForm.php2
-rw-r--r--core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUser.php50
-rw-r--r--core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php69
-rw-r--r--core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php2
-rw-r--r--core/modules/views/lib/Drupal/views/ViewsData.php10
-rw-r--r--core/modules/views/tests/Drupal/views/Tests/ViewsDataTest.php6
-rw-r--r--core/tests/Drupal/Tests/Core/Datetime/DateTest.php4
-rw-r--r--core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php6
-rw-r--r--core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php6
-rw-r--r--core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php6
-rw-r--r--core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php66
-rw-r--r--core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php12
-rw-r--r--core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php4
135 files changed, 3660 insertions, 2569 deletions
diff --git a/core/core.services.yml b/core/core.services.yml
index 6134359ddd1..6abd05ce920 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -225,7 +225,6 @@ services:
arguments: ['@event_dispatcher', '@service_container', '@controller_resolver']
language_manager:
class: Drupal\Core\Language\LanguageManager
- arguments: ['@state', '@module_handler']
string_translator.custom_strings:
class: Drupal\Core\StringTranslation\Translator\CustomStrings
arguments: ['@settings']
@@ -233,6 +232,9 @@ services:
- { name: string_translator, priority: 30 }
string_translation:
class: Drupal\Core\StringTranslation\TranslationManager
+ arguments: ['@language_manager']
+ calls:
+ - [initLanguageManager]
database.slave:
class: Drupal\Core\Database\Connection
factory_class: Drupal\Core\Database\Database
@@ -518,11 +520,6 @@ services:
tags:
- { name: event_subscriber }
arguments: ['@config.storage', '@config.storage.snapshot']
- language_request_subscriber:
- class: Drupal\Core\EventSubscriber\LanguageRequestSubscriber
- tags:
- - { name: event_subscriber }
- arguments: ['@language_manager', '@string_translation']
exception_controller:
class: Drupal\Core\Controller\ExceptionController
arguments: ['@content_negotiation', '@string_translation', '@title_resolver', '@html_page_renderer']
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 51f4446868e..c4b0cb4aac1 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2331,7 +2331,7 @@ function drupal_installation_attempted() {
function drupal_language_initialize() {
$language_manager = \Drupal::languageManager();
$language_manager->init();
- \Drupal::translation()->setDefaultLangcode($language_manager->getLanguage(Language::TYPE_INTERFACE)->id);
+ \Drupal::translation()->setDefaultLangcode($language_manager->getCurrentLanguage()->id);
}
/**
@@ -2343,47 +2343,10 @@ function drupal_language_initialize() {
* The type of language object needed, e.g. Language::TYPE_INTERFACE.
*
* @deprecated as of Drupal 8.0. Use
- * \Drupal::languageManager()->getLanguage($type).
+ * \Drupal::languageManager()->getCurrentLanguage().
*/
function language($type) {
- return \Drupal::languageManager()->getLanguage($type);
-}
-
-/**
- * Returns an array of the available language types.
- *
- * @return array
- * An array of all language types where the keys of each are the language type
- * name and its value is its configurability (TRUE/FALSE).
- */
-function language_types_get_all() {
- $types = \Drupal::config('system.language.types')->get('all');
- return $types ? $types : array_keys(language_types_get_default());
-}
-
-/**
- * Returns a list of the built-in language types.
- *
- * @return array
- * An array of key-values pairs where the key is the language type name and
- * the value is its configurability (TRUE/FALSE).
- */
-function language_types_get_default() {
- return array(
- Language::TYPE_INTERFACE => TRUE,
- Language::TYPE_CONTENT => FALSE,
- Language::TYPE_URL => FALSE,
- );
-}
-
-/**
- * Returns TRUE if there is more than one language enabled.
- *
- * @return bool
- * TRUE if more than one language is enabled.
- */
-function language_multilingual() {
- return \Drupal::languageManager()->isMultilingual();
+ return \Drupal::languageManager()->getCurrentLanguage($type);
}
/**
@@ -2397,101 +2360,12 @@ function language_multilingual() {
* @return array
* An associative array of languages, keyed by the language code, ordered by
* weight ascending and name ascending.
- */
-function language_list($flags = Language::STATE_CONFIGURABLE) {
-
- $languages = &drupal_static(__FUNCTION__);
-
- // Initialize master language list.
- if (!isset($languages)) {
- // Initialize local language list cache.
- $languages = array();
-
- // Fill in master language list based on current configuration.
- $default = language_default();
- if (language_multilingual() || \Drupal::moduleHandler()->moduleExists('language')) {
- // Use language module configuration if available.
- $language_entities = config_get_storage_names_with_prefix('language.entity.');
-
- // Initialize default property so callers have an easy reference and can
- // save the same object without data loss.
- foreach ($language_entities as $langcode_config_name) {
- $langcode = substr($langcode_config_name, strlen('language.entity.'));
- $info = \Drupal::config($langcode_config_name)->get();
- $languages[$langcode] = new Language(array(
- 'default' => ($info['id'] == $default->id),
- 'name' => $info['label'],
- 'id' => $info['id'],
- 'direction' => $info['direction'],
- 'locked' => $info['locked'],
- 'weight' => $info['weight'],
- ));
- }
- Language::sort($languages);
- }
- // If the language module is enabled but the configuration has not been
- // written yet, returning an empty language list will cause errors. For
- // example the cache clear in search_module_preinstall().
- if (empty($languages)) {
- // No language module, so use the default language only.
- $languages = array($default->id => $default);
- // Add the special languages, they will be filtered later if needed.
- $languages += language_default_locked_languages($default->weight);
- }
- }
-
- // Filter the full list of languages based on the value of the $all flag. By
- // default we remove the locked languages, but the caller may request for
- // those languages to be added as well.
- $filtered_languages = array();
-
- // Add the site's default language if flagged as allowed value.
- if ($flags & Language::STATE_SITE_DEFAULT) {
- $default = isset($default) ? $default : language_default();
- // Rename the default language.
- $default->name = t("Site's default language (@lang_name)", array('@lang_name' => $default->name));
- $filtered_languages['site_default'] = $default;
- }
-
- foreach ($languages as $langcode => $language) {
- if (($language->locked && !($flags & Language::STATE_LOCKED)) || (!$language->locked && !($flags & Language::STATE_CONFIGURABLE))) {
- continue;
- }
- $filtered_languages[$langcode] = $language;
- }
-
- return $filtered_languages;
-}
-
-/**
- * Returns a list of the default locked languages.
- *
- * @param int $weight
- * An integer value that is used as the start value for the weights of the
- * locked languages.
*
- * @return array
- * An array of language objects.
+ * @deprecated as of Drupal 8.0. Use
+ * \Drupal::languageManager()->getLanguages() instead.
*/
-function language_default_locked_languages($weight = 0) {
- $locked_language = array(
- 'default' => FALSE,
- 'locked' => TRUE,
- 'enabled' => TRUE,
- );
-
- $languages = array();
- $languages[Language::LANGCODE_NOT_SPECIFIED] = new Language(array(
- 'id' => Language::LANGCODE_NOT_SPECIFIED,
- 'name' => t('Not specified'),
- 'weight' => ++$weight,
- ) + $locked_language);
- $languages[Language::LANGCODE_NOT_APPLICABLE] = new Language(array(
- 'id' => Language::LANGCODE_NOT_APPLICABLE,
- 'name' => t('Not applicable'),
- 'weight' => ++$weight,
- ) + $locked_language);
- return $languages;
+function language_list($flags = Language::STATE_CONFIGURABLE) {
+ return \Drupal::languageManager()->getLanguages($flags);
}
/**
@@ -2502,47 +2376,14 @@ function language_default_locked_languages($weight = 0) {
*
* @return \Drupal\core\Language\Language|null
* A fully-populated language object or NULL.
- */
-function language_load($langcode) {
- $languages = language_list(Language::STATE_ALL);
- return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
-}
-
-/**
- * Produced the printed name for a language for display.
*
- * @param string $langcode
- * The language code.
+ * @see \Drupal\Core\Language\LanguageManager::getLanguage()
*
- * @return string
- * The printed name of the language.
+ * @deprecated as of Drupal 8.0. Use \Drupal::languageManager()->getLanguage()
+ * instead.
*/
-function language_name($langcode) {
- if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
- return t('None');
- }
-
- if ($language = language_load($langcode)) {
- return $language->name;
- }
- if (empty($langcode)) {
- return t('Unknown');
- }
- return t('Unknown (@langcode)', array('@langcode' => $langcode));
-}
-
-/**
- * Checks if a language is locked.
- *
- * @param string $langcode
- * The language code.
- *
- * @return bool
- * Returns whether the language is locked.
- */
-function language_is_locked($langcode) {
- $language = language_load($langcode);
- return ($language ? $language->locked : FALSE);
+function language_load($langcode) {
+ return \Drupal::languageManager()->getLanguage($langcode);
}
/**
@@ -2550,35 +2391,12 @@ function language_is_locked($langcode) {
*
* @return \Drupal\Core\Language\Language
* A language object.
- */
-function language_default() {
- $info = variable_get('language_default', array(
- 'id' => 'en',
- 'name' => 'English',
- 'direction' => 0,
- 'weight' => 0,
- 'locked' => 0,
- ));
- $info['default'] = TRUE;
- return new Language($info);
-}
-
-/**
- * Stores or retrieves the path derived during language negotiation.
*
- * @param string $new_path
- * The altered path.
- *
- * @todo Replace this with a path processor in language module. See
- * http://drupal.org/node/1888424.
+ * @deprecated as of Drupal 8.0. Use
+ * \Drupal::languageManager()->getDefaultLanguage() instead.
*/
-function _language_resolved_path($new_path = NULL) {
- $path = &drupal_static(__FUNCTION__, NULL);
- if ($new_path === NULL) {
- return $path;
- }
- $path = $new_path;
- return $path;
+function language_default() {
+ return \Drupal::languageManager()->getDefaultLanguage();
}
/**
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 9d03679746c..84e5edb9fb3 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4531,11 +4531,12 @@ function drupal_render_cid_parts($granularity = NULL) {
global $theme, $base_root, $user;
$cid_parts[] = $theme;
- // If Locale is enabled but we have only one language we do not need it as cid
- // part.
- if (language_multilingual()) {
- foreach (language_types_get_configurable() as $language_type) {
- $cid_parts[] = language($language_type)->id;
+
+ // If we have only one language enabled we do not need it as cid part.
+ $language_manager = \Drupal::languageManager();
+ if ($language_manager->isMultilingual()) {
+ foreach ($language_manager->getLanguageTypes() as $type) {
+ $cid_parts[] = $language_manager->getCurrentLanguage($type)->id;
}
}
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 6dfc2700e3b..5a46c8cb45c 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1,5 +1,6 @@
<?php
+use Drupal\Component\Utility\UserAgent;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Settings;
@@ -300,6 +301,9 @@ function install_begin_request(&$install_state) {
exit;
}
+ // Register the 'language_manager' service.
+ $container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
+
// If we have a language selected and it is not yet saved in the system
// (eg. pre-database data screens we are unable to persistently store
// the default language), we should set language_default so the proper
@@ -370,7 +374,6 @@ function install_begin_request(&$install_state) {
else {
// @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder.
$container = new ContainerBuilder();
-
$container->register('event_dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher');
$container->register('config.storage', 'Drupal\Core\Config\InstallStorage');
@@ -388,9 +391,7 @@ function install_begin_request(&$install_state) {
->addArgument(new Reference('config.typed'));
// Register the 'language_manager' service.
- $container
- ->register('language_manager', 'Drupal\Core\Language\LanguageManager')
- ->addArgument(NULL);
+ $container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
// Register the translation services.
install_register_translation_service($container);
@@ -1505,6 +1506,7 @@ function install_register_translation_service(ContainerBuilder $container) {
$container->register('string_translator.custom_strings', 'Drupal\Core\StringTranslation\Translator\CustomStrings')
->addArgument(settings());
$container->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
+ ->addArgument(new Reference('language_manager'))
->addMethodCall('addTranslator', array(new Reference('string_translator.file_translation')))
->addMethodCall('addTranslator', array(new Reference('string_translator.custom_strings')));
}
@@ -1582,9 +1584,6 @@ function install_select_language(&$install_state) {
* @ingroup forms
*/
function install_select_language_form($form, &$form_state, $files = array()) {
- include_once __DIR__ . '/../modules/language/language.module';
- include_once __DIR__ . '/../modules/language/language.negotiation.inc';
-
$standard_languages = LanguageManager::getStandardLanguageList();
$select_options = array();
$browser_options = array();
@@ -1596,22 +1595,19 @@ function install_select_language_form($form, &$form_state, $files = array()) {
// Select lists based on available language files.
foreach ($files as $langcode => $uri) {
$select_options[$langcode] = isset($standard_languages[$langcode]) ? $standard_languages[$langcode][1] : $langcode;
- $browser_options[$langcode] = new Language(array(
- 'id' => $langcode,
- ));
+ $browser_options[] = $langcode;
}
}
else {
// Select lists based on all standard languages.
foreach ($standard_languages as $langcode => $language_names) {
$select_options[$langcode] = $language_names[1];
- $browser_options[$langcode] = new Language(array(
- 'id' => $langcode,
- ));
+ $browser_options[] = $langcode;
}
}
- $browser_langcode = language_from_browser($browser_options);
+ $request = Request::createFromGlobals();
+ $browser_langcode = UserAgent::getBestMatchingLangcode($request->server->get('HTTP_ACCEPT_LANGUAGE'), $browser_options);
$form['langcode'] = array(
'#type' => 'select',
'#title' => t('Choose language'),
diff --git a/core/includes/language.inc b/core/includes/language.inc
deleted file mode 100644
index 618e3a70028..00000000000
--- a/core/includes/language.inc
+++ /dev/null
@@ -1,551 +0,0 @@
-<?php
-
-/**
- * @file
- * Language Negotiation API.
- *
- * @see http://drupal.org/node/1497272
- */
-
-use Drupal\Core\Language\Language;
-
-/**
- * No language negotiation. The default language is used.
- */
-const LANGUAGE_NEGOTIATION_SELECTED = 'language-selected';
-
-/**
- * The language is determined using the current interface language.
- */
-const LANGUAGE_NEGOTIATION_INTERFACE = 'language-interface';
-
-/**
- * @defgroup language_negotiation Language Negotiation API functionality
- * @{
- * Functions to customize the language types and the negotiation process.
- *
- * The language negotiation API is based on two major concepts:
- * - Language types: types of translatable data (the types of data that a user
- * can view or request).
- * - Language negotiation methods: functions for determining which language to
- * use to present a particular piece of data to the user.
- * Both language types and language negotiation methods are customizable.
- *
- * Drupal defines three built-in language types:
- * - Interface language: The page's main language, used to present translated
- * user interface elements such as titles, labels, help text, and messages.
- * - Content language: The language used to present content that is available
- * in more than one language (see
- * @link field_language Field Language API @endlink for details).
- * - URL language: The language associated with URLs. When generating a URL,
- * this value will be used by url() as a default if no explicit preference is
- * provided.
- * Modules can define additional language types through
- * hook_language_types_info(), and alter existing language type definitions
- * through hook_language_types_info_alter().
- *
- * Language types may be configurable or fixed. The language negotiation
- * methods associated with a configurable language type can be explicitly
- * set through the user interface. A fixed language type has predetermined
- * (module-defined) language negotiation settings and, thus, does not appear in
- * the configuration page. Here is a code snippet that makes the content
- * language (which by default inherits the interface language's values)
- * configurable:
- * @code
- * function mymodule_language_types_info_alter(&$language_types) {
- * unset($language_types[Language::TYPE_CONTENT]['fixed']);
- * }
- * @endcode
- *
- * The locked configuration property prevents one language type from being
- * switched from customized to not customized, and vice versa.
- * @see language_types_set()
- *
- * Every language type can have a different set of language negotiation methods
- * assigned to it. Different language types often share the same language
- * negotiation settings, but they can have independent settings if needed. If
- * two language types are configured the same way, their language switcher
- * configuration will be functionally identical and the same settings will act
- * on both language types.
- *
- * Drupal defines the following built-in language negotiation methods:
- * - URL: Determine the language from the URL (path prefix or domain).
- * - Session: Determine the language from a request/session parameter.
- * - User: Follow the user's language preference.
- * - Browser: Determine the language from the browser's language settings.
- * - Default language: Use the default site language.
- * Language negotiation methods are simple callback functions that implement a
- * particular logic to return a language code. For instance, the URL method
- * searches for a valid path prefix or domain name in the current request URL.
- * If a language negotiation method does not return a valid language code, the
- * next method associated to the language type (based on method weight) is
- * invoked.
- *
- * Modules can define additional language negotiation methods through
- * hook_language_negotiation_info(), and alter existing methods through
- * hook_language_negotiation_info_alter(). Here is an example snippet that lets
- * path prefixes be ignored for administrative paths:
- * @code
- * function mymodule_language_negotiation_info_alter(&$negotiation_info) {
- * // Replace the core function with our own function.
- * module_load_include('language', 'inc', 'language.negotiation');
- * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['negotiation'] = 'mymodule_from_url';
- * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module';
- * }
- *
- * function mymodule_from_url($languages) {
- * // Use the core URL language negotiation method to get a valid language
- * // code.
- * module_load_include('language', 'inc', 'language.negotiation');
- * $langcode = language_from_url($languages);
- *
- * // If we are on an administrative path, override with the default language.
- * $query = \Drupal::request()->query;
- * if ($query->has('q') && strtok($query->get('q'), '/') == 'admin') {
- * return language_default()->id;
- * }
- * return $langcode;
- * }
- * ?>
- * @endcode
- *
- * For more information, see
- * @link http://drupal.org/node/1497272 Language Negotiation API @endlink
- */
-
-/**
- * Chooses a language based on language negotiation method settings.
- *
- * @param $type
- * The language type key to find the language for.
- *
- * @param $request
- * The HttpReqeust object representing the current request.
- *
- * @return
- * The negotiated language object.
- */
-function language_types_initialize($type, $request = NULL) {
- // Execute the language negotiation methods in the order they were set up and
- // return the first valid language found.
- $negotiation = variable_get("language_negotiation_$type", array());
-
- foreach ($negotiation as $method_id => $method) {
- // Skip negotiation methods not appropriate for this type.
- if (isset($method['types']) && !in_array($type, $method['types'])) {
- continue;
- }
- $language = language_negotiation_method_invoke($method_id, $method, $request);
- if ($language) {
- // Remember the method ID used to detect the language.
- $language->method_id = $method_id;
- return $language;
- }
- }
-
- // If no other language was found use the default one.
- $language = language_default();
- $language->method_id = LANGUAGE_NEGOTIATION_SELECTED;
- return $language;
-}
-
-/**
- * Returns information about all defined language types.
- *
- * @return
- * An associative array of language type information arrays keyed by type
- * names. Based on information from hook_language_types_info().
- *
- * @see hook_language_types_info().
- */
-function language_types_info() {
- $language_types = &drupal_static(__FUNCTION__);
-
- if (!isset($language_types)) {
- $language_types = \Drupal::moduleHandler()->invokeAll('language_types_info');
- // Let other modules alter the list of language types.
- drupal_alter('language_types_info', $language_types);
- }
-
- return $language_types;
-}
-
-/**
- * Returns only the configurable language types.
- *
- * A language type maybe configurable or fixed. A fixed language type is a type
- * whose language negotiation methods are module-defined and not altered through
- * the user interface.
- *
- * @return
- * An array of language type names.
- */
-function language_types_get_configurable() {
- $configurable = \Drupal::config('system.language.types')->get('configurable');
- return $configurable ? $configurable : array();
-}
-
-/**
- * Disables the given language types.
- *
- * @param $types
- * An array of language types.
- */
-function language_types_disable($types) {
- $configurable = language_types_get_configurable();
- \Drupal::config('system.language.types')->set('configurable', array_diff($configurable, $types))->save();
-}
-
-/**
- * Updates the language type configuration.
- *
- * @param array $configurable_language_types
- * An array of configurable language types.
- */
-function language_types_set(array $configurable_language_types) {
- // Ensure that we are getting the defined language negotiation information. An
- // invocation of \Drupal\Core\Extension\ModuleHandler::install() or
- // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
- // cached information.
- drupal_static_reset('language_types_info');
- drupal_static_reset('language_negotiation_info');
-
- $language_types = array();
- $negotiation_info = language_negotiation_info();
- $language_types_info = language_types_info();
-
- foreach ($language_types_info as $type => $info) {
- $configurable = in_array($type, $configurable_language_types);
-
- // Check whether the language type is unlocked. Only the status of unlocked
- // language types can be toggled between configurable and non-configurable.
- // The default language negotiation settings, if available, are stored in
- // $info['fixed'].
- if (empty($info['locked'])) {
- // If we have a non-locked non-configurable language type without default
- // language negotiation settings, we use the values negotiated for the
- // interface language which should always be available.
- if (!$configurable && !empty($info['fixed'])) {
- $method_weights = array(LANGUAGE_NEGOTIATION_INTERFACE);
- $method_weights = array_flip($method_weights);
- language_negotiation_set($type, $method_weights);
- }
- }
- else {
- // Locked language types with default settings are always considered
- // non-configurable. In turn if default settings are missing, the language
- // type is always considered configurable.
- $configurable = empty($info['fixed']);
-
- // If the language is non-configurable we need to store its language
- // negotiation settings.
- if (!$configurable) {
- $method_weights = array();
- foreach ($info['fixed'] as $weight => $method_id) {
- if (isset($negotiation_info[$method_id])) {
- $method_weights[$method_id] = $weight;
- }
- }
- language_negotiation_set($type, $method_weights);
- }
- }
-
- $language_types[$type] = $configurable;
- }
-
- // Store the language type configuration.
- $config = \Drupal::config('system.language.types');
- $config->set('configurable', array_keys(array_filter($language_types)))->save();
- $config->set('all', array_keys($language_types))->save();
-
- // Ensure that subsequent calls of language_types_get_configurable() return
- // the updated language type information.
- drupal_static_reset('language_types_get_configurable');
-}
-
-/**
- * Returns the ID of the language type's first language negotiation method.
- *
- * @param $type
- * The language type.
- *
- * @return
- * The identifier of the first language negotiation method for the given
- * language type, or the default method if none exists.
- */
-function language_negotiation_method_get_first($type) {
- $negotiation = variable_get("language_negotiation_$type", array());
- return empty($negotiation) ? LANGUAGE_NEGOTIATION_SELECTED : key($negotiation);
-}
-
-/**
- * Checks whether a language negotiation method is enabled for a language type.
- *
- * @param $method_id
- * The language negotiation method ID.
- * @param $type
- * (optional) The language type. If none is passed, all the configurable
- * language types will be inspected.
- *
- * @return
- * TRUE if the method is enabled for at least one of the given language
- * types, or FALSE otherwise.
- */
-function language_negotiation_method_enabled($method_id, $type = NULL) {
- $language_types = !empty($type) ? array($type) : language_types_get_configurable();
-
- foreach ($language_types as $type) {
- $negotiation = variable_get("language_negotiation_$type", array());
- if (isset($negotiation[$method_id])) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- * Returns the language switch links for the given language type.
- *
- * @param $type
- * The language type.
- * @param $path
- * The internal path the switch links will be relative to.
- *
- * @return
- * A keyed array of links ready to be themed.
- */
-function language_negotiation_get_switch_links($type, $path) {
- $links = FALSE;
- $negotiation = variable_get("language_negotiation_$type", array());
-
- foreach ($negotiation as $method_id => $method) {
- if (isset($method['callbacks']['language_switch'])) {
- if (isset($method['file'])) {
- require_once DRUPAL_ROOT . '/' . $method['file'];
- }
-
- $callback = $method['callbacks']['language_switch'];
- $result = $callback($type, $path);
-
- if (!empty($result)) {
- // Allow modules to provide translations for specific links.
- drupal_alter('language_switch_links', $result, $type, $path);
- $links = (object) array('links' => $result, 'method_id' => $method_id);
- break;
- }
- }
- }
-
- return $links;
-}
-
-/**
- * Removes any language negotiation methods that are no longer defined.
- */
-function language_negotiation_purge() {
- // Ensure that we are getting the defined language negotiation information. An
- // invocation of \Drupal\Core\Extension\ModuleHandler::install() or
- // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
- // cached information.
- drupal_static_reset('language_negotiation_info');
- drupal_static_reset('language_types_info');
-
- $negotiation_info = language_negotiation_info();
- foreach (language_types_info() as $type => $type_info) {
- $weight = 0;
- $method_weights = array();
- foreach (variable_get("language_negotiation_$type", array()) as $method_id => $method) {
- if (isset($negotiation_info[$method_id])) {
- $method_weights[$method_id] = $weight++;
- }
- }
- language_negotiation_set($type, $method_weights);
- }
-}
-
-/**
- * Saves a list of language negotiation methods for a language type.
- *
- * @param $type
- * The language type.
- * @param $method_weights
- * An array of language negotiation method weights keyed by method ID.
- */
-function language_negotiation_set($type, $method_weights) {
- // Save only the necessary fields.
- $method_fields = array('callbacks', 'file', 'cache');
-
- $negotiation = array();
- $negotiation_info = language_negotiation_info();
- $default_types = language_types_get_configurable();
-
- // Order the language negotiation method list by weight.
- asort($method_weights);
-
- foreach ($method_weights as $method_id => $weight) {
- if (isset($negotiation_info[$method_id])) {
- $method = $negotiation_info[$method_id];
- // If the language negotiation method does not express any preference
- // about types, make it available for any configurable type.
- $types = array_flip(isset($method['types']) ? $method['types'] : $default_types);
- // Check whether the method is defined and has the right type.
- if (isset($types[$type])) {
- $method_data = array();
- foreach ($method_fields as $field) {
- if (isset($method[$field])) {
- $method_data[$field] = $method[$field];
- }
- }
- $negotiation[$method_id] = $method_data;
- }
- }
- }
-
- variable_set("language_negotiation_$type", $negotiation);
-}
-
-/**
- * Returns all defined language negotiation methods.
- *
- * @return
- * An array of language negotiation methods.
- */
-function language_negotiation_info() {
- $negotiation_info = &drupal_static(__FUNCTION__);
-
- if (!isset($negotiation_info)) {
- // Collect all the module-defined language negotiation methods.
- $negotiation_info = \Drupal::moduleHandler()->invokeAll('language_negotiation_info');
- $languages = language_list();
- $selected_language = $languages[language_from_selected($languages)];
- $description = 'Language based on a selected language. ';
- $description .= ($selected_language->id == language_default()->id) ? "(Site's default language (@language_name))" : '(@language_name)';
- // Add the default language negotiation method.
- $negotiation_info[LANGUAGE_NEGOTIATION_SELECTED] = array(
- 'callbacks' => array(
- 'negotiation' => 'language_from_selected',
- ),
- 'weight' => 12,
- 'name' => t('Selected language'),
- 'description' => t($description, array('@language_name' => $selected_language->name)),
- 'config' => 'admin/config/regional/language/detection/selected',
- );
-
- // Let other modules alter the list of language negotiation methods.
- drupal_alter('language_negotiation_info', $negotiation_info);
- }
-
- return $negotiation_info;
-}
-
-/**
- * Invokes a language negotiation method and caches the results.
- *
- * @param $method_id
- * The language negotiation method's identifier.
- * @param $method
- * (optional) An associative array of information about the method to be
- * invoked (see hook_language_negotiation_info() for details). If not passed
- * in, it will be loaded through language_negotiation_info().
- *
- * @param $request
- * (optional) The HttpRequest object representing the current request.
- *
- * @return
- * A language object representing the language chosen by the method.
- */
-function language_negotiation_method_invoke($method_id, $method = NULL, $request = NULL) {
- $results = &drupal_static(__FUNCTION__);
-
- if (!isset($results[$method_id])) {
- global $user;
-
- $languages = language_list();
-
- if (!isset($method)) {
- $negotiation_info = language_negotiation_info();
- $method = $negotiation_info[$method_id];
- }
-
- if (isset($method['file'])) {
- require_once DRUPAL_ROOT . '/' . $method['file'];
- }
- // Check for a cache mode force from settings.php.
- if (settings()->get('page_cache_without_database')) {
- $cache_enabled = TRUE;
- }
- else {
- drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
- $config = \Drupal::config('system.performance');
- $cache_enabled = $config->get('cache.page.use_internal');
- }
- // If the language negotiation method has no cache preference or this is
- // satisfied we can execute the callback.
- $cache = !isset($method['cache']) || $user->isAuthenticated() || $method['cache'] == $cache_enabled;
- $callback = isset($method['callbacks']['negotiation']) ? $method['callbacks']['negotiation'] : FALSE;
- $langcode = $cache && function_exists($callback) ? $callback($languages, $request) : FALSE;
- $results[$method_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
- }
-
- // Since objects are resources, we need to return a clone to prevent the
- // language negotiation method cache from being unintentionally altered. The
- // same methods might be used with different language types based on
- // configuration.
- return !empty($results[$method_id]) ? clone($results[$method_id]) : $results[$method_id];
-}
-
- /**
- * Identifies language from configuration.
- *
- * @param $languages
- * An array of valid language objects.
- *
- * @return
- * A valid language code on success, FALSE otherwise.
- */
-function language_from_selected($languages) {
- $langcode = (string) \Drupal::config('language.negotiation')->get('selected_langcode');
- // Replace the site's default langcode by its real value.
- if ($langcode == 'site_default') {
- $langcode = language_default()->id;
- }
- return isset($languages[$langcode]) ? $langcode : language_default()->id;
-}
-
-/**
- * Splits the given path into prefix and actual path.
- *
- * Parse the given path and return the language object identified by the prefix
- * and the actual path.
- *
- * @param $path
- * The path to split.
- * @param $languages
- * An array of valid languages.
- *
- * @return
- * An array composed of:
- * - A language object corresponding to the identified prefix on success,
- * FALSE otherwise.
- * - The path without the prefix on success, the given path otherwise.
- */
-function language_url_split_prefix($path, $languages) {
- $args = empty($path) ? array() : explode('/', $path);
- $prefix = array_shift($args);
-
- // Search prefix within enabled languages.
- $prefixes = language_negotiation_url_prefixes();
- foreach ($languages as $language) {
- if (isset($prefixes[$language->id]) && $prefixes[$language->id] == $prefix) {
- // Rebuild $path with the language removed.
- return array($language, implode('/', $args));
- }
- }
-
- return array(FALSE, $path);
-}
-
-/**
- * @} End of "language_negotiation"
- */
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 676f2fa4793..5ca4d61cdce 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1235,7 +1235,7 @@ function theme_links($variables) {
$output .= '<ul' . new Attribute($attributes) . '>';
$active = \Drupal::linkGenerator()->getActive();
- $language_url = \Drupal::languageManager()->getLanguage(Language::TYPE_URL);
+ $language_url = \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_URL);
foreach ($links as $key => $link) {
$link += array(
@@ -2072,7 +2072,7 @@ function template_preprocess_html(&$variables) {
$variables['html_attributes'] = new Attribute;
// HTML element attributes.
- $language_interface = \Drupal::service('language_manager')->getLanguage();
+ $language_interface = \Drupal::service('language_manager')->getCurrentLanguage();
$variables['html_attributes']['lang'] = $language_interface->id;
$variables['html_attributes']['dir'] = $language_interface->direction ? 'rtl' : 'ltr';
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 24f65832fde..c45e0139142 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -478,9 +478,7 @@ function update_prepare_stored_includes() {
foreach ($language_types as $language_type) {
$negotiation = update_variable_get("language_negotiation_$language_type", array());
foreach ($negotiation as &$method) {
- if (isset($method['file']) && $method['file'] == 'includes/locale.inc') {
- $method['file'] = 'core/modules/language/language.negotiation.inc';
- }
+ unset($method['file']);
}
update_variable_set("language_negotiation_$language_type", $negotiation);
}
@@ -525,9 +523,6 @@ function update_prepare_d8_language() {
db_drop_field('languages', 'native');
db_drop_field('languages', 'enabled');
- // Update language count.
- \Drupal::state()->set('language_count', db_query('SELECT COUNT(language) FROM {languages}')->fetchField());
-
// Rename the languages table to language.
db_rename_table('languages', 'language');
@@ -556,7 +551,7 @@ function update_prepare_d8_language() {
db_add_field('language', 'locked', $locked_spec);
$max_language_weight = db_query('SELECT MAX(weight) FROM {language}')->fetchField();
- $languages = language_default_locked_languages($max_language_weight);
+ $languages = \Drupal::languageManager()->getDefaultLockedLanguages($max_language_weight);
foreach ($languages as $language) {
db_insert('language')
->fields(array(
@@ -1640,7 +1635,7 @@ function update_language_list($flags = Language::STATE_CONFIGURABLE) {
// Fill in master language list based on current configuration.
$default = language_default();
- if (language_multilingual() || \Drupal::moduleHandler()->moduleExists('language')) {
+ if (\Drupal::languageManager()->isMultilingual() || \Drupal::moduleHandler()->moduleExists('language')) {
// Use language module configuration if available. We can not use
// entity_load_multiple() because this breaks during updates.
$language_entities = config_get_storage_names_with_prefix('language.entity.');
@@ -1665,7 +1660,7 @@ function update_language_list($flags = Language::STATE_CONFIGURABLE) {
// No language module, so use the default language only.
$languages = array($default->id => $default);
// Add the special languages, they will be filtered later if needed.
- $languages += language_default_locked_languages($default->weight);
+ $languages += \Drupal::languageManager()->getDefaultLockedLanguages($default->weight);
}
}
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 6af2411f166..0ec88d7dac5 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -533,7 +533,7 @@ class Drupal {
/**
* Returns the language manager service.
*
- * @return \Drupal\Core\Language\LanguageManager
+ * @return \Drupal\Core\Language\LanguageManagerInterface
* The language manager.
*/
public static function languageManager() {
diff --git a/core/lib/Drupal/Component/Utility/UserAgent.php b/core/lib/Drupal/Component/Utility/UserAgent.php
new file mode 100644
index 00000000000..361b057ce9f
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/UserAgent.php
@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\UserAgent.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Provides user agent related utility functions.
+ */
+class UserAgent {
+
+ /**
+ * Identifies user agent language from the Accept-language HTTP header.
+ *
+ * The algorithm works as follows:
+ * - map user agent language codes to available language codes.
+ * - order all user agent language codes by qvalue from high to low.
+ * - add generic user agent language codes if they aren't already specified
+ * but with a slightly lower qvalue.
+ * - find the most specific available language code with the highest qvalue.
+ * - if 2 or more languages are having the same qvalue, respect the order of
+ * them inside the $languages array.
+ *
+ * We perform user agent accept-language parsing only if page cache is
+ * disabled, otherwise we would cache a user-specific preference.
+ *
+ * @param string $http_accept_language
+ * The value of the "Accept-Language" HTTP header.
+ * @param array $langcodes
+ * An array of available language codes to pick from.
+ * @param array $mappings
+ * (optional) Custom mappings to support user agents that are sending non
+ * standard language codes. No mapping is assumed by default.
+ *
+ * @return string
+ * The selected language code or FALSE if no valid language can be
+ * identified.
+ */
+ public static function getBestMatchingLangcode($http_accept_language, $langcodes, $mappings = array()) {
+ // The Accept-Language header contains information about the language
+ // preferences configured in the user's user agent / operating system.
+ // RFC 2616 (section 14.4) defines the Accept-Language header as follows:
+ // Accept-Language = "Accept-Language" ":"
+ // 1#( language-range [ ";" "q" "=" qvalue ] )
+ // language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5"
+ $ua_langcodes = array();
+ if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($http_accept_language), $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $match) {
+ if ($mappings) {
+ $langcode = strtolower($match[1]);
+ foreach ($mappings as $ua_langcode => $standard_langcode) {
+ if ($langcode == $ua_langcode) {
+ $match[1] = $standard_langcode;
+ }
+ }
+ }
+ // We can safely use strtolower() here, tags are ASCII.
+ // RFC2616 mandates that the decimal part is no more than three digits,
+ // so we multiply the qvalue by 1000 to avoid floating point
+ // comparisons.
+ $langcode = strtolower($match[1]);
+ $qvalue = isset($match[2]) ? (float) $match[2] : 1;
+ // Take the highest qvalue for this langcode. Although the request
+ // supposedly contains unique langcodes, our mapping possibly resolves
+ // to the same langcode for different qvalues. Keep the highest.
+ $ua_langcodes[$langcode] = max(
+ (int) ($qvalue * 1000),
+ (isset($ua_langcodes[$langcode]) ? $ua_langcodes[$langcode] : 0)
+ );
+ }
+ }
+
+ // We should take pristine values from the HTTP headers, but Internet
+ // Explorer from version 7 sends only specific language tags (eg. fr-CA)
+ // without the corresponding generic tag (fr) unless explicitly configured.
+ // In that case, we assume that the lowest value of the specific tags is the
+ // value of the generic language to be as close to the HTTP 1.1 spec as
+ // possible.
+ // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 and
+ // http://blogs.msdn.com/b/ie/archive/2006/10/17/accept-language-header-for-internet-explorer-7.aspx
+ asort($ua_langcodes);
+ foreach ($ua_langcodes as $langcode => $qvalue) {
+ // For Chinese languages the generic tag is either zh-hans or zh-hant, so
+ // we need to handle this separately, we can not split $langcode on the
+ // first occurrence of '-' otherwise we get a non-existing language zh.
+ // All other languages use a langcode without a '-', so we can safely
+ // split on the first occurrence of it.
+ $generic_tag = '';
+ if (strlen($langcode) > 7 && (substr($langcode, 0, 7) == 'zh-hant' || substr($langcode, 0, 7) == 'zh-hans')) {
+ $generic_tag = substr($langcode, 0, 7);
+ }
+ else {
+ $generic_tag = strtok($langcode, '-');
+ }
+ if (!empty($generic_tag) && !isset($ua_langcodes[$generic_tag])) {
+ // Add the generic langcode, but make sure it has a lower qvalue as the
+ // more specific one, so the more specific one gets selected if it's
+ // defined by both the user agent and us.
+ $ua_langcodes[$generic_tag] = $qvalue - 0.1;
+ }
+ }
+
+ // Find the enabled language with the greatest qvalue, following the rules
+ // of RFC 2616 (section 14.4). If several languages have the same qvalue,
+ // prefer the one with the greatest weight.
+ $best_match_langcode = FALSE;
+ $max_qvalue = 0;
+ foreach ($langcodes as $langcode_case_sensitive) {
+ // Language tags are case insensitive (RFC2616, sec 3.10).
+ $langcode = strtolower($langcode_case_sensitive);
+
+ // If nothing matches below, the default qvalue is the one of the wildcard
+ // language, if set, or is 0 (which will never match).
+ $qvalue = isset($ua_langcodes['*']) ? $ua_langcodes['*'] : 0;
+
+ // Find the longest possible prefix of the user agent supplied language
+ // ('the language-range') that matches this site language ('the language
+ // tag').
+ $prefix = $langcode;
+ do {
+ if (isset($ua_langcodes[$prefix])) {
+ $qvalue = $ua_langcodes[$prefix];
+ break;
+ }
+ }
+ while ($prefix = substr($prefix, 0, strrpos($prefix, '-')));
+
+ // Find the best match.
+ if ($qvalue > $max_qvalue) {
+ $best_match_langcode = $langcode_case_sensitive;
+ $max_qvalue = $qvalue;
+ }
+ }
+
+ return $best_match_langcode;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Datetime/Date.php b/core/lib/Drupal/Core/Datetime/Date.php
index 34b863227f9..18f2425fdc7 100644
--- a/core/lib/Drupal/Core/Datetime/Date.php
+++ b/core/lib/Drupal/Core/Datetime/Date.php
@@ -12,7 +12,7 @@ use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
/**
@@ -37,7 +37,7 @@ class Date {
/**
* Language manager for retrieving the default langcode when none is specified.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -75,12 +75,14 @@ class Date {
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
* The string translation.
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The configuration factory.
*/
- public function __construct(EntityManagerInterface $entity_manager, LanguageManager $language_manager, TranslationInterface $translation, ConfigFactory $config_factory) {
+ public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, TranslationInterface $translation, ConfigFactory $config_factory) {
$this->dateFormatStorage = $entity_manager->getStorageController('date_format');
$this->languageManager = $language_manager;
$this->stringTranslation = $translation;
@@ -128,7 +130,7 @@ class Date {
}
if (empty($langcode)) {
- $langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $langcode = $this->languageManager->getCurrentLanguage()->id;
}
// Create a DrupalDateTime object from the timestamp and timezone.
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 5652085611d..9185c3222b9 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -142,7 +142,7 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface
$this->discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
$this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
$this->discovery = new AlterDecorator($this->discovery, 'entity_info');
- $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
+ $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getCurrentLanguage()->id, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
$this->factory = new DefaultFactory($this->discovery);
$this->container = $container;
}
@@ -321,7 +321,7 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface
public function getFieldDefinitions($entity_type, $bundle = NULL) {
if (!isset($this->entityFieldInfo[$entity_type])) {
// First, try to load from cache.
- $cid = 'entity_field_definitions:' . $entity_type . ':' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $cid = 'entity_field_definitions:' . $entity_type . ':' . $this->languageManager->getCurrentLanguage()->id;
if ($cache = $this->cache->get($cid)) {
$this->entityFieldInfo[$entity_type] = $cache->data;
}
@@ -420,7 +420,7 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface
*/
public function getAllBundleInfo() {
if (!isset($this->bundleInfo)) {
- $langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $langcode = $this->languageManager->getCurrentLanguage()->id;
if ($cache = $this->cache->get("entity_bundle_info:$langcode")) {
$this->bundleInfo = $cache->data;
}
@@ -460,7 +460,7 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface
if ($entity instanceof TranslatableInterface) {
if (empty($langcode)) {
- $langcode = $this->languageManager->getLanguage(Language::TYPE_CONTENT)->id;
+ $langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id;
}
// Retrieve language fallback candidates to perform the entity language
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index 1f09b3b53f6..64425770153 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -9,6 +9,7 @@ namespace Drupal\Core\Entity;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -48,17 +49,27 @@ class EntityViewBuilder implements EntityControllerInterface, EntityViewBuilderI
protected $cacheBin = 'cache';
/**
+ * The language manager.
+ *
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ */
+ protected $languageManager;
+
+ /**
* Constructs a new EntityViewBuilder.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_info
* The entity information array.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager service.
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ * The language manager.
*/
- public function __construct(EntityTypeInterface $entity_info, EntityManagerInterface $entity_manager) {
+ public function __construct(EntityTypeInterface $entity_info, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
$this->entityType = $entity_info->id();
$this->entityInfo = $entity_info;
$this->entityManager = $entity_manager;
+ $this->languageManager = $language_manager;
}
/**
@@ -67,7 +78,8 @@ class EntityViewBuilder implements EntityControllerInterface, EntityViewBuilderI
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_info) {
return new static(
$entity_info,
- $container->get('entity.manager')
+ $container->get('entity.manager'),
+ $container->get('language_manager')
);
}
@@ -174,7 +186,7 @@ class EntityViewBuilder implements EntityControllerInterface, EntityViewBuilderI
*/
public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) {
if (!isset($langcode)) {
- $langcode = language(Language::TYPE_CONTENT)->id;
+ $langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id;
}
// Build the view modes and display objects.
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 112644f5603..8e4596f1279 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -55,7 +55,7 @@ class FinishResponseSubscriber implements EventSubscriberInterface {
$response->headers->set('X-UA-Compatible', 'IE=edge,chrome=1', FALSE);
// Set the Content-language header.
- $response->headers->set('Content-language', $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id);
+ $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->id);
// Because pages are highly dynamic, set the last-modified time to now
// since the page is in fact being regenerated right now.
diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php
index 8a5015725ef..f0c36ffae87 100644
--- a/core/lib/Drupal/Core/Language/Language.php
+++ b/core/lib/Drupal/Core/Language/Language.php
@@ -18,6 +18,23 @@ namespace Drupal\Core\Language;
*/
class Language {
+ /**
+ * The values to use to instantiate the default language.
+ *
+ * @todo Remove once the default language is converted to config. See
+ * https://drupal.org/node/2108599.
+ *
+ * @var array
+ */
+ public static $defaultValues = array(
+ 'id' => 'en',
+ 'name' => 'English',
+ 'direction' => 0,
+ 'weight' => 0,
+ 'locked' => 0,
+ 'default' => TRUE,
+ );
+
// Properties within the Language are set up as the default language.
/**
diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php
index a7dfbc0bbde..d21cb9f1ef6 100644
--- a/core/lib/Drupal/Core/Language/LanguageManager.php
+++ b/core/lib/Drupal/Core/Language/LanguageManager.php
@@ -7,245 +7,198 @@
namespace Drupal\Core\Language;
-use Drupal\Component\Utility\MapArray;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\KeyValueStore\StateInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Component\Utility\String;
+use Drupal\Core\StringTranslation\TranslationInterface;
/**
- * Class responsible for initializing each language type.
+ * Class responsible for providing language support on language-unaware sites.
*/
-class LanguageManager {
+class LanguageManager implements LanguageManagerInterface {
/**
- * A request object.
+ * The string translation service.
*
- * @var \Symfony\Component\HttpFoundation\Request
+ * @var \Drupal\Core\StringTranslation\TranslationInterface
*/
- protected $request;
+ protected $translation;
/**
- * The Key/Value Store to use for state.
+ * An array of all the available languages keyed by language code.
*
- * @var \Drupal\Core\KeyValueStore\StateInterface
+ * @var array
*/
- protected $state = NULL;
+ protected $languages;
/**
- * The module handler service.
+ * The default language object.
*
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ * @var \Drupal\Core\Language\Language
*/
- protected $moduleHandler;
+ protected $defaultLanguage;
/**
- * An array of language objects keyed by language type.
- *
- * @var array
+ * {@inheritdoc}
*/
- protected $languages;
+ function setTranslation(TranslationInterface $translation) {
+ $this->translation = $translation;
+ }
/**
- * Whether or not the language manager has been initialized.
+ * Translates a string to the current language or to a given language.
*
- * @var bool
+ * @see \Drupal\Core\StringTranslation\TranslationInterface()
*/
- protected $initialized = FALSE;
+ protected function t($string, array $args = array(), array $options = array()) {
+ return $this->translation ? $this->translation->translate($string, $args, $options) : String::format($string, $args);
+ }
/**
- * Whether already in the process of language initialization.
- *
- * @todo This is only needed due to the circular dependency between language
- * and config. See http://drupal.org/node/1862202 for the plan to fix this.
- *
- * @var bool
+ * {@inheritdoc}
*/
- protected $initializing = FALSE;
+ public function init() {
+ }
/**
- * Constructs an LanguageManager object.
- *
- * @param \Drupal\Core\KeyValueStore\StateInterface $state
- * (optional) The state keyvalue store. Defaults to NULL.
- * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
- * (optional) The module handler service. Defaults to NULL.
+ * {@inheritdoc}
*/
- public function __construct(StateInterface $state = NULL, ModuleHandlerInterface $module_handler = NULL) {
- $this->state = $state;
- $this->moduleHandler = $module_handler;
+ public function isMultilingual() {
+ return FALSE;
}
/**
- * Initializes each language type to a language object.
+ * {@inheritdoc}
*/
- public function init() {
- if ($this->initialized) {
- return;
- }
- if ($this->isMultilingual()) {
- foreach ($this->getLanguageTypes() as $type) {
- $this->getLanguage($type);
- }
- }
- $this->initialized = TRUE;
+ public function getLanguageTypes() {
+ return array(Language::TYPE_INTERFACE, Language::TYPE_CONTENT, Language::TYPE_URL);
}
/**
- * Sets the $request property and resets all language types.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- * The HttpRequest object representing the current request.
+ * {@inheritdoc}
*/
- public function setRequest(Request $request) {
- $this->request = $request;
- $this->reset();
- $this->init();
+ public function getCurrentLanguage($type = Language::TYPE_INTERFACE) {
+ return $this->getDefaultLanguage();
}
/**
- * Returns a language object for the given type.
- *
- * @param string $type
- * (optional) The language type, e.g. the interface or the content language.
- * Defaults to \Drupal\Core\Language\Language::TYPE_INTERFACE.
- *
- * @return \Drupal\Core\Language\Language
- * A language object for the given type.
+ * {@inheritdoc}
*/
- public function getLanguage($type = Language::TYPE_INTERFACE) {
- if (isset($this->languages[$type])) {
- return $this->languages[$type];
- }
+ public function reset($type = NULL) {
+ }
- if ($this->isMultilingual() && $this->request) {
- if (!$this->initializing) {
- $this->initializing = TRUE;
- // @todo Objectify the language system so that we don't have to load an
- // include file and call out to procedural code. See
- // http://drupal.org/node/1862202
- include_once DRUPAL_ROOT . '/core/includes/language.inc';
- $this->languages[$type] = language_types_initialize($type, $this->request);
- $this->initializing = FALSE;
- }
- else {
- // Config has called getLanguage() during initialization of a language
- // type. Simply return the default language without setting it on the
- // $this->languages property. See the TODO in the docblock for the
- // $initializing property.
- return $this->getLanguageDefault();
- }
- }
- else {
- $this->languages[$type] = $this->getLanguageDefault();
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultLanguage() {
+ if (!isset($this->defaultLanguage)) {
+ $this->defaultLanguage = new Language(Language::$defaultValues);
}
- return $this->languages[$type];
+ return $this->defaultLanguage;
}
/**
- * Resets the given language type or all types if none specified.
- *
- * @param string|null $type
- * (optional) The language type to reset as a string, e.g.,
- * Language::TYPE_INTERFACE, or NULL to reset all language types. Defaults
- * to NULL.
+ * {@inheritdoc}
*/
- public function reset($type = NULL) {
- if (!isset($type)) {
- $this->languages = array();
- $this->initialized = FALSE;
+ public function getLanguages($flags = Language::STATE_CONFIGURABLE) {
+ // Initialize master language list.
+ if (!isset($this->languages)) {
+ // No language module, so use the default language only.
+ $default = $this->getDefaultLanguage();
+ $this->languages = array($default->id => $default);
+ // Add the special languages, they will be filtered later if needed.
+ $this->languages += $this->getDefaultLockedLanguages($default->weight);
}
- elseif (isset($this->languages[$type])) {
- unset($this->languages[$type]);
+
+ // Filter the full list of languages based on the value of the $all flag. By
+ // default we remove the locked languages, but the caller may request for
+ // those languages to be added as well.
+ $filtered_languages = array();
+
+ // Add the site's default language if flagged as allowed value.
+ if ($flags & Language::STATE_SITE_DEFAULT) {
+ $default = isset($default) ? $default : $this->getDefaultLanguage();
+ // Rename the default language.
+ $default->name = $this->t("Site's default language (@lang_name)", array('@lang_name' => $default->name));
+ $filtered_languages['site_default'] = $default;
+ }
+
+ foreach ($this->languages as $id => $language) {
+ if (($language->locked && ($flags & Language::STATE_LOCKED)) || (!$language->locked && ($flags & Language::STATE_CONFIGURABLE))) {
+ $filtered_languages[$id] = $language;
+ }
}
+
+ return $filtered_languages;
}
/**
- * Returns whether or not the site has more than one language enabled.
- *
- * @return bool
- * TRUE if more than one language is enabled, FALSE otherwise.
+ * {@inheritdoc}
*/
- public function isMultilingual() {
- if (!isset($this->state)) {
- // No state service in install time.
- return FALSE;
+ public function getLanguage($langcode) {
+ $languages = $this->getLanguages(Language::STATE_ALL);
+ return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function getLanguageName($langcode) {
+ if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
+ return $this->t('None');
}
- return ($this->state->get('language_count') ?: 1) > 1;
+ if ($language = $this->getLanguage($langcode)) {
+ return $language->name;
+ }
+ if (empty($langcode)) {
+ return $this->t('Unknown');
+ }
+ return $this->t('Unknown (@langcode)', array('@langcode' => $langcode));
}
/**
- * Returns the language fallback candidates for a given context.
- *
- * @param string $langcode
- * (optional) The language of the current context. Defaults to NULL.
- * @param array $context
- * (optional) An associative array of data that can be useful to determine
- * the fallback sequence. The following keys are used in core:
- * - langcode: The desired language.
- * - operation: The name of the operation indicating the context where
- * language fallback is being applied, e.g. 'entity_view'.
- * - data: An arbitrary data structure that makes sense in the provided
- * context, e.g. an entity.
- *
- * @return array
- * An array of language codes sorted by priority: first values should be
- * tried first.
+ * {@inheritdoc}
*/
- public function getFallbackCandidates($langcode = NULL, array $context = array()) {
- if ($this->isMultilingual()) {
- // Get languages ordered by weight, add Language::LANGCODE_NOT_SPECIFIED at
- // the end.
- $candidates = array_keys(language_list());
- $candidates[] = Language::LANGCODE_NOT_SPECIFIED;
- $candidates = MapArray::copyValuesToKeys($candidates);
+ public function getDefaultLockedLanguages($weight = 0) {
+ $languages = array();
- // The first candidate should always be the desired language if specified.
- if (!empty($langcode)) {
- $candidates = array($langcode => $langcode) + $candidates;
- }
+ $locked_language = array(
+ 'default' => FALSE,
+ 'locked' => TRUE,
+ );
+ $languages[Language::LANGCODE_NOT_SPECIFIED] = new Language(array(
+ 'id' => Language::LANGCODE_NOT_SPECIFIED,
+ 'name' => $this->t('Not specified'),
+ 'weight' => ++$weight,
+ ) + $locked_language);
- // Let other modules hook in and add/change candidates.
- $type = 'language_fallback_candidates';
- $types = array();
- if (!empty($context['operation'])) {
- $types[] = $type . '_' . $context['operation'];
- }
- $types[] = $type;
- $this->moduleHandler->alter($types, $candidates, $context);
- }
- else {
- $candidates = array(Language::LANGCODE_DEFAULT);
- }
+ $languages[Language::LANGCODE_NOT_APPLICABLE] = new Language(array(
+ 'id' => Language::LANGCODE_NOT_APPLICABLE,
+ 'name' => $this->t('Not applicable'),
+ 'weight' => ++$weight,
+ ) + $locked_language);
- return $candidates;
+ return $languages;
}
/**
- * Returns an array of the available language types.
- *
- * @return array()
- * An array of all language types.
+ * {@inheritdoc}
*/
- protected function getLanguageTypes() {
- return language_types_get_all();
+ public function isLanguageLocked($langcode) {
+ $language = $this->getLanguage($langcode);
+ return ($language ? $language->locked : FALSE);
}
/**
- * Returns a language object representing the site's default language.
- *
- * @return \Drupal\Core\Language\Language
- * A language object.
+ * {@inheritdoc}
+ */
+ public function getFallbackCandidates($langcode = NULL, array $context = array()) {
+ return array(Language::LANGCODE_DEFAULT);
+ }
+
+ /**
+ * {@inheritdoc}
*/
- public function getLanguageDefault() {
- $default_info = variable_get('language_default', array(
- 'id' => 'en',
- 'name' => 'English',
- 'direction' => 0,
- 'weight' => 0,
- 'locked' => 0,
- ));
- $default_info['default'] = TRUE;
- return new Language($default_info);
+ public function getLanguageSwitchLinks($type, $path) {
+ return array();
}
/**
diff --git a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
new file mode 100644
index 00000000000..159c39c6329
--- /dev/null
+++ b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Language\LanguageManagerInterface.
+ */
+
+namespace Drupal\Core\Language;
+
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Common interface for the language manager service.
+ */
+interface LanguageManagerInterface {
+
+ /**
+ * Injects the string translation service.
+ *
+ * @param \use Drupal\Core\StringTranslation\TranslationInterface $translation
+ * The string translation service.
+ */
+ function setTranslation(TranslationInterface $translation);
+
+ /**
+ * Initializes each language type to a language object.
+ */
+ public function init();
+
+ /**
+ * Returns whether or not the site has more than one language enabled.
+ *
+ * @return bool
+ * TRUE if more than one language is enabled, FALSE otherwise.
+ */
+ public function isMultilingual();
+
+ /**
+ * Returns an array of the available language types.
+ *
+ * @return array
+ * An array of language type names.
+ */
+ public function getLanguageTypes();
+
+ /**
+ * Returns the current language for the given type.
+ *
+ * @param string $type
+ * (optional) The language type, e.g. the interface or the content language.
+ * Defaults to \Drupal\Core\Language\Language::TYPE_INTERFACE.
+ *
+ * @return \Drupal\Core\Language\Language
+ * A language object for the given type.
+ */
+ public function getCurrentLanguage($type = Language::TYPE_INTERFACE);
+
+ /**
+ * Resets the given language type or all types if none specified.
+ *
+ * @param string|null $type
+ * (optional) The language type to reset as a string, e.g.,
+ * Language::TYPE_INTERFACE, or NULL to reset all language types. Defaults
+ * to NULL.
+ */
+ public function reset($type = NULL);
+
+ /**
+ * Returns a language object representing the site's default language.
+ *
+ * @return \Drupal\Core\Language\Language
+ * A language object.
+ */
+ public function getDefaultLanguage();
+
+ /**
+ * Returns a list of languages set up on the site.
+ *
+ * @param $flags
+ * (optional) Specifies the state of the languages that have to be
+ * returned. It can be: Language::STATE_CONFIGURABLE,
+ * Language::STATE_LOCKED, Language::STATE_ALL.
+ *
+ * @return array
+ * An associative array of languages, keyed by the language code, ordered
+ * by weight ascending and name ascending.
+ */
+ public function getLanguages($flags = Language::STATE_CONFIGURABLE);
+
+ /**
+ * Returns a language object from the given language code.
+ *
+ * @param string $langcode
+ * The language code.
+ *
+ * @return \Drupal\core\Language\Language|null
+ * A fully-populated language object or NULL.
+ */
+ public function getLanguage($langcode);
+
+ /**
+ * Produced the printed name for a language for display.
+ *
+ * @param string $langcode
+ * The language code.
+ *
+ * @return string
+ * The printed name of the language.
+ */
+ function getLanguageName($langcode);
+
+ /**
+ * Returns a list of the default locked languages.
+ *
+ * @param int $weight
+ * (optional) An integer value that is used as the start value for the
+ * weights of the locked languages.
+ *
+ * @return array
+ * An array of language objects.
+ */
+ public function getDefaultLockedLanguages($weight = 0);
+
+ /**
+ * Checks whether a language is locked.
+ *
+ * @param string $langcode
+ * The language code.
+ *
+ * @return bool
+ * Returns whether the language is locked.
+ */
+ public function isLanguageLocked($langcode);
+
+ /**
+ * Returns the language fallback candidates for a given context.
+ *
+ * @param string $langcode
+ * (optional) The language of the current context. Defaults to NULL.
+ * @param array $context
+ * (optional) An associative array of data that can be useful to determine
+ * the fallback sequence. The following keys are used in core:
+ * - langcode: The desired language.
+ * - operation: The name of the operation indicating the context where
+ * language fallback is being applied, e.g. 'entity_view'.
+ * - data: An arbitrary data structure that makes sense in the provided
+ * context, e.g. an entity.
+ *
+ * @return array
+ * An array of language codes sorted by priority: first values should be
+ * tried first.
+ */
+ public function getFallbackCandidates($langcode = NULL, array $context = array());
+
+ /**
+ * Returns the language switch links for the given language type.
+ *
+ * @param $type
+ * The language type.
+ * @param $path
+ * The internal path the switch links will be relative to.
+ *
+ * @return array
+ * A keyed array of links ready to be themed.
+ */
+ function getLanguageSwitchLinks($type, $path);
+
+}
diff --git a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
index 6543fbc990e..ad29a5b0840 100644
--- a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
+++ b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
@@ -90,7 +90,7 @@ class DefaultHtmlPageRenderer implements HtmlPageRendererInterface {
$page_array['#page'] = $page;
// HTML element attributes.
- $language_interface = $this->languageManager->getLanguage(Language::TYPE_INTERFACE);
+ $language_interface = $this->languageManager->getCurrentLanguage();
$html_attributes = $page->getHtmlAttributes();
$html_attributes['lang'] = $language_interface->id;
$html_attributes['dir'] = $language_interface->direction ? 'rtl' : 'ltr';
diff --git a/core/lib/Drupal/Core/Path/AliasManager.php b/core/lib/Drupal/Core/Path/AliasManager.php
index 151bb23d509..a9470681719 100644
--- a/core/lib/Drupal/Core/Path/AliasManager.php
+++ b/core/lib/Drupal/Core/Path/AliasManager.php
@@ -96,7 +96,7 @@ class AliasManager implements AliasManagerInterface {
// language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path
// alias matching the URL path.
- $path_language = $path_language ?: $this->languageManager->getLanguage(Language::TYPE_URL)->id;
+ $path_language = $path_language ?: $this->languageManager->getCurrentLanguage(Language::TYPE_URL)->id;
// Lookup the path alias first.
if (!empty($path) && $source = $this->lookupPathSource($path, $path_language)) {
$path = $source;
@@ -113,7 +113,7 @@ class AliasManager implements AliasManagerInterface {
// language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path
// alias matching the URL path.
- $path_language = $path_language ?: $this->languageManager->getLanguage(Language::TYPE_URL)->id;
+ $path_language = $path_language ?: $this->languageManager->getCurrentLanguage(Language::TYPE_URL)->id;
$result = $path;
if (!empty($path) && $alias = $this->lookupPathAlias($path, $path_language)) {
$result = $alias;
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
index ce93bab2140..712c5eec4b6 100644
--- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -14,7 +14,7 @@ use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Factory\ContainerFactory;
@@ -84,7 +84,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
/**
* The language manager.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -115,7 +115,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
*
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
- * @param \Drupal\Core\Language\LanguageManager
+ * @param \Drupal\Core\Language\LanguageManagerInterface
* The language manager.
* @param string $cache_key_prefix
* Cache key prefix to use, the language code will be appended
@@ -129,11 +129,11 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
* clearCachedDefinitions() method. Only use cache tags when cached plugin
* definitions should be cleared along with other, related cache entries.
*/
- public function setCacheBackend(CacheBackendInterface $cache_backend, LanguageManager $language_manager, $cache_key_prefix, array $cache_tags = array()) {
+ public function setCacheBackend(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, $cache_key_prefix, array $cache_tags = array()) {
$this->languageManager = $language_manager;
$this->cacheBackend = $cache_backend;
$this->cacheKeyPrefix = $cache_key_prefix;
- $this->cacheKey = $cache_key_prefix . ':' . $language_manager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $this->cacheKey = $cache_key_prefix . ':' . $language_manager->getCurrentLanguage()->id;
$this->cacheTags = $cache_tags;
}
@@ -186,14 +186,16 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
// Use the cache tags to clear the cache.
$this->cacheBackend->deleteTags($this->cacheTags);
}
- else {
+ elseif ($this->languageManager) {
$cache_keys = array();
- // @todo: Use $this->languageManager->languageList() after http://drupal.org/node/1862202 is in.
- foreach (language_list() as $langcode => $language) {
- $cache_keys[] = $this->cacheKeyPrefix . ':' .$langcode;
+ foreach ($this->languageManager->getLanguages() as $langcode => $language) {
+ $cache_keys[] = $this->cacheKeyPrefix . ':' . $langcode;
}
$this->cacheBackend->deleteMultiple($cache_keys);
}
+ else {
+ $this->cacheBackend->delete($this->cacheKey);
+ }
}
$this->definitions = NULL;
}
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
index 191ece45a91..bd1b3b3a019 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
@@ -7,8 +7,9 @@
namespace Drupal\Core\StringTranslation;
-use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
use Drupal\Component\Utility\String;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
/**
* Defines a chained translation implementation combining multiple translators.
@@ -16,6 +17,13 @@ use Drupal\Component\Utility\String;
class TranslationManager implements TranslationInterface, TranslatorInterface {
/**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
* An array of active translators keyed by priority.
*
* @var array
@@ -46,11 +54,24 @@ class TranslationManager implements TranslationInterface, TranslatorInterface {
/**
* Constructs a TranslationManager object.
+ *
+ * @param \Drupal\Core\Language\LanguageManagerInterface
+ * The language manager.
+ */
+ public function __construct(LanguageManagerInterface $language_manager) {
+ $this->languageManager = $language_manager;
+ $this->defaultLangcode = $language_manager->getDefaultLanguage()->id;
+ }
+
+ /**
+ * Initializes the injected language manager with the translation manager.
+ *
+ * This should be called right after instantiating the translation manager to
+ * make it available to the language manager without introducing a circular
+ * dependency.
*/
- public function __construct() {
- // @todo Inject language_manager or config system after language_default
- // variable is converted to CMI.
- $this->defaultLangcode = language_default()->id;
+ public function initLanguageManager() {
+ $this->languageManager->setTranslation($this);
}
/**
diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php b/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php
index 3debb1f9a91..667c3eb66ba 100644
--- a/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php
+++ b/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php
@@ -38,7 +38,7 @@ class CustomStrings extends StaticTranslation {
/**
* {@inheritdoc}
*/
- protected function loadLanguage($langcode) {
+ protected function getLanguage($langcode) {
return $this->settings->get('locale_custom_strings_' . $langcode, array());
}
diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/FileTranslation.php b/core/lib/Drupal/Core/StringTranslation/Translator/FileTranslation.php
index 3e162b13fc1..ecd5a61634e 100644
--- a/core/lib/Drupal/Core/StringTranslation/Translator/FileTranslation.php
+++ b/core/lib/Drupal/Core/StringTranslation/Translator/FileTranslation.php
@@ -41,7 +41,7 @@ class FileTranslation extends StaticTranslation {
/**
* {@inheritdoc}
*/
- protected function loadLanguage($langcode) {
+ protected function getLanguage($langcode) {
// If the given langcode was selected, there should be at least one .po
// file with its name in the pattern drupal-$version.$langcode.po.
// This might or might not be the entire filename. It is also possible
diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php b/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php
index fd72f5e1cfb..1b88a7a16ae 100644
--- a/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php
+++ b/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php
@@ -37,7 +37,7 @@ class StaticTranslation implements TranslatorInterface {
*/
public function getStringTranslation($langcode, $string, $context) {
if (!isset($this->translations[$langcode])) {
- $this->translations[$langcode] = $this->loadLanguage($langcode);
+ $this->translations[$langcode] = $this->getLanguage($langcode);
}
if (isset($this->translations[$langcode][$context][$string])) {
return $this->translations[$langcode][$context][$string];
@@ -60,7 +60,7 @@ class StaticTranslation implements TranslatorInterface {
* @param string $langcode
* The langcode of the language.
*/
- protected function loadLanguage($langcode) {
+ protected function getLanguage($langcode) {
// This class is usually a base class but we do not declare as abstract
// because it can be used on its own, by passing a simple array on the
// constructor. This can be useful while testing, but it does not support
diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php
index 3f6362064ed..1628e635e9e 100644
--- a/core/lib/Drupal/Core/Utility/LinkGenerator.php
+++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php
@@ -10,7 +10,7 @@ namespace Drupal\Core\Utility;
use Drupal\Component\Utility\String;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
@@ -45,7 +45,7 @@ class LinkGenerator implements LinkGeneratorInterface {
/**
* The language manager.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -56,10 +56,10 @@ class LinkGenerator implements LinkGeneratorInterface {
* The url generator.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
- public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
+ public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) {
$this->urlGenerator = $url_generator;
$this->moduleHandler = $module_handler;
$this->languageManager = $language_manager;
@@ -79,7 +79,7 @@ class LinkGenerator implements LinkGeneratorInterface {
$parameters = $raw_variables ? $raw_variables->all() : array();
$this->active = array(
'route_name' => $request->attributes->get(RouteObjectInterface::ROUTE_NAME),
- 'language' => $this->languageManager->getLanguage(Language::TYPE_URL)->id,
+ 'language' => $this->languageManager->getCurrentLanguage(Language::TYPE_URL)->id,
'parameters' => $parameters + (array) $request->query->all(),
);
}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
index 3befde0bf68..b3d2e615222 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
@@ -111,7 +111,7 @@ class CustomBlockFormController extends ContentEntityFormController {
// Set the correct default language.
if ($block->isNew()) {
- $language_default = $this->languageManager->getLanguage($language_configuration['langcode']);
+ $language_default = $this->languageManager->getCurrentLanguage($language_configuration['langcode']);
$block->langcode->value = $language_default->id;
}
}
diff --git a/core/modules/block/lib/Drupal/block/BlockFormController.php b/core/modules/block/lib/Drupal/block/BlockFormController.php
index 92bbe88ccc1..fba5659e312 100644
--- a/core/modules/block/lib/Drupal/block/BlockFormController.php
+++ b/core/modules/block/lib/Drupal/block/BlockFormController.php
@@ -13,7 +13,8 @@ use Drupal\Core\Entity\EntityFormController;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\language\ConfigurableLanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -45,7 +46,7 @@ class BlockFormController extends EntityFormController {
/**
* The language manager.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -63,12 +64,12 @@ class BlockFormController extends EntityFormController {
* The entity manager.
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
* The entity query factory.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
*/
- public function __construct(EntityManagerInterface $entity_manager, QueryFactory $entity_query_factory, LanguageManager $language_manager, ConfigFactory $config_factory) {
+ public function __construct(EntityManagerInterface $entity_manager, QueryFactory $entity_query_factory, LanguageManagerInterface $language_manager, ConfigFactory $config_factory) {
$this->storageController = $entity_manager->getStorageController('block');
$this->entityQueryFactory = $entity_query_factory;
$this->languageManager = $language_manager;
@@ -168,11 +169,11 @@ class BlockFormController extends EntityFormController {
}
// Configure the block visibility per language.
- if ($this->moduleHandler->moduleExists('language') && $this->languageManager->isMultilingual()) {
- $configurable_language_types = language_types_get_configurable();
+ if ($this->languageManager->isMultilingual() && $this->languageManager instanceof ConfigurableLanguageManagerInterface) {
+ $language_types = $this->languageManager->getLanguageTypes();
// Fetch languages.
- $languages = language_list(Language::STATE_ALL);
+ $languages = $this->languageManager->getLanguages(Language::STATE_ALL);
$langcodes_options = array();
foreach ($languages as $language) {
// @todo $language->name is not wrapped with t(), it should be replaced
@@ -189,16 +190,16 @@ class BlockFormController extends EntityFormController {
// If there are multiple configurable language types, let the user pick
// which one should be applied to this visibility setting. This way users
// can limit blocks by interface language or content language for example.
- $language_types = language_types_info();
+ $info = $this->languageManager->getDefinedLanguageTypesInfo();
$language_type_options = array();
- foreach ($configurable_language_types as $type_key) {
- $language_type_options[$type_key] = $language_types[$type_key]['name'];
+ foreach ($language_types as $type_key) {
+ $language_type_options[$type_key] = $info[$type_key]['name'];
}
$form['visibility']['language']['language_type'] = array(
'#type' => 'radios',
'#title' => $this->t('Language type'),
'#options' => $language_type_options,
- '#default_value' => !empty($visibility['language']['language_type']) ? $visibility['language']['language_type'] : $configurable_language_types[0],
+ '#default_value' => !empty($visibility['language']['language_type']) ? $visibility['language']['language_type'] : reset($language_types),
'#access' => count($language_type_options) > 1,
);
$form['visibility']['language']['langcodes'] = array(
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
index 2e4a4c6e5b6..e2bb9dac73c 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php
@@ -74,14 +74,13 @@ class BlockLanguageTest extends WebTestBase {
$this->drupalPostForm('admin/config/regional/settings', $edit, t('Save configuration'));
// Reset the static cache of the language list.
- drupal_static_reset('language_list');
-
+ $this->container->get('language_manager')->reset();
// Check that a page has a block.
- $this->drupalget('', array('language' => language_load('en')));
+ $this->drupalGet('en');
$this->assertText('Powered by Drupal', 'The body of the custom block appears on the page.');
// Check that a page doesn't has a block for the current language anymore.
- $this->drupalGet('', array('language' => language_load('fr')));
+ $this->drupalGet('fr');
$this->assertNoText('Powered by Drupal', 'The body of the custom block does not appear on the page.');
}
diff --git a/core/modules/block/tests/Drupal/block/Tests/BlockFormControllerTest.php b/core/modules/block/tests/Drupal/block/Tests/BlockFormControllerTest.php
index 69b0a1bf1d4..f3ae6ef66a3 100644
--- a/core/modules/block/tests/Drupal/block/Tests/BlockFormControllerTest.php
+++ b/core/modules/block/tests/Drupal/block/Tests/BlockFormControllerTest.php
@@ -66,9 +66,7 @@ class BlockFormControllerTest extends UnitTestCase {
->method('getStorageController')
->will($this->returnValue($block_storage));
- $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$config_factory = $this->getMockBuilder('Drupal\Core\Config\ConfigFactory')
->disableOriginalConstructor()
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
index ae1ef56f5cc..837554959ef 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
@@ -265,7 +265,7 @@ class CKEditor extends EditorBase implements ContainerFactoryPluginInterface {
// Map the interface language code to a CKEditor translation.
$ckeditor_langcodes = $this->getLangcodes();
- $language_interface = $this->languageManager->getLanguage(Language::TYPE_INTERFACE);
+ $language_interface = $this->languageManager->getCurrentLanguage();
if (isset($ckeditor_langcodes[$language_interface->id])) {
$display_langcode = $ckeditor_langcodes[$language_interface->id];
}
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index 3f88b515f0a..0adb4fc6845 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -66,7 +66,7 @@ class CommentFormController extends ContentEntityFormController {
// Make the comment inherit the current content language unless specifically
// set.
if ($comment->isNew()) {
- $language_content = \Drupal::languageManager()->getLanguage(Language::TYPE_CONTENT);
+ $language_content = \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT);
$comment->langcode->value = $language_content->id;
}
diff --git a/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php b/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php
index 7dd6517f4b1..d23ee11ac5b 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php
@@ -16,6 +16,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Entity\EntityViewBuilder;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\field\FieldInfo;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -52,6 +53,7 @@ class CommentViewBuilder extends EntityViewBuilder implements EntityViewBuilderI
return new static(
$entity_info,
$container->get('entity.manager'),
+ $container->get('language_manager'),
$container->get('field.info'),
$container->get('module_handler'),
$container->get('csrf_token')
@@ -65,6 +67,8 @@ class CommentViewBuilder extends EntityViewBuilder implements EntityViewBuilderI
* The entity information array.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager service.
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ * The language manager.
* @param \Drupal\field\FieldInfo $field_info
* The field info service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -72,8 +76,8 @@ class CommentViewBuilder extends EntityViewBuilder implements EntityViewBuilderI
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
* The CSRF token manager service.
*/
- public function __construct(EntityTypeInterface $entity_info, EntityManagerInterface $entity_manager, FieldInfo $field_info, ModuleHandlerInterface $module_handler, CsrfTokenGenerator $csrf_token) {
- parent::__construct($entity_info, $entity_manager);
+ public function __construct(EntityTypeInterface $entity_info, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, FieldInfo $field_info, ModuleHandlerInterface $module_handler, CsrfTokenGenerator $csrf_token) {
+ parent::__construct($entity_info, $entity_manager, $language_manager);
$this->fieldInfo = $field_info;
$this->moduleHandler = $module_handler;
$this->csrfToken = $csrf_token;
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
index c76dd41c6aa..3e738ce7e08 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
@@ -83,7 +83,6 @@ class CommentLanguageTest extends WebTestBase {
* Test that comment language is properly set.
*/
function testCommentLanguage() {
- drupal_static_reset('language_list');
// Create two nodes, one for english and one for french, and comment each
// node using both english and french as content language by changing URL
diff --git a/core/modules/comment/tests/modules/comment_test/comment_test.module b/core/modules/comment/tests/modules/comment_test/comment_test.module
index 110e8c5e2d9..10f521b6c84 100644
--- a/core/modules/comment/tests/modules/comment_test/comment_test.module
+++ b/core/modules/comment/tests/modules/comment_test/comment_test.module
@@ -13,7 +13,7 @@ use Drupal\comment\CommentInterface;
*/
function comment_test_entity_info_alter(&$entity_info) {
/** @var $entity_info \Drupal\Core\Entity\EntityTypeInterface[] */
- if (language_multilingual()) {
+ if (\Drupal::languageManager()->isMultilingual()) {
// Enable language handling for comment fields.
$translation = $entity_info['comment']->get('translation');
$translation['comment_test'] = TRUE;
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
index edb431c1457..4331d6f7397 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php
@@ -13,7 +13,7 @@ use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\Config\TypedConfigManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\Core\Plugin\Discovery\InfoHookDecorator;
use Drupal\Core\Plugin\Discovery\YamlDiscovery;
@@ -49,14 +49,14 @@ class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperMa
*
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* The cache backend.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Config\TypedConfigManager $typed_config_manager
* The typed config manager.
*/
- public function __construct(CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, TypedConfigManager $typed_config_manager) {
+ public function __construct(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, TypedConfigManager $typed_config_manager) {
$this->typedConfigManager = $typed_config_manager;
// Look at all themes and modules.
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
index 3eb0216f94f..03c2a20afca 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php
@@ -12,6 +12,7 @@ use Drupal\Core\Access\AccessManager;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
@@ -62,6 +63,13 @@ class ConfigTranslationController extends ControllerBase implements ContainerInj
protected $account;
/**
+ * The language manager.
+ *
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ */
+ protected $languageManager;
+
+ /**
* Constructs a ConfigTranslationController.
*
* @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
@@ -74,13 +82,16 @@ class ConfigTranslationController extends ControllerBase implements ContainerInj
* The inbound path processor.
* @param \Drupal\Core\Session\AccountInterface $account
* The current user.
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ * The language manager.
*/
- public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManager $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account) {
+ public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManager $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager) {
$this->configMapperManager = $config_mapper_manager;
$this->accessManager = $access_manager;
$this->router = $router;
$this->pathProcessor = $path_processor;
$this->account = $account;
+ $this->languageManager = $language_manager;
}
/**
@@ -92,7 +103,8 @@ class ConfigTranslationController extends ControllerBase implements ContainerInj
$container->get('access_manager'),
$container->get('router'),
$container->get('path_processor_manager'),
- $container->get('current_user')
+ $container->get('current_user'),
+ $container->get('language_manager')
);
}
@@ -119,10 +131,10 @@ class ConfigTranslationController extends ControllerBase implements ContainerInj
// not on the system. For example, the configuration shipped in English but
// the site has no English configured. Represent the original language in
// the table even if it is not currently configured.
- $languages = language_list();
+ $languages = $this->languageManager->getLanguages();
$original_langcode = $mapper->getLangcode();
if (!isset($languages[$original_langcode])) {
- $language_name = language_name($original_langcode);
+ $language_name = $this->languageManager->getLanguageName($original_langcode);
if ($original_langcode == 'en') {
$language_name = $this->t('Built-in English');
}
diff --git a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php
index b07e54259c1..51575070139 100644
--- a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php
+++ b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php
@@ -47,9 +47,9 @@ class ConfigMapperManagerTest extends UnitTestCase {
public function setUp() {
$language = new Language(array('id' => 'en'));
- $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->once())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->with(Language::TYPE_INTERFACE)
->will($this->returnValue($language));
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index a39d8f4e98c..f509752e839 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -275,7 +275,7 @@ function content_translation_form_language_content_settings_validate(array $form
}
$values = $bundle_settings['settings']['language'];
- if (language_is_locked($values['langcode']) && empty($values['language_show'])) {
+ if (empty($values['language_show']) && \Drupal::languageManager()->isLanguageLocked($values['langcode'])) {
foreach (language_list(Language::STATE_LOCKED) as $language) {
$locked_languages[] = $language->name;
}
diff --git a/core/modules/content_translation/content_translation.install b/core/modules/content_translation/content_translation.install
index bd817bcb042..e474d693d8e 100644
--- a/core/modules/content_translation/content_translation.install
+++ b/core/modules/content_translation/content_translation.install
@@ -6,6 +6,7 @@
*/
use Drupal\Core\Language\Language;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
/**
* Implements hook_schema().
@@ -85,8 +86,7 @@ function content_translation_install() {
// Assign a fairly low weight to ensure our implementation of
// hook_module_implements_alter() is run among the last ones.
module_set_weight('content_translation', 10);
- language_negotiation_include();
- language_negotiation_set(Language::TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0));
+ \Drupal::service('language_negotiator')->saveConfiguration(Language::TYPE_CONTENT, array(LanguageNegotiationUrl::METHOD_ID => 0));
}
/**
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 70d20dc35bb..21b315a81c1 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -41,7 +41,7 @@ function content_translation_help($path, $arg) {
case 'admin/config/regional/content-language':
$output = '';
- if (!language_multilingual()) {
+ if (!\Drupal::languageManager()->isMultilingual()) {
$output .= '<br/>' . t('Before you can translate content, there must be at least two languages added on the <a href="!url">languages administration</a> page.', array('!url' => url('admin/config/regional/language')));
}
return $output;
@@ -331,7 +331,7 @@ function _content_translation_menu_strip_loaders($path) {
* The entity whose translation overview should be displayed.
*/
function content_translation_translate_access(EntityInterface $entity) {
- return $entity instanceof ContentEntityInterface && empty($entity->getUntranslated()->language()->locked) && language_multilingual() && $entity->isTranslatable() &&
+ return $entity instanceof ContentEntityInterface && empty($entity->getUntranslated()->language()->locked) && \Drupal::languageManager()->isMultilingual() && $entity->isTranslatable() &&
(user_access('create content translations') || user_access('update content translations') || user_access('delete content translations'));
}
@@ -955,7 +955,7 @@ function content_translation_language_configuration_element_process(array $eleme
function content_translation_language_configuration_element_validate($element, array &$form_state, array $form) {
$key = $form_state['content_translation']['key'];
$values = $form_state['values'][$key];
- if (language_is_locked($values['langcode']) && !$values['language_show'] && $values['content_translation']) {
+ if (!$values['language_show'] && $values['content_translation'] && \Drupal::languageManager()->isLanguageLocked($values['langcode'])) {
foreach (language_list(Language::STATE_LOCKED) as $language) {
$locked_languages[] = $language->name;
}
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index 43e53318e82..aa1b1f3890c 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -33,7 +33,7 @@ function content_translation_overview(EntityInterface $entity) {
$header = array(t('Language'), t('Translation'), t('Source language'), t('Status'), t('Operations'));
$rows = array();
- if (language_multilingual()) {
+ if (\Drupal::languageManager()->isMultilingual()) {
// If we have a view path defined for the current entity get the switch
// links based on it.
if (!empty($rel['canonical'])) {
@@ -159,12 +159,12 @@ function content_translation_overview(EntityInterface $entity) {
* A renderable array of language switch links.
*/
function _content_translation_get_switch_links($path) {
- $links = language_negotiation_get_switch_links(Language::TYPE_CONTENT, $path);
+ $links = \Drupal::languageManager()->getLanguageSwitchLinks(Language::TYPE_CONTENT, $path);
if (empty($links)) {
// If content language is set up to fall back to the interface language,
// then there will be no switch links for Language::TYPE_CONTENT, ergo we
// also need to use interface switch links.
- $links = language_negotiation_get_switch_links(Language::TYPE_INTERFACE, $path);
+ $links = \Drupal::languageManager()->getLanguageSwitchLinks(Language::TYPE_INTERFACE, $path);
}
return $links;
}
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
index 6c6b35083c5..cc3dacca637 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
@@ -257,7 +257,7 @@ class Field extends FieldPluginBase {
$default_langcode = language_default()->id;
$langcode = str_replace(
array('***CURRENT_LANGUAGE***', '***DEFAULT_LANGUAGE***'),
- array($this->languageManager->getLanguage(Language::TYPE_CONTENT), $default_langcode),
+ array($this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT), $default_langcode),
$this->view->display_handler->options['field_langcode']
);
$placeholder = $this->placeholder();
@@ -857,7 +857,7 @@ class Field extends FieldPluginBase {
$default_langcode = language_default()->id;
$langcode = str_replace(
array('***CURRENT_LANGUAGE***', '***DEFAULT_LANGUAGE***'),
- array($this->languageManager->getLanguage(Language::TYPE_CONTENT), $default_langcode),
+ array($this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT), $default_langcode),
$this->view->display_handler->options['field_language']
);
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 4962044ffd4..f206e621d3f 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -193,7 +193,7 @@ function filter_formats(AccountInterface $account = NULL) {
// All available formats are cached for performance.
if (!isset($formats['all'])) {
- $language_interface = \Drupal::languageManager()->getLanguage(Language::TYPE_INTERFACE);
+ $language_interface = \Drupal::languageManager()->getCurrentLanguage();
if ($cache = \Drupal::cache()->get("filter_formats:{$language_interface->id}")) {
$formats['all'] = $cache->data;
}
diff --git a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
index 3c0d72958d8..596eb5cd377 100644
--- a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
+++ b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
@@ -73,6 +73,7 @@ abstract class NormalizerTestBase extends DrupalUnitTestBase {
$german = new Language(array(
'id' => 'de',
'name' => 'Deutsch',
+ 'weight' => -1,
));
language_save($german);
diff --git a/core/modules/system/config/system.language.types.yml b/core/modules/language/config/language.types.yml
index 2b77d89967f..2b77d89967f 100644
--- a/core/modules/system/config/system.language.types.yml
+++ b/core/modules/language/config/language.types.yml
diff --git a/core/modules/language/config/schema/language.schema.yml b/core/modules/language/config/schema/language.schema.yml
index 1b251c97b80..9a31be73214 100644
--- a/core/modules/language/config/schema/language.schema.yml
+++ b/core/modules/language/config/schema/language.schema.yml
@@ -1,5 +1,22 @@
# Schema for the configuration files of the Language module.
+language.types:
+ type: mapping
+ label: 'Language types'
+ mapping:
+ all:
+ type: sequence
+ label: 'All language types'
+ sequence:
+ - type: string
+ label: 'Language type'
+ configurable:
+ type: sequence
+ label: 'Configurable language types'
+ sequence:
+ - type: string
+ label: 'Language type'
+
language.detection:
type: mapping
label: 'Language detection settings'
diff --git a/core/modules/language/language.api.php b/core/modules/language/language.api.php
index d0a31c4992a..e93f508dc92 100644
--- a/core/modules/language/language.api.php
+++ b/core/modules/language/language.api.php
@@ -11,6 +11,73 @@
*/
/**
+ * Define language types.
+ *
+ * @return
+ * An associative array of language type definitions. The keys are the
+ * identifiers, which are also used as names for global variables representing
+ * the types in the bootstrap phase. The values are associative arrays that
+ * may contain the following elements:
+ * - name: The human-readable language type identifier.
+ * - description: A description of the language type.
+ * - locked: A boolean indicating if the user can choose wether to configure
+ * the language type or not using the UI.
+ * - fixed: A fixed array of language negotiation method identifiers to use to
+ * initialize this language. If locked is set to TRUE and fixed is set, it
+ * will always use the specified methods in the given priority order. If not
+ * present and locked is TRUE then language-interface will be
+ * used.
+ *
+ * @todo Rename the 'fixed' key to something more meaningful, for instance
+ * 'negotiation settings'. See https://drupal.org/node/2166879.
+ *
+ * @see hook_language_types_info_alter()
+ * @ingroup language_negotiation
+ */
+function hook_language_types_info() {
+ return array(
+ 'custom_language_type' => array(
+ 'name' => t('Custom language'),
+ 'description' => t('A custom language type.'),
+ 'locked' => FALSE,
+ ),
+ 'fixed_custom_language_type' => array(
+ 'locked' => TRUE,
+ 'fixed' => array('custom_language_negotiation_method'),
+ ),
+ );
+}
+
+/**
+ * Perform alterations on language types.
+ *
+ * @param $language_types
+ * Array of language type definitions.
+ *
+ * @see hook_language_types_info()
+ * @ingroup language_negotiation
+ */
+function hook_language_types_info_alter(array &$language_types) {
+ if (isset($language_types['custom_language_type'])) {
+ $language_types['custom_language_type_custom']['description'] = t('A far better description.');
+ }
+}
+
+/**
+ * Perform alterations on language negotiation methods.
+ *
+ * @param $negotiation_info
+ * Array of language negotiation method definitions.
+ *
+ * @ingroup language_negotiation
+ */
+function hook_language_negotiation_info_alter(array &$negotiation_info) {
+ if (isset($negotiation_info['custom_language_method'])) {
+ $negotiation_info['custom_language_method']['config'] = 'admin/config/regional/language/detection/custom-language-method';
+ }
+}
+
+/**
* React to a language about to be added or updated in the system.
*
* @param $language
@@ -66,7 +133,7 @@ function hook_language_delete($language) {
* @param array $context
* A language fallback context.
*
- * @see \Drupal\Core\Language\LanguageManager::getFallbackCandidates()
+ * @see \Drupal\Core\Language\LanguageManagerInterface::getFallbackCandidates()
*/
function hook_language_fallback_candidates_alter(array &$candidates, array $context) {
$candidates = array_reverse($candidates);
@@ -81,7 +148,7 @@ function hook_language_fallback_candidates_alter(array &$candidates, array $cont
* @param array $context
* A language fallback context.
*
- * @see \Drupal\Core\Language\LanguageManager::getFallbackCandidates()
+ * @see \Drupal\Core\Language\LanguageManagerInterface::getFallbackCandidates()
*/
function hook_language_fallback_candidates_OPERATION_alter(array &$candidates, array $context) {
// We know that the current OPERATION deals with entities so no need to check
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
index 51033894cc5..37388311d44 100644
--- a/core/modules/language/language.install
+++ b/core/modules/language/language.install
@@ -6,6 +6,8 @@
*/
use Drupal\Core\Language\Language;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
/**
* Implements hook_install().
@@ -14,15 +16,16 @@ use Drupal\Core\Language\Language;
* system on multilingual sites without needing any preliminary configuration.
*/
function language_install() {
- // Enable URL language detection for each configurable language type.
- require_once DRUPAL_ROOT . '/core/includes/language.inc';
- foreach (language_types_get_configurable() as $type) {
- module_load_include('inc', 'language', 'language.negotiation');
- language_negotiation_set($type, array(LANGUAGE_NEGOTIATION_URL => 0));
+ $language_manager = \Drupal::languageManager();
+ if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+ $negotiator = \Drupal::service('language_negotiator');
+ $types = $language_manager->getLanguageTypes();
+ $negotiator->updateConfiguration($types);
+ // Enable URL language detection for each configurable language type.
+ foreach ($types as $type) {
+ $negotiator->saveConfiguration($type, array(LanguageNegotiationUrl::METHOD_ID => 0));
+ }
}
-
- // Update the language count.
- language_update_count();
}
/**
@@ -31,12 +34,9 @@ function language_install() {
function language_uninstall() {
// Clear variables.
variable_del('language_default');
- \Drupal::state()->delete('language_count');
// Clear variables.
- variable_del('language_types');
-
- foreach (language_types_get_all() as $type) {
+ foreach (\Drupal::languageManager()->getDefinedLanguageTypes() as $type) {
variable_del("language_negotiation_$type");
variable_del("language_negotiation_methods_weight_$type");
}
@@ -44,19 +44,4 @@ function language_uninstall() {
// Re-initialize the language system so successive calls to t() and other
// functions will not expect languages to be present.
drupal_language_initialize();
-
- // Force the language_count state to be 1, so that when checking if the
- // site is multilingual (for example in language_multilingual()), the result
- // will be FALSE, because the language module is not installed.
- \Drupal::state()->set('language_count', 1);
-}
-
-/**
- * Implements hook_requirements().
- */
-function language_requirements($phase) {
- if ($phase == 'update') {
- // Load the include files to make constants available for updates.
- language_negotiation_include();
- }
}
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 07a4aad7a4a..883ab881742 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -5,8 +5,13 @@
* Add language handling functionality to Drupal.
*/
-use Drupal\node\NodeTypeInterface;
use Drupal\Core\Language\Language;
+use Drupal\language\ConfigurableLanguageManager;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrlFallback;
+use Drupal\node\NodeTypeInterface;
/**
* Implements hook_help().
@@ -451,6 +456,7 @@ function language_save($language) {
$language_entity->weight = isset($language->weight) ? $language->weight : 0;
// Save the record and inform others about the change.
+ $multilingual = \Drupal::languageManager()->isMultilingual();
$language_entity->save();
$t_args = array('%language' => $language->name, '%langcode' => $language->id);
if ($language->is_new) {
@@ -467,39 +473,23 @@ function language_save($language) {
variable_set('language_default', (array) $language);
}
- // Kill the static cache in language_list().
- drupal_static_reset('language_list');
-
- // Update language count based on unlocked language count.
- language_update_count();
-
- // Update weight of locked system languages.
- language_update_locked_weights();
-
- language_negotiation_include();
+ $language_manager = \Drupal::languageManager();
+ $language_manager->reset();
+ if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+ $language_manager->updateLockedLanguageWeights();
+ }
// Update URL Prefixes for all languages after the new default language is
// propagated and the language_list() cache is flushed.
language_negotiation_url_prefixes_update();
- return $language;
-}
-
-/**
- * Updates the language_count state.
- *
- * This is used to check if a site is multilingual or not.
- *
- * @see language_multilingual()
- */
-function language_update_count() {
- $count = 0;
- foreach (entity_load_multiple('language_entity') as $language) {
- if (!$language->locked) {
- $count++;
- }
+ // If after adding this language the site will become multilingual, we need to
+ // rebuild language services.
+ if (!$multilingual && $language->is_new) {
+ ConfigurableLanguageManager::rebuildServices();
}
- \Drupal::state()->set('language_count', $count);
+
+ return $language;
}
/**
@@ -521,12 +511,17 @@ function language_delete($langcode) {
// Remove the language.
entity_delete_multiple('language_entity', array($language->id));
- drupal_static_reset('language_list');
-
- language_update_count();
+ $language_manager = \Drupal::languageManager();
+ $language_manager->reset();
+ if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+ $language_manager->updateLockedLanguageWeights();
+ }
- // Update weight of locked system languages.
- language_update_locked_weights();
+ // If after deleting this language the site will become monolingual, we need
+ // to rebuild language services.
+ if (!\Drupal::languageManager()->isMultilingual()) {
+ ConfigurableLanguageManager::rebuildServices();
+ }
$t_args = array('%language' => $language->name, '%langcode' => $language->id);
watchdog('language', 'The %language (%langcode) language has been removed.', $t_args);
@@ -570,8 +565,6 @@ function language_library_info() {
* language if none is specified.
*/
function language_language_types_info() {
- language_negotiation_include();
-
return array(
Language::TYPE_INTERFACE => array(
'name' => t('User interface text'),
@@ -581,114 +574,75 @@ function language_language_types_info() {
Language::TYPE_CONTENT => array(
'name' => t('Content'),
'description' => t('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
- 'fixed' => array(LANGUAGE_NEGOTIATION_INTERFACE),
+ 'fixed' => array(LanguageNegotiationUI::METHOD_ID),
'locked' => TRUE,
),
Language::TYPE_URL => array(
- 'fixed' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_URL_FALLBACK),
+ 'fixed' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationUrlFallback::METHOD_ID),
'locked' => TRUE,
),
);
}
/**
- * Implements hook_language_negotiation_info().
+ * Reads language prefixes and uses the langcode if no prefix is set.
*/
-function language_language_negotiation_info() {
- language_negotiation_include();
- $file = drupal_get_path('module', 'language') . '/language.negotiation.inc';
-
- $negotiation_info = array();
- $negotiation_info[LANGUAGE_NEGOTIATION_URL] = array(
- 'types' => array(Language::TYPE_CONTENT, Language::TYPE_INTERFACE, Language::TYPE_URL),
- 'callbacks' => array(
- 'negotiation' => 'language_from_url',
- 'language_switch' => 'language_switcher_url',
- ),
- 'file' => $file,
- 'weight' => -8,
- 'name' => t('URL'),
- 'description' => t('Language from the URL (Path prefix or domain).'),
- 'config' => 'admin/config/regional/language/detection/url',
- );
-
- $negotiation_info[LANGUAGE_NEGOTIATION_SESSION] = array(
- 'callbacks' => array(
- 'negotiation' => 'language_from_session',
- 'language_switch' => 'language_switcher_session',
- 'url_rewrite' => 'language_url_rewrite_session',
- ),
- 'file' => $file,
- 'weight' => -6,
- 'name' => t('Session'),
- 'description' => t('Language from a request/session parameter.'),
- 'config' => 'admin/config/regional/language/detection/session',
- );
-
- $negotiation_info[LANGUAGE_NEGOTIATION_USER] = array(
- 'callbacks' => array('negotiation' => 'language_from_user'),
- 'file' => $file,
- 'weight' => -4,
- 'name' => t('Account preference for site'),
- 'description' => t("The language setting for the site in the user's account."),
- );
-
- $negotiation_info[LANGUAGE_NEGOTIATION_BROWSER] = array(
- 'callbacks' => array('negotiation' => 'language_from_browser'),
- 'file' => $file,
- 'weight' => -2,
- 'cache' => 0,
- 'name' => t('Browser'),
- 'description' => t("Language from the browser's language settings."),
- 'config' => 'admin/config/regional/language/detection/browser',
- );
-
- $negotiation_info[LANGUAGE_NEGOTIATION_INTERFACE] = array(
- 'types' => array(Language::TYPE_CONTENT),
- 'callbacks' => array('negotiation' => 'language_from_interface'),
- 'file' => $file,
- 'weight' => 8,
- 'name' => t('Interface'),
- 'description' => t('Use the detected interface language.'),
- );
+function language_negotiation_url_prefixes() {
+ return \Drupal::config('language.negotiation')->get('url.prefixes');
+}
- $negotiation_info[LANGUAGE_NEGOTIATION_URL_FALLBACK] = array(
- 'types' => array(Language::TYPE_URL),
- 'callbacks' => array('negotiation' => 'language_url_fallback'),
- 'file' => $file,
- 'weight' => 8,
- 'name' => t('URL fallback'),
- 'description' => t('Use an already detected language for URLs if none is found.'),
- );
+/**
+ * Update the list of prefixes from the installed languages.
+ */
+function language_negotiation_url_prefixes_update() {
+ $prefixes = language_negotiation_url_prefixes();
+ foreach (language_list() as $language) {
+ // The prefix for this language should be updated if it's not assigned yet
+ // or the prefix is set to the empty string.
+ if (empty($prefixes[$language->id])) {
+ // For the default language, set the prefix to the empty string,
+ // otherwise use the langcode.
+ $prefixes[$language->id] = !empty($language->default) ? '' : $language->id;
+ }
+ // Otherwise we keep the configured prefix.
+ }
+ language_negotiation_url_prefixes_save($prefixes);
+}
- $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 preference for administration pages'),
- 'description' => t("The language setting for account administration pages in the user's account."),
- );
+/**
+ * Saves language prefix settings.
+ */
+function language_negotiation_url_prefixes_save(array $prefixes) {
+ \Drupal::config('language.negotiation')
+ ->set('url.prefixes', $prefixes)
+ ->save();
+}
- return $negotiation_info;
+/**
+ * Reads language domains.
+ */
+function language_negotiation_url_domains() {
+ return \Drupal::config('language.negotiation')->get('url.domains');
}
/**
- * Include negotiation backend functionality.
+ * Saves the language domain settings.
*/
-function language_negotiation_include() {
- include_once DRUPAL_ROOT . '/core/includes/language.inc';
- include_once __DIR__ . '/language.negotiation.inc';
+function language_negotiation_url_domains_save(array $domains) {
+ \Drupal::config('language.negotiation')
+ ->set('url.domains', $domains)
+ ->save();
}
/**
* Implements hook_modules_installed().
*/
function language_modules_installed($modules) {
- include_once DRUPAL_ROOT . '/core/includes/language.inc';
- // Load configurability options from configuration.
- language_types_set(array());
- language_negotiation_purge();
+ if (!in_array('language', $modules)) {
+ $negotiator = \Drupal::service('language_negotiator');
+ $negotiator->updateConfiguration(array());
+ $negotiator->purgeConfiguration();
+ }
}
/**
@@ -706,8 +660,6 @@ function language_language_insert($language) {
return;
}
- language_negotiation_include();
-
// Add language to the list of language domains.
$domains = language_negotiation_url_domains();
$domains[$language->id] = '';
@@ -718,8 +670,6 @@ function language_language_insert($language) {
* Implements hook_language_delete().
*/
function language_language_delete($language) {
- language_negotiation_include();
-
// Remove language from language prefix list.
$prefixes = language_negotiation_url_prefixes();
unset($prefixes[$language->id]);
@@ -769,29 +719,6 @@ function language_set_browser_drupal_langcode_mappings($mappings) {
}
/**
- * Updates locked system language weights.
- */
-function language_update_locked_weights() {
- $max_weight = 0;
-
- // Get maximum weight to update the system languages to keep them on bottom.
- foreach (language_list(Language::STATE_CONFIGURABLE) as $language) {
- if (!$language->locked && $language->weight > $max_weight) {
- $max_weight = $language->weight;
- }
- }
-
- // Loop locked languages to maintain the existing order.
- foreach (language_list(Language::STATE_LOCKED) as $language) {
- $max_weight++;
- // Update system languages weight.
- \Drupal::config('language.entity.' . $language->id)
- ->set('weight', $max_weight)
- ->save();
- }
-}
-
-/**
* Implements hook_form_FORM_ID_alter for system_regional_settings().
*
* @see language_system_regional_settings_form_submit()
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
deleted file mode 100644
index f87284d76f2..00000000000
--- a/core/modules/language/language.negotiation.inc
+++ /dev/null
@@ -1,529 +0,0 @@
-<?php
-
-use Drupal\Component\Utility\String;
-use \Symfony\Component\HttpFoundation\Request;
-
-/**
- * @file
- * Language negotiation functions.
- */
-
-use Drupal\Core\Language\Language;
-
-/**
- * The language is determined using path prefix or domain.
- */
-const LANGUAGE_NEGOTIATION_URL = 'language-url';
-
-/**
- * The language is set based on the browser language settings.
- */
-const LANGUAGE_NEGOTIATION_BROWSER = 'language-browser';
-
-/**
- * If no URL language, language is determined using an already detected one.
- */
-const LANGUAGE_NEGOTIATION_URL_FALLBACK = 'language-url-fallback';
-
-/**
- * The language is set based on the user language settings.
- */
-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';
-
-/**
- * URL language negotiation: use the path prefix as URL language indicator.
- */
-const LANGUAGE_NEGOTIATION_URL_PREFIX = 'path_prefix';
-
-/**
- * URL language negotiation: use the domain as URL language indicator.
- */
-const LANGUAGE_NEGOTIATION_URL_DOMAIN = 'domain';
-
-/**
- * Identifies the language from the current interface language.
- *
- * @return
- * The current interface language code.
- */
-function language_from_interface() {
- return language(Language::TYPE_INTERFACE)->id;
-}
-
-/**
- * Identify language from the Accept-language HTTP header we got.
- *
- * The algorithm works as follows:
- * - map browser language codes to Drupal language codes.
- * - order all browser language codes by qvalue from high to low.
- * - add generic browser language codes if they aren't already specified
- * but with a slightly lower qvalue.
- * - find the most specific Drupal language code with the highest qvalue.
- * - if 2 or more languages are having the same qvalue, respect the order of
- * them inside the $languages array.
- *
- * We perform browser accept-language parsing only if page cache is disabled,
- * otherwise we would cache a user-specific preference.
- *
- * @param $languages
- * An array of language objects for enabled languages ordered by weight.
- *
- * @return
- * A valid language code on success, FALSE otherwise.
- */
-function language_from_browser($languages) {
- $accept_language = \Drupal::request()->server->get('HTTP_ACCEPT_LANGUAGE');
- if (empty($accept_language)) {
- return FALSE;
- }
-
- // The Accept-Language header contains information about the language
- // preferences configured in the user's browser / operating system. RFC 2616
- // (section 14.4) defines the Accept-Language header as follows:
- // Accept-Language = "Accept-Language" ":"
- // 1#( language-range [ ";" "q" "=" qvalue ] )
- // language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
- // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5"
- $browser_langcodes = array();
- if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($accept_language), $matches, PREG_SET_ORDER)) {
- // Load custom mappings to support browsers that are sending non standard
- // language codes.
- $mappings = language_get_browser_drupal_langcode_mappings();
- foreach ($matches as $match) {
- if ($mappings) {
- $langcode = strtolower($match[1]);
- foreach ($mappings as $browser_langcode => $drupal_langcode) {
- if ($langcode == $browser_langcode) {
- $match[1] = $drupal_langcode;
- }
- }
- }
- // We can safely use strtolower() here, tags are ASCII.
- // RFC2616 mandates that the decimal part is no more than three digits,
- // so we multiply the qvalue by 1000 to avoid floating point comparisons.
- $langcode = strtolower($match[1]);
- $qvalue = isset($match[2]) ? (float) $match[2] : 1;
- // Take the highest qvalue for this langcode. Although the request
- // supposedly contains unique langcodes, our mapping possibly resolves
- // to the same langcode for different qvalues. Keep the highest.
- $browser_langcodes[$langcode] = max(
- (int) ($qvalue * 1000),
- (isset($browser_langcodes[$langcode]) ? $browser_langcodes[$langcode] : 0)
- );
- }
- }
-
- // We should take pristine values from the HTTP headers, but Internet Explorer
- // from version 7 sends only specific language tags (eg. fr-CA) without the
- // corresponding generic tag (fr) unless explicitly configured. In that case,
- // we assume that the lowest value of the specific tags is the value of the
- // generic language to be as close to the HTTP 1.1 spec as possible.
- // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 and
- // http://blogs.msdn.com/b/ie/archive/2006/10/17/accept-language-header-for-internet-explorer-7.aspx
- asort($browser_langcodes);
- foreach ($browser_langcodes as $langcode => $qvalue) {
- // For Chinese languages the generic tag is either zh-hans or zh-hant, so we
- // need to handle this separately, we can not split $langcode on the
- // first occurrence of '-' otherwise we get a non-existing language zh.
- // All other languages use a langcode without a '-', so we can safely split
- // on the first occurrence of it.
- $generic_tag = '';
- if (strlen($langcode) > 7 && (substr($langcode, 0, 7) == 'zh-hant' || substr($langcode, 0, 7) == 'zh-hans')) {
- $generic_tag = substr($langcode, 0, 7);
- }
- else {
- $generic_tag = strtok($langcode, '-');
- }
- if (!empty($generic_tag) && !isset($browser_langcodes[$generic_tag])) {
- // Add the generic langcode, but make sure it has a lower qvalue as the
- // more specific one, so the more specific one gets selected if it's
- // defined by both the browser and Drupal.
- $browser_langcodes[$generic_tag] = $qvalue - 0.1;
- }
- }
-
- // Find the enabled language with the greatest qvalue, following the rules of
- // RFC 2616 (section 14.4). If several languages have the same qvalue, prefer
- // the one with the greatest weight.
- $best_match_langcode = FALSE;
- $max_qvalue = 0;
- foreach ($languages as $langcode => $language) {
- // Language tags are case insensitive (RFC2616, sec 3.10).
- $langcode = strtolower($langcode);
-
- // If nothing matches below, the default qvalue is the one of the wildcard
- // language, if set, or is 0 (which will never match).
- $qvalue = isset($browser_langcodes['*']) ? $browser_langcodes['*'] : 0;
-
- // Find the longest possible prefix of the browser-supplied language ('the
- // language-range') that matches this site language ('the language tag').
- $prefix = $langcode;
- do {
- if (isset($browser_langcodes[$prefix])) {
- $qvalue = $browser_langcodes[$prefix];
- break;
- }
- }
- while ($prefix = substr($prefix, 0, strrpos($prefix, '-')));
-
- // Find the best match.
- if ($qvalue > $max_qvalue) {
- $best_match_langcode = $language->id;
- $max_qvalue = $qvalue;
- }
- }
-
- return $best_match_langcode;
-}
-
-/**
- * Identify 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($languages) {
- // User preference (only for authenticated users).
- $user = \Drupal::currentUser();
-
- if ($user->id()) {
- $langcode = $user->getPreferredLangcode();
- $default_langcode = language_default()->id;
- if (!empty($langcode) && $langcode != $default_langcode && isset($languages[$langcode])) {
- return $langcode;
- }
- }
-
- // No language preference from the user.
- return FALSE;
-}
-
-/**
- * Identifies admin language from the user preferences.
- *
- * @param $languages
- * An array of valid language objects.
- *
- * @param \Symfony\Component\HttpFoundation\Request|null $request
- * (optional) The HttpRequest object representing the current request.
- * Defaults to NULL.
- *
- * @return
- * A valid language code on success, FALSE otherwise.
- */
-function language_from_user_admin(array $languages, Request $request = NULL) {
- // User preference (only for authenticated users).
- $user = \Drupal::currentUser();
-
- if ($user->id()) {
- $request_path = $request ? urldecode(trim($request->getPathInfo(), '/')) : _current_path();
- $langcode = $user->getPreferredAdminLangcode();
- $default_langcode = language_default()->id;
- if (!empty($langcode) && $langcode != $default_langcode && isset($languages[$langcode]) && path_is_admin($request_path)) {
- return $langcode;
- }
- }
-
- // No language preference from the user or not on an admin path.
- return FALSE;
-}
-
-/**
- * Identify language from a request/session parameter.
- *
- * @param $languages
- * An array of valid language objects.
- *
- * @return
- * A valid language code on success, FALSE otherwise.
- */
-function language_from_session($languages) {
- $param = \Drupal::config('language.negotiation')->get('session.parameter');
- $query = \Drupal::request()->query;
-
- // Request parameter: we need to update the session parameter only if we have
- // an authenticated user.
- if ($query->has($param) && isset($languages[$langcode = $query->get($param)])) {
- $user = \Drupal::currentUser();
- if ($user->id()) {
- $_SESSION[$param] = $langcode;
- }
- return $langcode;
- }
-
- // Session parameter.
- if (isset($_SESSION[$param])) {
- return $_SESSION[$param];
- }
-
- return FALSE;
-}
-
-/**
- * Identify language via URL prefix or domain.
- *
- * @param $languages
- * An array of valid language objects.
- *
- * @param \Symfony\Component\HttpFoundation\Request|null $request
- * (optional) The HttpRequest object representing the current request.
- * Defaults to NULL.
- *
- * @return
- * A valid language code on success, FALSE otherwise.
- */
-function language_from_url($languages, Request $request = NULL) {
- $language_url = FALSE;
-
- if (!language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_URL) || !$request) {
- return $language_url;
- }
-
- switch (\Drupal::config('language.negotiation')->get('url.source')) {
- case LANGUAGE_NEGOTIATION_URL_PREFIX:
-
- $request_path = urldecode(trim($request->getPathInfo(), '/'));
- list($language, $path) = language_url_split_prefix($request_path, $languages);
-
- if ($language !== FALSE) {
- $language_url = $language->id;
- }
- break;
-
- case LANGUAGE_NEGOTIATION_URL_DOMAIN:
- // Get only the host, not the port.
- $http_host= \Drupal::request()->server->get('HTTP_HOST');
- if (strpos($http_host, ':') !== FALSE) {
- $http_host_tmp = explode(':', $http_host);
- $http_host = current($http_host_tmp);
- }
- $domains = language_negotiation_url_domains();
- foreach ($languages as $language) {
- // Skip the check if the language doesn't have a domain.
- if (!empty($domains[$language->id])) {
- // Ensure that there is exactly one protocol in the URL when checking
- // the hostname.
- $host = 'http://' . str_replace(array('http://', 'https://'), '', $domains[$language->id]);
- $host = parse_url($host, PHP_URL_HOST);
- if ($http_host == $host) {
- $language_url = $language->id;
- break;
- }
- }
- }
- break;
- }
-
- return $language_url;
-}
-
-/**
- * Determines the language to be assigned to URLs when none is detected.
- *
- * The language negotiation process has a fallback chain that ends with the
- * default language negotiation method. Each built-in language type has a
- * separate initialization:
- * - Interface language, which is the only configurable one, always gets a valid
- * value. If no request-specific language is detected, the default language
- * will be used.
- * - Content language merely inherits the interface language by default.
- * - URL language is detected from the requested URL and will be used to rewrite
- * URLs appearing in the page being rendered. If no language can be detected,
- * there are two possibilities:
- * - If the default language has no configured path prefix or domain, then the
- * default language is used. This guarantees that (missing) URL prefixes are
- * preserved when navigating through the site.
- * - If the default language has a configured path prefix or domain, a
- * requested URL having an empty prefix or domain is an anomaly that must be
- * fixed. This is done by introducing a prefix or domain in the rendered
- * page matching the detected interface language.
- *
- * @param $languages
- * (optional) An array of valid language objects. This is passed by
- * language_negotiation_method_invoke() to every language method callback,
- * but it is not actually needed here. Defaults to NULL.
- *
- * @param $request
- * (optional) The HttpRequest object representing the current request.
- *
- * @param $language_type
- * (optional) The language type to fall back to. Defaults to the interface
- * language.
- *
- * @return
- * A valid language code.
- */
-function language_url_fallback($language = NULL, $request = NULL, $language_type = Language::TYPE_INTERFACE) {
- $default = language_default();
- $prefix = (\Drupal::config('language.negotiation')->get('url.source') == LANGUAGE_NEGOTIATION_URL_PREFIX);
-
- // If the default language is not configured to convey language information,
- // a missing URL language information indicates that URL language should be
- // the default one, otherwise we fall back to an already detected language.
- $domains = language_negotiation_url_domains();
- $prefixes = language_negotiation_url_prefixes();
- if (($prefix && empty($prefixes[$default->id])) || (!$prefix && empty($domains[$default->id]))) {
- return $default->id;
- }
- else {
- $langcode = language($language_type)->id;
- return $langcode;
- }
-}
-
-/**
- * Return links for the URL language switcher block.
- *
- * Translation links may be provided by other modules.
- */
-function language_switcher_url($type, $path) {
- $languages = language_list();
- $links = array();
-
- foreach ($languages as $language) {
- $links[$language->id] = array(
- 'href' => $path,
- 'title' => $language->name,
- 'language' => $language,
- 'attributes' => array('class' => array('language-link')),
- );
- }
-
- return $links;
-}
-
-/**
- * Return the session language switcher block.
- */
-function language_switcher_session($type, $path) {
- $param = \Drupal::config('language.negotiation')->get('session.parameter');
- $language_query = isset($_SESSION[$param]) ? $_SESSION[$param] : language($type)->id;
-
- $languages = language_list();
- $links = array();
-
- $query = \Drupal::request()->query->all();
-
- foreach ($languages as $language) {
- $langcode = $language->id;
- $links[$langcode] = array(
- 'href' => $path,
- 'title' => $language->name,
- 'attributes' => array('class' => array('language-link')),
- 'query' => $query,
- );
- if ($language_query != $langcode) {
- $links[$langcode]['query'][$param] = $langcode;
- }
- else {
- $links[$langcode]['attributes']['class'][] = ' session-active';
- }
- }
-
- return $links;
-}
-
-/**
- * Reads language prefixes and uses the langcode if no prefix is set.
- */
-function language_negotiation_url_prefixes() {
- return \Drupal::config('language.negotiation')->get('url.prefixes');
-}
-
-/**
- * Update the list of prefixes from the installed languages.
- */
-function language_negotiation_url_prefixes_update() {
- $prefixes = language_negotiation_url_prefixes();
- foreach (language_list() as $language) {
- // The prefix for this language should be updated if it's not assigned yet
- // or the prefix is set to the empty string.
- if (empty($prefixes[$language->id])) {
- // For the default language, set the prefix to the empty string,
- // otherwise use the langcode.
- $prefixes[$language->id] = !empty($language->default) ? '' : $language->id;
- }
- // Otherwise we keep the configured prefix.
- }
- language_negotiation_url_prefixes_save($prefixes);
-}
-
-/**
- * Saves language prefix settings.
- */
-function language_negotiation_url_prefixes_save(array $prefixes) {
- \Drupal::config('language.negotiation')
- ->set('url.prefixes', $prefixes)
- ->save();
-}
-
-/**
- * Reads language domains.
- */
-function language_negotiation_url_domains() {
- return \Drupal::config('language.negotiation')->get('url.domains');
-}
-
-/**
- * Saves the language domain settings.
- */
-function language_negotiation_url_domains_save(array $domains) {
- \Drupal::config('language.negotiation')
- ->set('url.domains', $domains)
- ->save();
-}
-
-/**
- * Rewrite URLs for the Session language negotiation method.
- */
-function language_url_rewrite_session(&$path, &$options) {
- static $query_rewrite, $query_param, $query_value;
-
- // The following values are not supposed to change during a single page
- // request processing.
- if (!isset($query_rewrite)) {
- $user = \Drupal::currentUser();
- if (!$user->id()) {
- $languages = language_list();
- $query_param = String::checkPlain(\Drupal::config('language.negotiation')->get('session.parameter'));
- $query = \Drupal::request()->query;
- if ($query->has($query_param)) {
- $query_value = String::checkPlain(\Drupal::request()->query->get($query_param));
- }
- else {
- return FALSE;
- }
- $query_rewrite = isset($languages[$query_value]) && language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_SESSION);
- }
- else {
- $query_rewrite = FALSE;
- }
- }
-
- // If the user is anonymous, the user language negotiation method is enabled,
- // and the corresponding option has been set, we must preserve any explicit
- // user language preference even with cookies disabled.
- if ($query_rewrite) {
- if (is_string($options['query'])) {
- $query = array();
- parse_str($options['query'], $query);
- $options['query'] = $query;
- }
- if (!isset($options['query'][$query_param])) {
- $options['query'][$query_param] = $query_value;
- }
- }
-}
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index 05b4798c6d2..81aede72a9c 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -1,12 +1,9 @@
services:
- path_processor_language:
- class: Drupal\language\HttpKernel\PathProcessorLanguage
- arguments: ['@config.factory', '@settings', '@language_manager']
- tags:
- - { name: path_processor_inbound, priority: 300 }
- - { name: path_processor_outbound, priority: 100 }
- language_config_subscriber:
- class: Drupal\language\LanguageConfigSubscriber
- tags:
- - { name: event_subscriber }
- arguments: ['@language_manager', '@config.factory']
+ plugin.manager.language_negotiation_method:
+ class: Drupal\language\LanguageNegotiationMethodManager
+ arguments: ['@container.namespaces', '@cache.cache', '@module_handler']
+ language_negotiator:
+ class: Drupal\language\LanguageNegotiator
+ arguments: ['@language_manager', '@plugin.manager.language_negotiation_method', '@config.factory', '@settings']
+ calls:
+ - [initLanguageManager]
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
new file mode 100644
index 00000000000..49c7ea42ac3
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
@@ -0,0 +1,386 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\ConfigurableLanguageManager.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Component\PhpStorage\PhpStorageFactory;
+use Drupal\Component\Utility\MapArray;
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManager;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Overrides default LanguageManager to provide configured languages.
+ */
+class ConfigurableLanguageManager extends LanguageManager implements ConfigurableLanguageManagerInterface {
+
+ /**
+ * The configuration storage service.
+ *
+ * @var \Drupal\Core\Config\ConfigFactory
+ */
+ protected $configFactory;
+
+ /**
+ * The module handler service.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * The request object.
+ *
+ * @var \Symfony\Component\HttpFoundation\Request
+ */
+ protected $request;
+
+ /**
+ * The language negotiator.
+ *
+ * @var \Drupal\language\LanguageNegotiatorInterface
+ */
+ protected $negotiator;
+
+ /**
+ * Local cache for language type configuration data.
+ *
+ * @var array
+ */
+ protected $languageTypes;
+
+ /**
+ * Local cache for language type information.
+ *
+ * @var array
+ */
+ protected $languageTypesInfo;
+
+ /**
+ * An array of language objects keyed by language type.
+ *
+ * @var array
+ */
+ protected $negotiatedLanguages;
+
+ /**
+ * Whether or not the language manager has been initialized.
+ *
+ * @var bool
+ */
+ protected $initialized = FALSE;
+
+ /**
+ * Whether already in the process of language initialization.
+ *
+ * @var bool
+ */
+ protected $initializing = FALSE;
+
+ /**
+ * Rebuild the container to register services needed on multilingual sites.
+ */
+ public static function rebuildServices() {
+ PhpStorageFactory::get('service_container')->deleteAll();
+ }
+
+ /**
+ * Constructs a new ConfigurableLanguageManager object.
+ *
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The configuration storage service.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler service.
+ */
+ public function __construct(ConfigFactory $config_factory, ModuleHandlerInterface $module_handler) {
+ $this->configFactory = $config_factory;
+ $this->moduleHandler = $module_handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initConfigOverrides() {
+ $this->configFactory->setLanguage($this->getCurrentLanguage());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init() {
+ if (!$this->initialized) {
+ foreach ($this->getDefinedLanguageTypes() as $type) {
+ $this->getCurrentLanguage($type);
+ }
+ $this->initialized = TRUE;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isMultilingual() {
+ return count($this->getLanguages(Language::STATE_CONFIGURABLE)) > 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLanguageTypes() {
+ $this->loadLanguageTypesConfiguration();
+ return $this->languageTypes['configurable'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefinedLanguageTypes() {
+ $this->loadLanguageTypesConfiguration();
+ return $this->languageTypes['all'];
+ }
+
+ /**
+ * Retrieves language types from the configuration storage.
+ *
+ * @return array
+ * An array of language type names.
+ */
+ protected function loadLanguageTypesConfiguration() {
+ if (!$this->languageTypes) {
+ $this->languageTypes = $this->configFactory->get('language.types')->get() ?: array('configurable' => array(), 'all' => parent::getLanguageTypes());
+ }
+ return $this->languageTypes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefinedLanguageTypesInfo() {
+ if (!isset($this->languageTypesInfo)) {
+ $info = $this->moduleHandler->invokeAll('language_types_info');
+ // Let other modules alter the list of language types.
+ $this->moduleHandler->alter('language_types_info', $info);
+ $this->languageTypesInfo = $info;
+ }
+ return $this->languageTypesInfo;
+ }
+
+ /**
+ * Stores language types configuration.
+ */
+ public function saveLanguageTypesConfiguration(array $config) {
+ $this->configFactory->get('language.types')->setData($config)->save();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCurrentLanguage($type = Language::TYPE_INTERFACE) {
+ if (!isset($this->negotiatedLanguages[$type])) {
+ // Ensure we have a valid value for this language type.
+ $this->negotiatedLanguages[$type] = $this->getDefaultLanguage();
+
+ if ($this->negotiator && $this->isMultilingual()) {
+ if (!$this->initializing) {
+ $this->initializing = TRUE;
+ $this->negotiatedLanguages[$type] = $this->negotiator->initializeType($type);
+ $this->initializing = FALSE;
+ }
+ // If the current interface language needs to be retrieved during
+ // initialization we return the system language. This way string
+ // translation calls happening during initialization will return the
+ // original strings which can be translated by calling them again
+ // afterwards. This can happen for instance while parsing negotiation
+ // method definitions.
+ elseif ($type == Language::TYPE_INTERFACE) {
+ return new Language(array('id' => Language::LANGCODE_SYSTEM));
+ }
+ }
+ }
+
+ return $this->negotiatedLanguages[$type];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset($type = NULL) {
+ if (!isset($type)) {
+ $this->initialized = FALSE;
+ $this->negotiatedLanguages = array();
+ $this->languageTypes = NULL;
+ $this->languageTypesInfo = NULL;
+ $this->languages = NULL;
+ $this->defaultLanguage = NULL;
+ if ($this->negotiator) {
+ $this->negotiator->reset();
+ }
+ }
+ elseif (isset($this->negotiatedLanguages[$type])) {
+ unset($this->negotiatedLanguages[$type]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRequest(Request $request) {
+ $this->request = $request;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNegotiator() {
+ return $this->negotiator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNegotiator(LanguageNegotiatorInterface $negotiator) {
+ $this->negotiator = $negotiator;
+ $this->initialized = FALSE;
+ $this->negotiatedLanguages = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultLanguage() {
+ if (!isset($this->defaultLanguage)) {
+ // @todo Convert to CMI https://drupal.org/node/1827038 and
+ // https://drupal.org/node/2108599.
+ $default_info = variable_get('language_default', Language::$defaultValues);
+ $this->defaultLanguage = new Language($default_info + array('default' => TRUE));
+ }
+ return $this->defaultLanguage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLanguages($flags = Language::STATE_CONFIGURABLE) {
+ if (!isset($this->languages)) {
+ // Prepopulate the language list with the default language to keep things
+ // working even if we have no configuration.
+ $default = $this->getDefaultLanguage();
+ $this->languages = array($default->id => $default);
+
+ // Retrieve the config storage to list available languages.
+ $prefix = 'language.entity.';
+ $storage = $this->configFactory->get($prefix . Language::LANGCODE_NOT_SPECIFIED)->getStorage();
+ $config_ids = $storage->listAll($prefix);
+
+ // Instantiate languages from config objects.
+ $weight = 0;
+ foreach ($this->configFactory->loadMultiple($config_ids) as $config) {
+ $data = $config->get();
+ $langcode = $data['id'];
+ // Initialize default property so callers have an easy reference and can
+ // save the same object without data loss.
+ $data['default'] = ($langcode == $default->id);
+ $data['name'] = $data['label'];
+ $this->languages[$langcode] = new Language($data);
+ $weight = max(array($weight, $this->languages[$langcode]->weight));
+ }
+
+ // Add locked languages, they will be filtered later if needed.
+ $this->languages += $this->getDefaultLockedLanguages($weight);
+
+ // Sort the language list by weight.
+ Language::sort($this->languages);
+ }
+
+ return parent::getLanguages($flags);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function updateLockedLanguageWeights() {
+ $max_weight = 0;
+
+ // Get maximum weight to update the system languages to keep them on bottom.
+ foreach ($this->getLanguages(Language::STATE_CONFIGURABLE) as $language) {
+ if (!$language->locked && $language->weight > $max_weight) {
+ $max_weight = $language->weight;
+ }
+ }
+
+ // Loop locked languages to maintain the existing order.
+ $locked_languages = $this->getLanguages(Language::STATE_LOCKED);
+ $config_ids = array_map(function($language) { return 'language.entity.' . $language->id; }, $locked_languages);
+ foreach ($this->configFactory->loadMultiple($config_ids) as $config_id => $config) {
+ // Update system languages weight.
+ $max_weight++;
+ $config->set('weight', $max_weight);
+ $config->save();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFallbackCandidates($langcode = NULL, array $context = array()) {
+ if ($this->isMultilingual()) {
+ // Get languages ordered by weight, add Language::LANGCODE_NOT_SPECIFIED
+ // at the end.
+ $candidates = array_keys($this->getLanguages());
+ $candidates[] = Language::LANGCODE_NOT_SPECIFIED;
+ $candidates = MapArray::copyValuesToKeys($candidates);
+
+ // The first candidate should always be the desired language if specified.
+ if (!empty($langcode)) {
+ $candidates = array($langcode => $langcode) + $candidates;
+ }
+
+ // Let other modules hook in and add/change candidates.
+ $type = 'language_fallback_candidates';
+ $types = array();
+ if (!empty($context['operation'])) {
+ $types[] = $type . '_' . $context['operation'];
+ }
+ $types[] = $type;
+ $this->moduleHandler->alter($types, $candidates, $context);
+ }
+ else {
+ $candidates = parent::getFallbackCandidates($langcode, $context);
+ }
+
+ return $candidates;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLanguageSwitchLinks($type, $path) {
+ $links = FALSE;
+
+ if ($this->negotiator) {
+ foreach ($this->negotiator->getNegotiationMethods($type) as $method_id => $method) {
+ $reflector = new \ReflectionClass($method['class']);
+
+ if ($reflector->implementsInterface('\Drupal\language\LanguageSwitcherInterface')) {
+ $result = $this->negotiator->getNegotiationMethodInstance($method_id)->getLanguageSwitchLinks($this->request, $type, $path);
+
+ if (!empty($result)) {
+ // Allow modules to provide translations for specific links.
+ $this->moduleHandler->alter('language_switch_links', $result, $type, $path);
+ $links = (object) array('links' => $result, 'method_id' => $method_id);
+ break;
+ }
+ }
+ }
+ }
+
+ return $links;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
new file mode 100644
index 00000000000..c9a13d655d4
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\ConfigurableLanguageManagerInterface
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Common interface for language negotiation services.
+ */
+interface ConfigurableLanguageManagerInterface extends LanguageManagerInterface {
+
+ /**
+ * Injects the request object.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request
+ * The request object.
+ */
+ public function setRequest(Request $request);
+
+ /**
+ * Returns the language negotiator.
+ *
+ * @retun \Drupal\language\LanguageNegotiatorInterface
+ * The language negotiator.
+ */
+ public function getNegotiator();
+
+ /**
+ * Injects the language negotiator.
+ *
+ * @param \Drupal\language\LanguageNegotiatorInterface $negotiator
+ * The language negotiator.
+ */
+ public function setNegotiator(LanguageNegotiatorInterface $negotiator);
+
+ /**
+ * Returns all the defined language types including fixed ones.
+ *
+ * A language type maybe configurable or fixed. A fixed language type is a
+ * type whose language negotiation methods are module-defined and not altered
+ * through the user interface.
+ *
+ * @return array
+ * An array of language type names.
+ */
+ public function getDefinedLanguageTypes();
+
+ /**
+ * Returns information about all defined language types.
+ *
+ * @return array
+ * An associative array of language type information arrays keyed by type
+ * names. Based on information from hook_language_types_info().
+ *
+ * @see hook_language_types_info()
+ */
+ public function getDefinedLanguageTypesInfo();
+
+ /**
+ * Stores language types configuration.
+ *
+ * @param array
+ * An indexed array with the following keys_
+ * - configurable: an array of configurable language type names.
+ * - all: an array of all the defined language type names.
+ */
+ public function saveLanguageTypesConfiguration(array $config);
+
+ /**
+ * Updates locked system language weights.
+ */
+ public function updateLockedLanguageWeights();
+
+ /**
+ * Initializes per-language overrides for configuration.
+ */
+ public function initConfigOverrides();
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Entity/Language.php b/core/modules/language/lib/Drupal/language/Entity/Language.php
index 6ae43852b8b..60b06a149a9 100644
--- a/core/modules/language/lib/Drupal/language/Entity/Language.php
+++ b/core/modules/language/lib/Drupal/language/Entity/Language.php
@@ -9,7 +9,6 @@ namespace Drupal\language\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\Core\Language\LanguageManager;
use Drupal\language\LanguageInterface;
/**
diff --git a/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php
index d50022dae16..c9551f440fe 100644
--- a/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php
+++ b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php
@@ -2,14 +2,16 @@
/**
* @file
- * Contains \Drupal\Core\EventSubscriber\LanguageRequestSubscriber.
+ * Contains \Drupal\language\EventSubscriber\LanguageRequestSubscriber.
*/
-namespace Drupal\Core\EventSubscriber;
+namespace Drupal\language\EventSubscriber;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\LanguageNegotiatorInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -23,11 +25,18 @@ class LanguageRequestSubscriber implements EventSubscriberInterface {
/**
* The language manager service.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\language\ConfigurableLanguageManagerInterface
*/
protected $languageManager;
/**
+ * The language negotiator.
+ *
+ * @var \Drupal\language\LanguageNegotiatorInterface
+ */
+ protected $negotiator;
+
+ /**
* The translation service.
*
* @var \Drupal\Core\Translation\Translator\TranslatorInterface
@@ -35,17 +44,29 @@ class LanguageRequestSubscriber implements EventSubscriberInterface {
protected $translation;
/**
+ * The current active user.
+ *
+ * @return \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ /**
* Constructs a LanguageRequestSubscriber object.
*
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
* The language manager service.
- *
+ * @param \Drupal\language\LanguageNegotiatorInterface
+ * The language negotiator.
* @param \Drupal\Core\Translation\Translator\TranslatorInterface $translation
* The translation service.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current active user.
*/
- public function __construct(LanguageManager $language_manager, TranslatorInterface $translation) {
+ public function __construct(ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, TranslatorInterface $translation, AccountInterface $current_user) {
$this->languageManager = $language_manager;
+ $this->negotiator = $negotiator;
$this->translation = $translation;
+ $this->currentUser = $current_user;
}
/**
@@ -56,10 +77,17 @@ class LanguageRequestSubscriber implements EventSubscriberInterface {
*/
public function onKernelRequestLanguage(GetResponseEvent $event) {
if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
- $this->languageManager->setRequest($event->getRequest());
+ $request = $event->getRequest();
+ $this->negotiator->setCurrentUser($this->currentUser);
+ $this->negotiator->setRequest($request);
+ if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) {
+ $this->languageManager->setNegotiator($this->negotiator);
+ $this->languageManager->setRequest($request);
+ $this->languageManager->initConfigOverrides();
+ }
// After the language manager has initialized, set the default langcode
// for the string translations.
- $langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $langcode = $this->languageManager->getCurrentLanguage()->id;
$this->translation->setDefaultLangcode($langcode);
}
}
diff --git a/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php b/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php
index bca5523c5f7..aa65f91bb16 100644
--- a/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php
+++ b/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php
@@ -98,6 +98,7 @@ class LanguageAddForm extends LanguageFormBase {
}
// Save the language and inform the user that it happened.
$language = language_save($language);
+
drupal_set_message($this->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
diff --git a/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php b/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php
index 66e1ed17df3..2dacdc2785b 100644
--- a/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php
+++ b/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php
@@ -54,6 +54,7 @@ class LanguageEditForm extends LanguageFormBase {
$language->name = $form_state['values']['name'];
$language->direction = $form_state['values']['direction'];
language_save($language);
+
$form_state['redirect_route']['route_name'] = 'language.admin_overview';
}
diff --git a/core/modules/language/lib/Drupal/language/Form/NegotiationConfigureForm.php b/core/modules/language/lib/Drupal/language/Form/NegotiationConfigureForm.php
index 01dec5bbcf7..c5b2a667d46 100644
--- a/core/modules/language/lib/Drupal/language/Form/NegotiationConfigureForm.php
+++ b/core/modules/language/lib/Drupal/language/Form/NegotiationConfigureForm.php
@@ -14,6 +14,9 @@ use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\LanguageNegotiatorInterface;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -22,36 +25,49 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
class NegotiationConfigureForm extends FormBase {
/**
- * Stores the configuration object for system.language.types.
+ * Stores the configuration object for language.types.
*
* @var \Drupal\Core\Config\Config
*/
- protected $languageTypesConfig;
+ protected $languageTypes;
/**
- * The block manager.
+ * The language manager.
*
- * @var \Drupal\block\Plugin\Type\BlockManager
+ * @var \Drupal\language\ConfigurableLanguageManagerInterface
*/
- protected $blockManager;
+ protected $languageManager;
/**
- * The module handler.
+ * The language negotiator.
*
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ * @var \Drupal\language\LanguageNegotiatorInterface
*/
- protected $moduleHandler;
+ protected $negotiator;
+
+ /**
+ * The block manager.
+ *
+ * @var \Drupal\block\Plugin\Type\BlockManager
+ */
+ protected $blockManager;
/**
* Constructs a NegotiationConfigureForm object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The factory for configuration objects.
+ * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
+ * The language manager.
+ * @param \Drupal\language\LanguageNegotiatorInterface $negotiator
+ * The language negotiation methods manager.
* @param \Drupal\block\Plugin\Type\BlockManager $block_manager
* The block manager, or NULL if not available.
*/
- public function __construct(ConfigFactory $config_factory, BlockManager $block_manager = NULL) {
- $this->languageTypesConfig = $config_factory->get('system.language.types');
+ public function __construct(ConfigFactory $config_factory, ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, BlockManager $block_manager = NULL) {
+ $this->languageTypes = $config_factory->get('language.types');
+ $this->languageManager = $language_manager;
+ $this->negotiator = $negotiator;
$this->blockManager = $block_manager;
}
@@ -61,6 +77,8 @@ class NegotiationConfigureForm extends FormBase {
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
+ $container->get('language_manager'),
+ $container->get('language_negotiator'),
$container->has('plugin.manager.block') ? $container->get('plugin.manager.block') : NULL
);
}
@@ -76,14 +94,12 @@ class NegotiationConfigureForm extends FormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
- language_negotiation_include();
-
- $configurable = $this->languageTypesConfig->get('configurable');
+ $configurable = $this->languageTypes->get('configurable');
$form = array(
'#theme' => 'language_negotiation_configure_form',
- '#language_types_info' => language_types_info(),
- '#language_negotiation_info' => language_negotiation_info(),
+ '#language_types_info' => $this->languageManager->getDefinedLanguageTypesInfo(),
+ '#language_negotiation_info' => $this->negotiator->getNegotiationMethods(),
);
$form['#language_types'] = array();
@@ -111,10 +127,9 @@ class NegotiationConfigureForm extends FormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
- language_negotiation_include();
$configurable_types = $form['#language_types'];
- $stored_values = $this->languageTypesConfig->get('configurable');
+ $stored_values = $this->languageTypes->get('configurable');
$customized = array();
$method_weights_type = array();
@@ -122,7 +137,7 @@ class NegotiationConfigureForm extends FormBase {
$customized[$type] = in_array($type, $stored_values);
$method_weights = array();
$enabled_methods = $form_state['values'][$type]['enabled'];
- $enabled_methods[LANGUAGE_NEGOTIATION_SELECTED] = TRUE;
+ $enabled_methods[LanguageNegotiationSelected::METHOD_ID] = TRUE;
$method_weights_input = $form_state['values'][$type]['weight'];
if (isset($form_state['values'][$type]['configurable'])) {
$customized[$type] = !empty($form_state['values'][$type]['configurable']);
@@ -141,11 +156,11 @@ class NegotiationConfigureForm extends FormBase {
// Update non-configurable language types and the related language
// negotiation configuration.
- language_types_set(array_keys(array_filter($customized)));
+ $this->negotiator->updateConfiguration(array_keys(array_filter($customized)));
// Update the language negotiations after setting the configurability.
foreach ($method_weights_type as $type => $method_weights) {
- language_negotiation_set($type, $method_weights);
+ $this->negotiator->saveConfiguration($type, $method_weights);
}
// Clear block definitions cache since the available blocks and their names
@@ -183,7 +198,7 @@ class NegotiationConfigureForm extends FormBase {
);
// Only show configurability checkbox for the unlocked language types.
if (empty($info['locked'])) {
- $configurable = $this->languageTypesConfig->get('configurable');
+ $configurable = $this->languageTypes->get('configurable');
$table_form['configurable'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Customize %language_name language detection to differ from User interface text language detection settings.', array('%language_name' => $info['name'])),
@@ -246,7 +261,7 @@ class NegotiationConfigureForm extends FormBase {
'#title_display' => 'invisible',
'#default_value' => $enabled,
);
- if ($method_id === LANGUAGE_NEGOTIATION_SELECTED) {
+ if ($method_id === LanguageNegotiationSelected::METHOD_ID) {
$table_form['enabled'][$method_id]['#default_value'] = TRUE;
$table_form['enabled'][$method_id]['#attributes'] = array('disabled' => 'disabled');
}
@@ -254,10 +269,10 @@ class NegotiationConfigureForm extends FormBase {
$table_form['description'][$method_id] = array('#markup' => Xss::filterAdmin($method['description']));
$config_op = array();
- if (isset($method['config'])) {
+ if (isset($method['config_path'])) {
$config_op['configure'] = array(
'title' => $this->t('Configure'),
- 'href' => $method['config'],
+ 'href' => $method['config_path'],
);
// If there is at least one operation enabled show the operation
// column.
diff --git a/core/modules/language/lib/Drupal/language/Form/NegotiationUrlForm.php b/core/modules/language/lib/Drupal/language/Form/NegotiationUrlForm.php
index ac709e30b95..172e6b0ab0e 100644
--- a/core/modules/language/lib/Drupal/language/Form/NegotiationUrlForm.php
+++ b/core/modules/language/lib/Drupal/language/Form/NegotiationUrlForm.php
@@ -8,6 +8,7 @@
namespace Drupal\language\Form;
use Drupal\Core\Form\ConfigFormBase;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
/**
* Configure the URL language negotiation method for this site.
@@ -27,14 +28,13 @@ class NegotiationUrlForm extends ConfigFormBase {
public function buildForm(array $form, array &$form_state) {
global $base_url;
$config = $this->configFactory->get('language.negotiation');
- language_negotiation_include();
$form['language_negotiation_url_part'] = array(
'#title' => t('Part of the URL that determines language'),
'#type' => 'radios',
'#options' => array(
- LANGUAGE_NEGOTIATION_URL_PREFIX => t('Path prefix'),
- LANGUAGE_NEGOTIATION_URL_DOMAIN => t('Domain'),
+ LanguageNegotiationUrl::CONFIG_PATH_PREFIX => t('Path prefix'),
+ LanguageNegotiationUrl::CONFIG_DOMAIN => t('Domain'),
),
'#default_value' => $config->get('url.source'),
);
@@ -47,7 +47,7 @@ class NegotiationUrlForm extends ConfigFormBase {
'#states' => array(
'visible' => array(
':input[name="language_negotiation_url_part"]' => array(
- 'value' => (string) LANGUAGE_NEGOTIATION_URL_PREFIX,
+ 'value' => (string) LanguageNegotiationUrl::CONFIG_PATH_PREFIX,
),
),
),
@@ -60,7 +60,7 @@ class NegotiationUrlForm extends ConfigFormBase {
'#states' => array(
'visible' => array(
':input[name="language_negotiation_url_part"]' => array(
- 'value' => (string) LANGUAGE_NEGOTIATION_URL_DOMAIN,
+ 'value' => (string) LanguageNegotiationUrl::CONFIG_DOMAIN,
),
),
),
@@ -103,7 +103,7 @@ class NegotiationUrlForm extends ConfigFormBase {
$value = $form_state['values']['prefix'][$langcode];
if ($value === '') {
- if (!$language->default && $form_state['values']['language_negotiation_url_part'] == LANGUAGE_NEGOTIATION_URL_PREFIX) {
+ if (!$language->default && $form_state['values']['language_negotiation_url_part'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) {
// Throw a form error if the prefix is blank for a non-default language,
// although it is required for selected negotiation type.
$this->setFormError("prefix][$langcode", $form_state, t('The prefix may only be left blank for the default language.'));
@@ -127,7 +127,7 @@ class NegotiationUrlForm extends ConfigFormBase {
$value = $form_state['values']['domain'][$langcode];
if ($value === '') {
- if (!$language->default && $form_state['values']['language_negotiation_url_part'] == LANGUAGE_NEGOTIATION_URL_DOMAIN) {
+ if (!$language->default && $form_state['values']['language_negotiation_url_part'] == LanguageNegotiationUrl::CONFIG_DOMAIN) {
// Throw a form error if the domain is blank for a non-default language,
// although it is required for selected negotiation type.
$this->setFormError("domain][$langcode", $form_state, t('The domain may only be left blank for the default language.'));
diff --git a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php
index d212c7b2896..71a5cfe3b68 100644
--- a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php
+++ b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php
@@ -8,13 +8,14 @@
namespace Drupal\language\HttpKernel;
use Drupal\Component\Utility\Settings;
+use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactory;
-use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\LanguageNegotiatorInterface;
use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Session\AccountInterface;
/**
* Processes the inbound path using path alias lookups.
@@ -38,129 +39,114 @@ class PathProcessorLanguage implements InboundPathProcessorInterface, OutboundPa
/**
* Language manager for retrieving the url language type.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\language\ConfigurableLanguageManagerInterface
*/
protected $languageManager;
/**
- * An array of enabled languages.
+ * The language negotiator.
+ *
+ * @var \Drupal\language\LanguageNegotiatorInterface
+ */
+ protected $negotiator;
+
+ /**
+ * Local cache for language path processors.
*
* @var array
*/
- protected $languages;
+ protected $processors;
+ /**
+ * Flag indicating whether the site is multilingual.
+ *
+ * @var bool
+ */
+ protected $multilingual;
/**
* Constructs a PathProcessorLanguage object.
*
* @param \Drupal\Core\Config\ConfigFactory $config
* A config factory object for retrieving configuration settings.
- *
- * @param array $languages
- * An array of languages, keyed by language code, representing the languages
- * currently enabled on the site.
+ * @param \Drupal\Component\Utility\Settings $settings
+ * The settings instance.
+ * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
+ * The configurable language manager.
+ * @param \Drupal\language\LanguageNegotiatorInterface
+ * The language negotiator.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current active user.
*/
- public function __construct(ConfigFactory $config, Settings $settings, LanguageManager $language_manager, array $languages = array()) {
+ public function __construct(ConfigFactory $config, Settings $settings, ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, AccountInterface $current_user) {
$this->config = $config;
$this->mixedModeSessions = $settings->get('mixed_mode_sessions', FALSE);
$this->languageManager = $language_manager;
- if (empty($languages)) {
- $languages = language_list();
- }
- $this->languages = $languages;
+ $this->negotiator = $negotiator;
+ $this->negotiator->setCurrentUser($current_user);
}
/**
- * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ * {@inheritdoc}
*/
public function processInbound($path, Request $request) {
if (!empty($path)) {
- $args = explode('/', $path);
- $prefix = array_shift($args);
-
- // Search prefix within enabled languages.
- $prefixes = $this->config->get('language.negotiation')->get('url.prefixes');
- foreach ($this->languages as $language) {
- if (isset($prefixes[$language->id]) && $prefixes[$language->id] == $prefix) {
- // Rebuild $path with the language removed.
- return implode('/', $args);
- }
+ $scope = 'inbound';
+ if (!isset($this->processors[$scope])) {
+ $this->initProcessors($scope);
+ }
+ foreach ($this->processors[$scope] as $instance) {
+ $path = $instance->processInbound($path, $request);
}
}
return $path;
}
/**
- * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processOutbound().
+ * {@inheritdoc}
*/
public function processOutbound($path, &$options = array(), Request $request = NULL) {
- if (!$this->languageManager->isMultilingual()) {
- return $path;
- }
- $url_scheme = 'http';
- $port = 80;
- if ($request) {
- $url_scheme = $request->getScheme();
- $port = $request->getPort();
- }
- $languages = array_flip(array_keys($this->languages));
- // Language can be passed as an option, or we go for current URL language.
- if (!isset($options['language'])) {
- $language_url = $this->languageManager->getLanguage(Language::TYPE_URL);
- $options['language'] = $language_url;
- }
- // We allow only enabled languages here.
- elseif (is_object($options['language']) && !isset($languages[$options['language']->id])) {
- return $path;
+ if (!isset($this->multilingual)) {
+ $this->multilingual = $this->languageManager->isMultilingual();
}
- $url_source = $this->config->get('language.negotiation')->get('url.source');
- // @todo Go back to using a constant instead of the string 'path_prefix' once we can use a class
- // constant.
- if ($url_source == 'path_prefix') {
- $prefixes = $this->config->get('language.negotiation')->get('url.prefixes');
- if (is_object($options['language']) && !empty($prefixes[$options['language']->id])) {
- return empty($path) ? $prefixes[$options['language']->id] : $prefixes[$options['language']->id] . '/' . $path;
+ if ($this->multilingual) {
+ $this->negotiator->setRequest($request);
+ $scope = 'outbound';
+ if (!isset($this->processors[$scope])) {
+ $this->initProcessors($scope);
+ }
+ // Execute outbound language processors.
+ $options['mixed_mode_sessions'] = $this->mixedModeSessions;
+ foreach ($this->processors[$scope] as $instance) {
+ $path = $instance->processOutbound($path, $options, $request);
+ }
+ // No language dependent path allowed in this mode.
+ if (empty($this->processors[$scope])) {
+ unset($options['language']);
}
}
- elseif ($url_source == 'domain') {
- $domains = $this->config->get('language.negotiation')->get('url.domains');
- if (is_object($options['language']) && !empty($domains[$options['language']->id])) {
-
- // Save the original base URL. If it contains a port, we need to
- // retain it below.
- if (!empty($options['base_url'])) {
- // The colon in the URL scheme messes up the port checking below.
- $normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']);
- }
-
- // Ask for an absolute URL with our modified base URL.
- $options['absolute'] = TRUE;
- $options['base_url'] = $url_scheme . '://' . $domains[$options['language']->id];
-
- // In case either the original base URL or the HTTP host contains a
- // port, retain it.
- if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) {
- list( , $port) = explode(':', $normalized_base_url);
- $options['base_url'] .= ':' . $port;
- }
- elseif ($port != 80) {
- $options['base_url'] .= ':' . $port;
- }
+ return $path;
+ }
- if (isset($options['https']) && $this->mixedModeSessions) {
- if ($options['https'] === TRUE) {
- $options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
- }
- elseif ($options['https'] === FALSE) {
- $options['base_url'] = str_replace('https://', 'http://', $options['base_url']);
+ /**
+ * Initializes the local cache for language path processors.
+ *
+ * @param string $scope
+ * The scope of the processors: "inbound" or "outbound".
+ */
+ protected function initProcessors($scope) {
+ $interface = '\Drupal\Core\PathProcessor\\' . Unicode::ucfirst($scope) . 'PathProcessorInterface';
+ $this->processors[$scope] = array();
+ foreach ($this->languageManager->getLanguageTypes() as $type) {
+ foreach ($this->negotiator->getNegotiationMethods($type) as $method_id => $method) {
+ if (!isset($this->processors[$scope][$method_id])) {
+ $reflector = new \ReflectionClass($method['class']);
+ if ($reflector->implementsInterface($interface)) {
+ $this->processors[$scope][$method_id] = $this->negotiator->getNegotiationMethodInstance($method_id);
}
}
-
- // Add Drupal's subfolder from the base_path if there is one.
- $options['base_url'] .= rtrim(base_path(), '/');
}
}
- return $path;
}
}
diff --git a/core/modules/language/lib/Drupal/language/LanguageConfigSubscriber.php b/core/modules/language/lib/Drupal/language/LanguageConfigSubscriber.php
deleted file mode 100644
index 702b85760ac..00000000000
--- a/core/modules/language/lib/Drupal/language/LanguageConfigSubscriber.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
- * @file
- * Contains \Drupal\language\LanguageConfigSubscriber.
- */
-
-namespace Drupal\language;
-
-use Drupal\Core\Config\ConfigFactory;
-use Drupal\Core\Config\StorageDispatcher;
-use Drupal\Core\Language\LanguageManager;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Language event subscriber to set language on configuration factory service.
- */
-class LanguageConfigSubscriber implements EventSubscriberInterface {
-
- /**
- * The language manager.
- *
- * @var \Drupal\Core\Language\LanguageManager
- */
- protected $languageManager;
-
- /**
- * The configuration factory.
- *
- * @var \Drupal\Core\Config\ConfigFactory
- */
- protected $configFactory;
-
- /**
- * Constructs a LanguageConfigSubscriber object.
- *
- * @param \Drupal\Core\Language\LanguageManager $language_manager
- * The language manager service.
- * @param \Drupal\Core\Config\ConfigFactory $config_factory
- * The configuration object factory.
- */
- public function __construct(LanguageManager $language_manager, ConfigFactory $config_factory) {
- $this->languageManager = $language_manager;
- $this->configFactory = $config_factory;
- }
-
- /**
- * Sets the negotiated interface language on the configuration factory.
- *
- * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * Kernel event to respond to.
- */
- public function onKernelRequestSetDefaultConfigLanguage(GetResponseEvent $event) {
- if ($this->languageManager->isMultiLingual()) {
- $this->configFactory->setLanguage($this->languageManager->getLanguage());
- }
- }
-
- /**
- * Implements EventSubscriberInterface::getSubscribedEvents().
- */
- static function getSubscribedEvents() {
- $events[KernelEvents::REQUEST][] = array('onKernelRequestSetDefaultConfigLanguage', 48);
- return $events;
- }
-}
-
diff --git a/core/modules/language/lib/Drupal/language/LanguageListController.php b/core/modules/language/lib/Drupal/language/LanguageListController.php
index 9d65146b0ef..601d0598de8 100644
--- a/core/modules/language/lib/Drupal/language/LanguageListController.php
+++ b/core/modules/language/lib/Drupal/language/LanguageListController.php
@@ -95,11 +95,11 @@ class LanguageListController extends DraggableListController {
public function submitForm(array &$form, array &$form_state) {
parent::submitForm($form, $form_state);
- // Kill the static cache in language_list().
- drupal_static_reset('language_list');
-
- // Update weight of locked system languages.
- language_update_locked_weights();
+ $language_manager = \Drupal::languageManager();
+ $language_manager->reset();
+ if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+ $language_manager->updateLockedLanguageWeights();
+ }
drupal_set_message(t('Configuration saved.'));
}
diff --git a/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodBase.php b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodBase.php
new file mode 100644
index 00000000000..5dc497bd745
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodBase.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageNegotiationMethodBase.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Base class for language negotiation methods.
+ */
+abstract class LanguageNegotiationMethodBase implements LanguageNegotiationMethodInterface {
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * The configuration factory.
+ *
+ * @var \Drupal\Core\Config\ConfigFactory
+ */
+ protected $config;
+
+ /**
+ * The current active user.
+ *
+ * @return \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLanguageManager(ConfigurableLanguageManagerInterface $language_manager) {
+ $this->languageManager = $language_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setConfig(ConfigFactory $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setCurrentUser(AccountInterface $current_user) {
+ $this->currentUser = $current_user;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function persist(Language $language) {
+ // Remember the method ID used to detect the language.
+ $language->method_id = static::METHOD_ID;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodInterface.php b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodInterface.php
new file mode 100644
index 00000000000..3ac20c9e030
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodInterface.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageNegotiationMethodInterface.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface for language negotiation classes.
+ */
+interface LanguageNegotiationMethodInterface {
+
+ /**
+ * Injects the language manager.
+ *
+ * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
+ * The language manager to be used to retrieve the language list and the
+ * already negotiated languages.
+ */
+ public function setLanguageManager(ConfigurableLanguageManagerInterface $language_manager);
+
+ /**
+ * Injects the configuration factory.
+ *
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The configuration factory.
+ */
+ public function setConfig(ConfigFactory $config);
+
+ /**
+ * Injects the current user.
+ *
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current active user.
+ */
+ public function setCurrentUser(AccountInterface $current_user);
+
+ /**
+ * Performs language negotiation.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * (optional) The current request. Defaults to NULL if it has not been
+ * initialized yet.
+ *
+ * @return string
+ * A valid language code or FALSE if the negotitation was unsuccessful.
+ */
+ public function getLangcode(Request $request = NULL);
+
+ /**
+ * Notifies the plugin that the language code it returned has been accepted.
+ *
+ * @param \Drupal\Core\Language\Language $language
+ * The accepted language.
+ */
+ public function persist(Language $language);
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodManager.php b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodManager.php
new file mode 100644
index 00000000000..1480bd6ac9b
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageNegotiationMethodManager.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageNegotiationMethodManager.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Manages language negotiation methods.
+ */
+class LanguageNegotiationMethodManager extends DefaultPluginManager {
+
+ /**
+ * Constructs a new LanguageNegotiationMethodManager object.
+ *
+ * @param \Traversable $namespaces
+ * An object that implements \Traversable which contains the root paths
+ * keyed by the corresponding namespace to look for plugin implementations.
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+ * An object that implements CacheBackendInterface
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * An object that implements ModuleHandlerInterface
+ */
+ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+ parent::__construct('Plugin/LanguageNegotiation', $namespaces);
+ $this->cacheBackend = $cache_backend;
+ $this->cacheKeyPrefix = 'language_negotiation_plugins';
+ $this->cacheKey = 'language_negotiation_plugins';
+ $this->alterInfo($module_handler, 'language_negotiation_info');
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageNegotiator.php b/core/modules/language/lib/Drupal/language/LanguageNegotiator.php
new file mode 100644
index 00000000000..f2a74f6c7ce
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageNegotiator.php
@@ -0,0 +1,372 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageNegotiator.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Utility\Settings;
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class responsible for performing language negotiation.
+ */
+class LanguageNegotiator implements LanguageNegotiatorInterface {
+
+ /**
+ * The language negotiation method plugin manager.
+ *
+ * @var \Drupal\Component\Plugin\PluginManagerInterface
+ */
+ protected $negotiatorManager;
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\language\ConfigurableLanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * The configuration factory.
+ *
+ * @var \Drupal\Core\Config\config
+ */
+ protected $configFactory;
+
+ /**
+ * The settings instance.
+ *
+ * @return \Drupal\Component\Utility\Settings
+ */
+ protected $settings;
+
+ /**
+ * The request object.
+ *
+ * @var \Symfony\Component\HttpFoundation\Request
+ */
+ protected $request;
+
+ /**
+ * The current active user.
+ *
+ * @return \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ /**
+ * Local cache for language negotiation method instances.
+ *
+ * @var array
+ */
+ protected $methods;
+
+ /**
+ * An array of language objects keyed by method id.
+ *
+ * @var array
+ */
+ protected $negotiatedLanguages;
+
+ /**
+ * Constructs a new LanguageNegotiator object.
+ *
+ * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
+ * The language manager.
+ * @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager
+ * The language negotiation methods plugin manager
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The configuration factory.
+ * @param \Drupal\Component\Utility\Settings $settings
+ * The settings instance.
+ */
+ public function __construct(ConfigurableLanguageManagerInterface $language_manager, PluginManagerInterface $negotiator_manager, ConfigFactory $config_factory, Settings $settings) {
+ $this->languageManager = $language_manager;
+ $this->negotiatorManager = $negotiator_manager;
+ $this->configFactory = $config_factory;
+ $this->settings = $settings;
+ }
+
+ /**
+ * Initializes the injected language manager with the negotiator.
+ *
+ * This should be called right after instantiating the negotiator to make it
+ * available to the language manager without introducing a circular
+ * dependency.
+ */
+ public function initLanguageManager() {
+ $this->languageManager->setNegotiator($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset() {
+ $this->negotiatedLanguages = array();
+ $this->methods = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setCurrentUser(AccountInterface $current_user) {
+ $this->currentUser = $current_user;
+ $this->reset();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRequest(Request $request) {
+ $this->request = $request;
+ $this->reset();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initializeType($type) {
+ $language = NULL;
+
+ if ($this->currentUser && $this->request) {
+ // Execute the language negotiation methods in the order they were set up
+ // and return the first valid language found.
+ foreach ($this->getConfiguration($type) as $method_id => $info) {
+ if (!isset($this->negotiatedLanguages[$method_id])) {
+ $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id);
+ }
+
+ // Since objects are references, we need to return a clone to prevent
+ // the language negotiation method cache from being unintentionally
+ // altered. The same methods might be used with different language types
+ // based on configuration.
+ $language = !empty($this->negotiatedLanguages[$method_id]) ? clone($this->negotiatedLanguages[$method_id]) : NULL;
+
+ if ($language) {
+ $this->getNegotiationMethodInstance($method_id)->persist($language);
+ break;
+ }
+ }
+ }
+
+ if (!$language) {
+ // If no other language was found use the default one.
+ $language = $this->languageManager->getDefaultLanguage();
+ $language->method_id = LanguageNegotiatorInterface::METHOD_ID;
+ }
+
+ return $language;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getConfiguration($type) {
+ // @todo convert to CMI https://drupal.org/node/1827038 and
+ // https://drupal.org/node/2102477
+ drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
+ return variable_get("language_negotiation_$type", array());
+ }
+
+ /**
+ * Performs language negotiation using the specified negotiation method.
+ *
+ * @param string $type
+ * The language type to be initialized.
+ * @param string $method_id
+ * The string identifier of the language negotiation method to use to detect
+ * language.
+ *
+ * @return \Drupal\Core\Language\Language|NULL
+ * Negotiated language object for given type and method, FALSE otherwise.
+ */
+ protected function negotiateLanguage($type, $method_id) {
+ $langcode = NULL;
+ $method = $this->negotiatorManager->getDefinition($method_id);
+
+ if (!isset($method['types']) || in_array($type, $method['types'])) {
+
+ // Check for a cache mode force from settings.php.
+ if ($this->settings->get('page_cache_without_database')) {
+ $cache_enabled = TRUE;
+ }
+ else {
+ $cache_enabled = $this->configFactory->get('system.performance')->get('cache.page.use_internal');
+ }
+
+ // If the language negotiation method has no cache preference or this is
+ // satisfied we can execute the callback.
+ if ($cache = !isset($method['cache']) || $this->currentUser->isAuthenticated() || $method['cache'] == $cache_enabled) {
+ $langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->request);
+ }
+ }
+
+ $languages = $this->languageManager->getLanguages();
+ return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNegotiationMethods($type = NULL) {
+ $definitions = $this->negotiatorManager->getDefinitions();
+ if (isset($type)) {
+ $config = $this->getConfiguration($type);
+ $definitions = array_intersect_key($definitions, $config);
+ }
+ return $definitions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNegotiationMethodInstance($method_id) {
+ if (!isset($this->methods[$method_id])) {
+ $instance = $this->negotiatorManager->createInstance($method_id, array());
+ $instance->setLanguageManager($this->languageManager);
+ $instance->setConfig($this->configFactory);
+ $instance->setCurrentUser($this->currentUser);
+ $this->methods[$method_id] = $instance;
+ }
+ return $this->methods[$method_id];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPrimaryNegotiationMethod($type) {
+ $config = $this->getConfiguration($type);
+ return empty($config) ? LanguageNegotiatorInterface::METHOD_ID : key($config);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isNegotiationMethodEnabled($method_id, $type = NULL) {
+ $enabled = FALSE;
+ $language_types = !empty($type) ? array($type) : $this->languageManager->getLanguageTypes();
+
+ foreach ($language_types as $type) {
+ $config = $this->getConfiguration($type);
+ if (isset($config[$method_id])) {
+ $enabled = TRUE;
+ break;
+ }
+ }
+
+ return $enabled;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function saveConfiguration($type, $method_weights) {
+ $definitions = $this->getNegotiationMethods();
+ $default_types = $this->languageManager->getLanguageTypes();
+
+ // Order the language negotiation method list by weight.
+ asort($method_weights);
+ foreach ($method_weights as $method_id => $weight) {
+ if (isset($definitions[$method_id])) {
+ $method = $definitions[$method_id];
+ // If the language negotiation method does not express any preference
+ // about types, make it available for any configurable type.
+ $types = array_flip(!empty($method['types']) ? $method['types'] : $default_types);
+ // Check whether the method is defined and has the right type.
+ if (!isset($types[$type])) {
+ unset($method_weights[$method_id]);
+ }
+ }
+ else {
+ unset($method_weights[$method_id]);
+ }
+ }
+
+ variable_set("language_negotiation_$type", $method_weights);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function purgeConfiguration() {
+ // Ensure that we are getting the defined language negotiation information.
+ // An invocation of \Drupal\Core\Extension\ModuleHandler::install() or
+ // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
+ // cached information.
+ $this->negotiatorManager->clearCachedDefinitions();
+ $this->languageManager->reset();
+ foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) {
+ $this->saveConfiguration($type, $this->getConfiguration($type));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function updateConfiguration(array $types) {
+ // Ensure that we are getting the defined language negotiation information.
+ // An invocation of \Drupal\Core\Extension\ModuleHandler::install() or
+ // \Drupal\Core\Extension\ModuleHandler::uninstall() could invalidate the
+ // cached information.
+ $this->negotiatorManager->clearCachedDefinitions();
+ $this->languageManager->reset();
+
+ $language_types = array();
+ $language_types_info = $this->languageManager->getDefinedLanguageTypesInfo();
+ $method_definitions = $this->getNegotiationMethods();
+
+ foreach ($language_types_info as $type => $info) {
+ $configurable = in_array($type, $types);
+
+ // Check whether the language type is unlocked. Only the status of
+ // unlocked language types can be toggled between configurable and
+ // non-configurable. The default language negotiation settings, if
+ // available, are stored in $info['fixed'].
+ if (empty($info['locked'])) {
+ // If we have a non-locked non-configurable language type without
+ // default language negotiation settings, we use the values negotiated
+ // for the interface language which should always be available.
+ if (!$configurable && !empty($info['fixed'])) {
+ $method_weights = array(LanguageNegotiationUI::METHOD_ID);
+ $method_weights = array_flip($method_weights);
+ $this->saveConfiguration($type, $method_weights);
+ }
+ }
+ else {
+ // Locked language types with default settings are always considered
+ // non-configurable. In turn if default settings are missing, the
+ // language type is always considered configurable.
+ $configurable = empty($info['fixed']);
+
+ // If the language is non-configurable we need to store its language
+ // negotiation settings.
+ if (!$configurable) {
+ $method_weights = array();
+ foreach ($info['fixed'] as $weight => $method_id) {
+ if (isset($method_definitions[$method_id])) {
+ $method_weights[$method_id] = $weight;
+ }
+ }
+ $this->saveConfiguration($type, $method_weights);
+ }
+ }
+
+ $language_types[$type] = $configurable;
+ }
+
+ // Store the language type configuration.
+ $config = array(
+ 'configurable' => array_keys(array_filter($language_types)),
+ 'all' => array_keys($language_types),
+ );
+ $this->languageManager->saveLanguageTypesConfiguration($config);
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageNegotiatorInterface.php b/core/modules/language/lib/Drupal/language/LanguageNegotiatorInterface.php
new file mode 100644
index 00000000000..0654fdec798
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageNegotiatorInterface.php
@@ -0,0 +1,217 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageNegotiatorInterface
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Common interface for language negotiation services.
+ *
+ * The language negotiation API is based on two major concepts:
+ * - Language types: types of translatable data (the types of data that a user
+ * can view or request).
+ * - Language negotiation methods: responsible for determining which language to
+ * use to present a particular piece of data to the user.
+ * Both language types and language negotiation methods are customizable.
+ *
+ * Drupal defines three built-in language types:
+ * - Interface language: The page's main language, used to present translated
+ * user interface elements such as titles, labels, help text, and messages.
+ * - Content language: The language used to present content that is available
+ * in more than one language.
+ * - URL language: The language associated with URLs. When generating a URL,
+ * this value will be used by url() as a default if no explicit preference is
+ * provided.
+ * Modules can define additional language types through
+ * hook_language_types_info(), and alter existing language type definitions
+ * through hook_language_types_info_alter().
+ *
+ * Language types may be configurable or fixed. The language negotiation
+ * methods associated with a configurable language type can be explicitly
+ * set through the user interface. A fixed language type has predetermined
+ * (module-defined) language negotiation settings and, thus, does not appear in
+ * the configuration page. Here is a code snippet that makes the content
+ * language (which by default inherits the interface language's values)
+ * configurable:
+ * @code
+ * function mymodule_language_types_info_alter(&$language_types) {
+ * unset($language_types[Language::TYPE_CONTENT]['fixed']);
+ * }
+ * @endcode
+ *
+ * The locked configuration property prevents one language type from being
+ * switched from customized to not customized, and vice versa.
+ * @see \Drupal\language\LanguageNegotiator::updateConfiguration()
+ *
+ * Every language type can have a different set of language negotiation methods
+ * assigned to it. Different language types often share the same language
+ * negotiation settings, but they can have independent settings if needed. If
+ * two language types are configured the same way, their language switcher
+ * configuration will be functionally identical and the same settings will act
+ * on both language types.
+ *
+ * Drupal defines the following built-in language negotiation methods:
+ * - URL: Determine the language from the URL (path prefix or domain).
+ * - Session: Determine the language from a request/session parameter.
+ * - User: Follow the user's language preference.
+ * - User admin language: Identifie admin language from the user preferences.
+ * - Browser: Determine the language from the browser's language settings.
+ * - Selected language: Use the default site language.
+ * Language negotiation methods are simple plugin classes that implement a
+ * particular logic to return a language code. For instance, the URL method
+ * searches for a valid path prefix or domain name in the current request URL.
+ * If a language negotiation method does not return a valid language code, the
+ * next method associated to the language type (based on method weight) is
+ * invoked.
+ *
+ * Modules can define additional language negotiation methods by simply provide
+ * the related plugins, and alter existing methods through
+ * hook_language_negotiation_info_alter(). Here is an example snippet that lets
+ * path prefixes be ignored for administrative paths:
+ * @code
+ * function mymodule_language_negotiation_info_alter(&$negotiation_info) {
+ * // Replace the original plugin with our own implementation.
+ * $method_id = \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::METHOD_ID;
+ * $negotiation_info[$method_id]['class'] = 'Drupal\my_module\Plugin\LanguageNegotiation\MyLanguageNegotiationUrl';
+ * }
+ *
+ * class MyLanguageNegotiationUrl extends LanguageNegotiationUrl {
+ * public function getCurrentLanguage(Request $request = NULL) {
+ * if ($request) {
+ * // Use the original URL language negotiation method to get a valid
+ * // language code.
+ * $langcode = parent::getCurrentLanguage($request);
+ *
+ * // If we are on an administrative path, override with the default
+ * language.
+ * if ($request->query->has('q') && strtok($request->query->get('q'), '/') == 'admin') {
+ * return $this->languageManager->getDefaultLanguage()->id;
+ * }
+ * return $langcode;
+ * }
+ * }
+ * }
+ * ?>
+ * @endcode
+ *
+ * For more information, see
+ * @link http://drupal.org/node/1497272 Language Negotiation API @endlink
+ */
+interface LanguageNegotiatorInterface {
+
+ /**
+ * The language negotiation method id for the language negotiator itself.
+ */
+ const METHOD_ID = 'language-default';
+
+ /**
+ * Resets the negotiated languages and the method instances.
+ */
+ public function reset();
+
+ /**
+ * Sets the current active user and resets all language types.
+ *
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current active user.
+ */
+ public function setCurrentUser(AccountInterface $current_user);
+
+ /**
+ * Sets the active request and resets all language types.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The HttpRequest object representing the current request.
+ */
+ public function setRequest(Request $request);
+
+ /**
+ * Initializes the specified language type.
+ *
+ * @param string $type
+ * The language type to be initialized.
+ *
+ * @return \Drupal\Core\Language\Language
+ * Return either the language of the specified type or the default language.
+ */
+ public function initializeType($type);
+
+ /**
+ * Returns the language negotiation methods enabled for a language type.
+ *
+ * @param string $type
+ * (optional) The language type. If no type is specified all the method
+ * definitions are returned.
+ *
+ * @return array
+ * An array of language negotiation method definitions keyed by method id.
+ */
+ public function getNegotiationMethods($type = NULL);
+
+ /**
+ * Returns an instance of the specified language negotiation method.
+ *
+ * @param string $method_id
+ * The method identifier.
+ *
+ * @return \Drupal\language\LanguageNegotiationMethodInterface
+ */
+ public function getNegotiationMethodInstance($method_id);
+
+ /**
+ * Returns the ID of the language type's primary language negotiation method.
+ *
+ * @param $type
+ * The language type.
+ *
+ * @return
+ * The identifier of the primary language negotiation method for the given
+ * language type, or the default method if none exists.
+ */
+ public function getPrimaryNegotiationMethod($type);
+
+ /**
+ * Checks whether a language negotiation method is enabled for a language type.
+ *
+ * @param $method_id
+ * The language negotiation method ID.
+ * @param $type
+ * (optional) The language type. If none is passed, all the configurable
+ * language types will be inspected.
+ *
+ * @return
+ * TRUE if the method is enabled for at least one of the given language
+ * types, or FALSE otherwise.
+ */
+ public function isNegotiationMethodEnabled($method_id, $type = NULL);
+
+ /**
+ * Saves a list of language negotiation methods for a language type.
+ *
+ * @param string $type
+ * The language type.
+ * @param array $method_weights
+ * An array of language negotiation method weights keyed by method ID.
+ */
+ function saveConfiguration($type, $method_weights);
+
+ /**
+ * Resave the configuration to purge missing negotiation methods.
+ */
+ function purgeConfiguration();
+
+ /**
+ * Updates the configuration based on the given language types.
+ *
+ * @param array $types
+ * An array of configurable language types.
+ */
+ function updateConfiguration(array $types);
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php
new file mode 100644
index 00000000000..28a719dc28a
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageServiceProvider.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Config\BootstrapConfigStorageFactory;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceProviderBase;
+use Drupal\Core\Language\Language;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Overrides the language_manager service to point to language's module one.
+ */
+class LanguageServiceProvider extends ServiceProviderBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function register(ContainerBuilder $container) {
+ // The following services are needed only on multilingual sites.
+ if ($this->isMultilingual()) {
+ $container->register('language_request_subscriber', 'Drupal\language\EventSubscriber\LanguageRequestSubscriber')
+ ->addTag('event_subscriber')
+ ->addArgument(new Reference('language_manager'))
+ ->addArgument(new Reference('language_negotiator'))
+ ->addArgument(new Reference('string_translation'))
+ ->addArgument(new Reference('current_user'));
+
+ $container->register('path_processor_language', 'Drupal\language\HttpKernel\PathProcessorLanguage')
+ ->addTag('path_processor_inbound', array('priority' => 300))
+ ->addTag('path_processor_outbound', array('priority' => 100))
+ ->addArgument(new Reference('config.factory'))
+ ->addArgument(new Reference('settings'))
+ ->addArgument(new Reference('language_manager'))
+ ->addArgument(new Reference('language_negotiator'))
+ ->addArgument(new Reference('current_user'));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function alter(ContainerBuilder $container) {
+ $definition = $container->getDefinition('language_manager');
+ $definition->setClass('Drupal\language\ConfigurableLanguageManager')
+ ->addArgument(new Reference('config.factory'))
+ ->addArgument(new Reference('module_handler'));
+ }
+
+ /**
+ * Checks whether the site is multilingual.
+ *
+ * @return bool
+ * TRUE if the site is multilingual, FALSE otherwise.
+ */
+ protected function isMultilingual() {
+ $prefix = 'language.entity.';
+ // @todo Try to swap out for config.storage to take advantage of database
+ // and caching. This might prove difficult as this is called before the
+ // container has finished building.
+ $config_storage = BootstrapConfigStorageFactory::get();
+ $config_ids = array_filter($config_storage->listAll($prefix), function($config_id) use ($prefix) {
+ return $config_id != $prefix . Language::LANGCODE_NOT_SPECIFIED && $config_id != $prefix . Language::LANGCODE_NOT_APPLICABLE;
+ });
+ return count($config_ids) > 1;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/LanguageSwitcherInterface.php b/core/modules/language/lib/Drupal/language/LanguageSwitcherInterface.php
new file mode 100644
index 00000000000..d6edd5b2e6c
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageSwitcherInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageSwitcherInterface.
+ */
+
+namespace Drupal\language;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface for language switcher classes.
+ */
+interface LanguageSwitcherInterface {
+
+ /**
+ * Returns language switch links.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ * @param string $type
+ * The language type.
+ * @param string $path
+ * The path links should point to.
+ *
+ * @return array
+ * An array of link arrays keyed by language code.
+ */
+ public function getLanguageSwitchLinks(Request $request, $type, $path);
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
index f53c81b072a..3ccae225053 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
@@ -9,6 +9,9 @@ namespace Drupal\language\Plugin\Block;
use Drupal\block\BlockBase;
use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a 'Language switcher' block.
@@ -20,13 +23,51 @@ use Drupal\Core\Session\AccountInterface;
* derivative = "Drupal\language\Plugin\Derivative\LanguageBlock"
* )
*/
-class LanguageBlock extends BlockBase {
+class LanguageBlock extends BlockBase implements ContainerFactoryPluginInterface {
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * Constructs an LanguageBlock object.
+ *
+ * @param array $configuration
+ * A configuration array containing information about the plugin instance.
+ * @param string $plugin_id
+ * The plugin_id for the plugin instance.
+ * @param array $plugin_definition
+ * The plugin implementation definition.
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+ * The language manager.
+ */
+ public function __construct(array $configuration, $plugin_id, array $plugin_definition, LanguageManagerInterface $language_manager) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition);
+ $this->languageManager = $language_manager;
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+ return new static(
+ $configuration,
+ $plugin_id,
+ $plugin_definition,
+ $container->get('language_manager')
+ );
+ }
+
/**
* {@inheritdoc}
*/
function access(AccountInterface $account) {
- return language_multilingual();
+ return $this->languageManager->isMultilingual();
}
/**
@@ -36,7 +77,7 @@ class LanguageBlock extends BlockBase {
$build = array();
$path = drupal_is_front_page() ? '<front>' : current_path();
$type = $this->getDerivativeId();
- $links = language_negotiation_get_switch_links($type, $path);
+ $links = $this->languageManager->getLanguageSwitchLinks($type, $path);
if (isset($links->links)) {
$build = array(
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Condition/Language.php b/core/modules/language/lib/Drupal/language/Plugin/Condition/Language.php
index 7f4289ea524..9dda57177af 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Condition/Language.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Condition/Language.php
@@ -30,7 +30,7 @@ class Language extends ConditionPluginBase {
*/
public function buildForm(array $form, array &$form_state) {
$form = parent::buildForm($form, $form_state);
- if (language_multilingual()) {
+ if (\Drupal::languageManager()->isMultilingual()) {
// Fetch languages.
$languages = language_list(Lang::STATE_ALL);
$langcodes_options = array();
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
index a329c3b1954..acf276fb7e4 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
@@ -8,28 +8,35 @@
namespace Drupal\language\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
+use Drupal\language\ConfigurableLanguageManagerInterface;
/**
* Provides language switcher block plugin definitions for all languages.
*/
class LanguageBlock extends DerivativeBase {
+
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
- include_once DRUPAL_ROOT . '/core/includes/language.inc';
- $info = language_types_info();
- $configurable_types = language_types_get_configurable();
- foreach ($configurable_types as $type) {
- $this->derivatives[$type] = $base_plugin_definition;
- $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name']));
- $this->derivatives[$type]['cache'] = DRUPAL_NO_CACHE;
- }
- // If there is just one configurable type then change the title of the
- // block.
- if (count($configurable_types) == 1) {
- $this->derivatives[reset($configurable_types)]['admin_label'] = t('Language switcher');
+ $language_manager = \Drupal::languageManager();
+
+ if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+ $info = $language_manager->getDefinedLanguageTypesInfo();
+ $configurable_types = $language_manager->getLanguageTypes();
+ foreach ($configurable_types as $type) {
+ $this->derivatives[$type] = $base_plugin_definition;
+ $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name']));
+ $this->derivatives[$type]['cache'] = DRUPAL_NO_CACHE;
+ }
+ // If there is just one configurable type then change the title of the
+ // block.
+ if (count($configurable_types) == 1) {
+ $this->derivatives[reset($configurable_types)]['admin_label'] = t('Language switcher');
+ }
}
+
return parent::getDerivativeDefinitions($base_plugin_definition);
}
+
}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php
new file mode 100644
index 00000000000..0ce2c86c694
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\Component\Utility\UserAgent;
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language from the browser Accept-language HTTP header.
+ *
+ * @Plugin(
+ * id = \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser::METHOD_ID,
+ * weight = -2,
+ * cache = 0,
+ * name = @Translation("Browser"),
+ * description = @Translation("Language from the browser's language settings."),
+ * config_path = "admin/config/regional/language/detection/browser"
+ * )
+ */
+class LanguageNegotiationBrowser extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-browser';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ if ($this->languageManager && $request && $request->server->get('HTTP_ACCEPT_LANGUAGE')) {
+ $http_accept_language = $request->server->get('HTTP_ACCEPT_LANGUAGE');
+ $langcodes = array_keys($this->languageManager->getLanguages());
+ $mappings = $this->config->get('language.mappings')->get();
+ $langcode = UserAgent::getBestMatchingLangcode($http_accept_language, $langcodes, $mappings);
+ }
+
+ return $langcode;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php
new file mode 100644
index 00000000000..bdbedc526cd
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language from a selected language.
+ *
+ * @Plugin(
+ * id = Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected::METHOD_ID,
+ * weight = 12,
+ * name = @Translation("Selected language"),
+ * description = @Translation("Language based on a selected language."),
+ * config_path = "admin/config/regional/language/detection/selected"
+ * )
+ */
+class LanguageNegotiationSelected extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-selected';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ if ($this->languageManager) {
+ $languages = $this->languageManager->getLanguages();
+ $langcode = $this->config->get('language.negotiation')->get('selected_langcode');
+ }
+
+ return $langcode;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
new file mode 100644
index 00000000000..e56278d6c76
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSession.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\Core\Language\Language;
+use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\language\LanguageNegotiationMethodBase;
+use Drupal\language\LanguageSwitcherInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Identify language from a request/session parameter.
+ *
+ * @Plugin(
+ * id = Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSession::METHOD_ID,
+ * weight = -6,
+ * name = @Translation("Session"),
+ * description = @Translation("Language from a request/session parameter."),
+ * config_path = "admin/config/regional/language/detection/session"
+ * )
+ */
+class LanguageNegotiationSession extends LanguageNegotiationMethodBase implements OutboundPathProcessorInterface, LanguageSwitcherInterface {
+
+ /**
+ * Flag used to determine whether query rewriting is active.
+ *
+ * @var bool
+ */
+ protected $queryRewrite;
+
+ /**
+ * The query parameter name to rewrite.
+ *
+ * @var string
+ */
+ protected $queryParam;
+
+ /**
+ * The query parameter value to be set.
+ *
+ * @var string
+ */
+ protected $queryValue;
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-session';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $config = $this->config->get('language.negotiation')->get('session');
+ $param = $config['parameter'];
+ $langcode = $request && $request->query->get($param) ? $request->query->get($param) : NULL;
+ if (!$langcode && isset($_SESSION[$param])) {
+ $langcode = $_SESSION[$param];
+ }
+ return $langcode;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function persist(Language $language) {
+ parent::persist($language);
+
+ // We need to update the session parameter with the request value only if we
+ // have an authenticated user.
+ $langcode = $language->id;
+ if ($langcode && $this->languageManager) {
+ $languages = $this->languageManager->getLanguages();
+ if ($this->currentUser->isAuthenticated() && isset($languages[$langcode])) {
+ $config = $this->config->get('language.negotiation')->get('session');
+ $_SESSION[$config['parameter']] = $langcode;
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function processOutbound($path, &$options = array(), Request $request = NULL) {
+ if ($request) {
+ // The following values are not supposed to change during a single page
+ // request processing.
+ if (!isset($this->queryRewrite)) {
+ if ($this->currentUser->isAnonymous()) {
+ $languages = $this->languageManager->getLanguages();
+ $config = $this->config->get('language.negotiation')->get('session');
+ $this->queryParam = $config['parameter'];
+ $this->queryValue = $request->query->has($this->queryParam) ? $request->query->get($this->queryParam) : NULL;
+ $this->queryRewrite = isset($languages[$this->queryValue]);
+ }
+ else {
+ $this->queryRewrite = FALSE;
+ }
+ }
+
+ // If the user is anonymous, the user language negotiation method is
+ // enabled, and the corresponding option has been set, we must preserve
+ // any explicit user language preference even with cookies disabled.
+ if ($this->queryRewrite) {
+ if (isset($options['query']) && is_string($options['query'])) {
+ $query = array();
+ parse_str($options['query'], $query);
+ $options['query'] = $query;
+ }
+ if (!isset($options['query'][$this->queryParam])) {
+ $options['query'][$this->queryParam] = $this->queryValue;
+ }
+ }
+ }
+ return $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function getLanguageSwitchLinks(Request $request, $type, $path) {
+ $links = array();
+ $config = $this->config->get('language.negotiation')->get('session');
+ $param = $config['parameter'];
+ $language_query = isset($_SESSION[$param]) ? $_SESSION[$param] : $this->languageManager->getCurrentLanguage($type)->id;
+ $query = array();
+ parse_str($request->getQueryString(), $query);
+
+ foreach ($this->languageManager->getLanguages() as $language) {
+ $langcode = $language->id;
+ $links[$langcode] = array(
+ 'href' => $path,
+ 'title' => $language->name,
+ 'attributes' => array('class' => array('language-link')),
+ 'query' => $query,
+ );
+ if ($language_query != $langcode) {
+ $links[$langcode]['query'][$param] = $langcode;
+ }
+ else {
+ $links[$langcode]['attributes']['class'][] = 'session-active';
+ }
+ }
+
+ return $links;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php
new file mode 100644
index 00000000000..3b649741c48
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying the language from the current interface language.
+ *
+ * @Plugin(
+ * id = Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI::METHOD_ID,
+ * types = {Drupal\Core\Language\Language::TYPE_CONTENT},
+ * weight = 9,
+ * name = @Translation("Interface"),
+ * description = @Translation("Use the detected interface language.")
+ * )
+ */
+class LanguageNegotiationUI extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-interface';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ return $this->languageManager ? $this->languageManager->getCurrentLanguage()->id : NULL;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php
new file mode 100644
index 00000000000..a72ca444c8f
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php
@@ -0,0 +1,203 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\Core\Language\Language;
+use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\language\LanguageNegotiationMethodBase;
+use Drupal\language\LanguageSwitcherInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language via URL prefix or domain.
+ *
+ * @Plugin(
+ * id = \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::METHOD_ID,
+ * types = {\Drupal\Core\Language\Language::TYPE_INTERFACE, \Drupal\Core\Language\Language::TYPE_CONTENT, \Drupal\Core\Language\Language::TYPE_URL},
+ * weight = -8,
+ * name = @Translation("URL"),
+ * description = @Translation("Language from the URL (Path prefix or domain)."),
+ * config_path = "admin/config/regional/language/detection/url"
+ * )
+ */
+class LanguageNegotiationUrl extends LanguageNegotiationMethodBase implements InboundPathProcessorInterface, OutboundPathProcessorInterface, LanguageSwitcherInterface {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-url';
+
+ /**
+ * URL language negotiation: use the path prefix as URL language indicator.
+ */
+ const CONFIG_PATH_PREFIX = 'path_prefix';
+
+ /**
+ * URL language negotiation: use the domain as URL language indicator.
+ */
+ const CONFIG_DOMAIN = 'domain';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ if ($request && $this->languageManager) {
+ $languages = $this->languageManager->getLanguages();
+ $config = $this->config->get('language.negotiation')->get('url');
+
+ switch ($config['source']) {
+ case LanguageNegotiationUrl::CONFIG_PATH_PREFIX:
+ $request_path = urldecode(trim($request->getPathInfo(), '/'));
+ $path_args = explode('/', $request_path);
+ $prefix = array_shift($path_args);
+
+ // Search prefix within enabled languages.
+ $negotiated_language = FALSE;
+ foreach ($languages as $language) {
+ if (isset($config['prefixes'][$language->id]) && $config['prefixes'][$language->id] == $prefix) {
+ $negotiated_language = $language;
+ break;
+ }
+ }
+
+ if ($negotiated_language) {
+ $langcode = $negotiated_language->id;
+ }
+ break;
+
+ case LanguageNegotiationUrl::CONFIG_DOMAIN:
+ // Get only the host, not the port.
+ $http_host = $request->getHost();
+ foreach ($languages as $language) {
+ // Skip the check if the language doesn't have a domain.
+ if (!empty($config['domains'][$language->id])) {
+ // Ensure that there is exactly one protocol in the URL when
+ // checking the hostname.
+ $host = 'http://' . str_replace(array('http://', 'https://'), '', $config['domains'][$language->id]);
+ $host = parse_url($host, PHP_URL_HOST);
+ if ($http_host == $host) {
+ $langcode = $language->id;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return $langcode;
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound().
+ */
+ public function processInbound($path, Request $request) {
+ $config = $this->config->get('language.negotiation')->get('url');
+ $parts = explode('/', $path);
+ $prefix = array_shift($parts);
+
+ // Search prefix within enabled languages.
+ foreach ($this->languageManager->getLanguages() as $language) {
+ if (isset($config['prefixes'][$language->id]) && $config['prefixes'][$language->id] == $prefix) {
+ // Rebuild $path with the language removed.
+ $path = implode('/', $parts);
+ break;
+ }
+ }
+
+ return $path;
+ }
+
+ /**
+ * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processOutbound().
+ */
+ public function processOutbound($path, &$options = array(), Request $request = NULL) {
+ $url_scheme = 'http';
+ $port = 80;
+ if ($request) {
+ $url_scheme = $request->getScheme();
+ $port = $request->getPort();
+ }
+ $languages = array_flip(array_keys($this->languageManager->getLanguages()));
+ // Language can be passed as an option, or we go for current URL language.
+ if (!isset($options['language'])) {
+ $language_url = $this->languageManager->getCurrentLanguage(Language::TYPE_URL);
+ $options['language'] = $language_url;
+ }
+ // We allow only enabled languages here.
+ elseif (!is_object($options['language']) || !isset($languages[$options['language']->id])) {
+ return $path;
+ }
+ $config = $this->config->get('language.negotiation')->get('url');
+ if ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) {
+ if (is_object($options['language']) && !empty($config['prefixes'][$options['language']->id])) {
+ return empty($path) ? $config['prefixes'][$options['language']->id] : $config['prefixes'][$options['language']->id] . '/' . $path;
+ }
+ }
+ elseif ($config['source'] == LanguageNegotiationUrl::CONFIG_DOMAIN) {
+ if (is_object($options['language']) && !empty($config['domains'][$options['language']->id])) {
+
+ // Save the original base URL. If it contains a port, we need to
+ // retain it below.
+ if (!empty($options['base_url'])) {
+ // The colon in the URL scheme messes up the port checking below.
+ $normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']);
+ }
+
+ // Ask for an absolute URL with our modified base URL.
+ $options['absolute'] = TRUE;
+ $options['base_url'] = $url_scheme . '://' . $config['domains'][$options['language']->id];
+
+ // In case either the original base URL or the HTTP host contains a
+ // port, retain it.
+ if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) {
+ list(, $port) = explode(':', $normalized_base_url);
+ $options['base_url'] .= ':' . $port;
+ }
+ elseif ($port != 80) {
+ $options['base_url'] .= ':' . $port;
+ }
+
+ if (isset($options['https']) && !empty($options['mixed_mode_sessions'])) {
+ if ($options['https'] === TRUE) {
+ $options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
+ }
+ elseif ($options['https'] === FALSE) {
+ $options['base_url'] = str_replace('https://', 'http://', $options['base_url']);
+ }
+ }
+
+ // Add Drupal's subfolder from the base_path if there is one.
+ $options['base_url'] .= rtrim(base_path(), '/');
+ }
+ }
+ return $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function getLanguageSwitchLinks(Request $request, $type, $path) {
+ $links = array();
+
+ foreach ($this->languageManager->getLanguages() as $language) {
+ $links[$language->id] = array(
+ 'href' => $path,
+ 'title' => $language->name,
+ 'language' => $language,
+ 'attributes' => array('class' => array('language-link')),
+ );
+ }
+
+ return $links;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php
new file mode 100644
index 00000000000..2310153a071
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrlFallback.
+ */
+
+namespace Drupal\language\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class that determines the language to be assigned to URLs when none is
+ * detected.
+ *
+ * The language negotiation process has a fallback chain that ends with the
+ * default language negotiation method. Each built-in language type has a
+ * separate initialization:
+ * - Interface language, which is the only configurable one, always gets a valid
+ * value. If no request-specific language is detected, the default language
+ * will be used.
+ * - Content language merely inherits the interface language by default.
+ * - URL language is detected from the requested URL and will be used to rewrite
+ * URLs appearing in the page being rendered. If no language can be detected,
+ * there are two possibilities:
+ * - If the default language has no configured path prefix or domain, then the
+ * default language is used. This guarantees that (missing) URL prefixes are
+ * preserved when navigating through the site.
+ * - If the default language has a configured path prefix or domain, a
+ * requested URL having an empty prefix or domain is an anomaly that must be
+ * fixed. This is done by introducing a prefix or domain in the rendered
+ * page matching the detected interface language.
+ *
+ * @Plugin(
+ * id = Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrlFallback::METHOD_ID,
+ * types = {Drupal\Core\Language\Language::TYPE_URL},
+ * weight = 8,
+ * name = @Translation("URL fallback"),
+ * description = @Translation("Use an already detected language for URLs if none is found.")
+ * )
+ */
+class LanguageNegotiationUrlFallback extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-url-fallback';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ if ($this->languageManager) {
+ $default = $this->languageManager->getDefaultLanguage();
+ $config = $this->config->get('language.negotiation')->get('url');
+ $prefix = ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX);
+
+ // If the default language is not configured to convey language
+ // information, a missing URL language information indicates that URL
+ // language should be the default one, otherwise we fall back to an
+ // already detected language.
+ if (($prefix && empty($config['prefixes'][$default->id])) || (!$prefix && empty($config['domains'][$default->id]))) {
+ $langcode = $default->id;
+ }
+ else {
+ $langcode = $this->languageManager->getCurrentLanguage()->id;
+ }
+ }
+
+ return $langcode;
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/Condition/LanguageConditionTest.php b/core/modules/language/lib/Drupal/language/Tests/Condition/LanguageConditionTest.php
index 19449d89c1b..ed029fa74fd 100644
--- a/core/modules/language/lib/Drupal/language/Tests/Condition/LanguageConditionTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/Condition/LanguageConditionTest.php
@@ -26,7 +26,7 @@ class LanguageConditionTest extends DrupalUnitTestBase {
/**
* The language manager.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
index 679d6f973eb..55716687e9c 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
@@ -7,8 +7,10 @@
namespace Drupal\language\Tests;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Component\Utility\UserAgent;
use Drupal\Core\Language\Language;
+use Drupal\simpletest\WebTestBase;
+use Symfony\Component\HttpFoundation\Request;
/**
* Test browser language detection.
@@ -153,9 +155,9 @@ class LanguageBrowserDetectionUnitTest extends WebTestBase {
'zh-cht' => 'zh-hant',
);
+ $mappings = $this->container->get('config.factory')->get('language.mappings')->get();
foreach ($test_cases as $accept_language => $expected_result) {
- \Drupal::request()->server->set('HTTP_ACCEPT_LANGUAGE', $accept_language);
- $result = language_from_browser($languages);
+ $result = UserAgent::getBestMatchingLangcode($accept_language, array_keys($languages), $mappings);
$this->assertIdentical($result, $expected_result, format_string("Language selection '@accept-language' selects '@result', result = '@actual'", array('@accept-language' => $accept_language, '@result' => $expected_result, '@actual' => isset($result) ? $result : 'none')));
}
}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
index 1fb8c853788..6f9c5523d47 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
@@ -72,7 +72,7 @@ class LanguageConfigurationTest extends WebTestBase {
);
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
$this->assertOptionSelected('edit-site-default-language', 'fr', 'Default language updated.');
- $this->assertEqual($this->getUrl(), url('admin/config/regional/settings', array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url('fr/admin/config/regional/settings', array('absolute' => TRUE)), 'Correct page redirection.');
// Check if a valid language prefix is added after changing the default
// language.
@@ -156,10 +156,10 @@ class LanguageConfigurationTest extends WebTestBase {
*/
protected function checkConfigurableLanguageWeight($state = 'by default') {
// Reset language list.
- drupal_static_reset('language_list');
+ \Drupal::languageManager()->reset();
$max_configurable_language_weight = $this->getHighestConfigurableLanguageWeight();
$replacements = array('@event' => $state);
- foreach (language_list(Language::STATE_LOCKED) as $locked_language) {
+ foreach (\Drupal::languageManager()->getLanguages(Language::STATE_LOCKED) as $locked_language) {
$replacements['%language'] = $locked_language->name;
$this->assertTrue($locked_language->weight > $max_configurable_language_weight, format_string('System language %language has higher weight than configurable languages @event', $replacements));
}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
index ca496731726..969a836ccaa 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
@@ -9,36 +9,23 @@ namespace Drupal\language\Tests;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\Language;
-use Drupal\simpletest\WebTestBase;
/**
* Test for dependency injected language object.
*/
-class LanguageDependencyInjectionTest extends WebTestBase {
+class LanguageDependencyInjectionTest extends LanguageTestBase {
/**
- * Modules to enable.
- *
- * @var array
+ * {@inheritdoc}
*/
- public static $modules = array('language');
-
public static function getInfo() {
return array(
- 'name' => 'Language dependency injection',
- 'description' => 'Compares the default language from $GLOBALS against the dependency injected language object.',
- 'group' => 'Language',
+ 'name' => 'Language dependency injection',
+ 'description' => 'Compares the default language from $GLOBALS against the dependency injected language object.',
+ 'group' => 'Language',
);
}
- function setUp() {
- parent::setUp();
-
- // Ensure we are building a new Language object for each test.
- $this->container->get('language_manager')->reset();
- }
-
-
/**
* Test dependency injected languages against a new Language object.
*
@@ -48,8 +35,8 @@ class LanguageDependencyInjectionTest extends WebTestBase {
// Initialize the language system.
drupal_language_initialize();
- $expected = language_default();
- $result = language(Language::TYPE_INTERFACE);
+ $expected = $this->languageManager->getDefaultLanguage();
+ $result = $this->languageManager->getCurrentLanguage();
foreach ($expected as $property => $value) {
$this->assertEqual($expected->$property, $result->$property, format_string('The dependency injected language object %prop property equals the new Language object %prop property.', array('%prop' => $property)));
}
@@ -74,12 +61,12 @@ class LanguageDependencyInjectionTest extends WebTestBase {
variable_set('language_default', $new_language_default);
// Initialize the language system.
- drupal_language_initialize();
+ $this->languageManager->init();
// The language system creates a Language object which contains the
// same properties as the new default language object.
$expected = new Language($new_language_default);
- $result = language(Language::TYPE_INTERFACE);
+ $result = $this->languageManager->getCurrentLanguage();
foreach ($expected as $property => $value) {
$this->assertEqual($expected->$property, $result->$property, format_string('The dependency injected language object %prop property equals the default language object %prop property.', array('%prop' => $property)));
}
@@ -87,4 +74,5 @@ class LanguageDependencyInjectionTest extends WebTestBase {
// Delete the language_default variable we previously set.
variable_del('language_default');
}
+
}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageFallbackTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageFallbackTest.php
index 4123fc02085..fb621d8fafd 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageFallbackTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageFallbackTest.php
@@ -8,12 +8,11 @@
namespace Drupal\language\Tests;
use Drupal\Core\Language\Language;
-use Drupal\simpletest\DrupalUnitTestBase;
/**
* Tests the language fallback behavior.
*/
-class LanguageFallbackTest extends DrupalUnitTestBase {
+class LanguageFallbackTest extends LanguageTestBase {
public static function getInfo() {
return array(
@@ -24,23 +23,11 @@ class LanguageFallbackTest extends DrupalUnitTestBase {
}
/**
- * The state storage service.
- *
- * @var \Drupal\Core\KeyValueStore\StateInterface
- */
- protected $state;
-
- /**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
- $this->enableModules(array('language', 'language_test'));
- $this->installConfig(array('language'));
-
- $this->state = $this->container->get('state');
-
for ($i = 0; $i < 3; $i++) {
$language = new Language();
$language->id = $this->randomName(2);
@@ -53,18 +40,18 @@ class LanguageFallbackTest extends DrupalUnitTestBase {
* Tests language fallback candidates.
*/
public function testCandidates() {
- $manager = $this->getLanguageManager();
- $expected = array_keys(language_list() + array(Language::LANGCODE_NOT_SPECIFIED => NULL));
+ $language_list = $this->languageManager->getLanguages();
+ $expected = array_keys($language_list + array(Language::LANGCODE_NOT_SPECIFIED => NULL));
// Check that language fallback candidates by default are all the available
// languages sorted by weight.
- $candidates = $manager->getFallbackCandidates();
+ $candidates = $this->languageManager->getFallbackCandidates();
$this->assertEqual(array_values($candidates), $expected, 'Language fallback candidates are properly returned.');
// Check that candidates are alterable.
$this->state->set('language_test.fallback_alter.candidates', TRUE);
$expected = array_slice($expected, 0, count($expected) - 1);
- $candidates = $manager->getFallbackCandidates();
+ $candidates = $this->languageManager->getFallbackCandidates();
$this->assertEqual(array_values($candidates), $expected, 'Language fallback candidates are alterable.');
// Check that candidates are alterable for specific operations.
@@ -72,28 +59,18 @@ class LanguageFallbackTest extends DrupalUnitTestBase {
$this->state->set('language_test.fallback_operation_alter.candidates', TRUE);
$expected[] = Language::LANGCODE_NOT_SPECIFIED;
$expected[] = Language::LANGCODE_NOT_APPLICABLE;
- $candidates = $manager->getFallbackCandidates(NULL, array('operation' => 'test'));
+ $candidates = $this->languageManager->getFallbackCandidates(NULL, array('operation' => 'test'));
$this->assertEqual(array_values($candidates), $expected, 'Language fallback candidates are alterable for specific operations.');
// Check that when the site is monolingual no language fallback is applied.
- $default_langcode = language_default()->id;
- foreach (language_list() as $langcode => $language) {
+ $default_langcode = $this->languageManager->getDefaultLanguage()->id;
+ foreach ($language_list as $langcode => $language) {
if ($langcode != $default_langcode) {
language_delete($langcode);
}
}
- $candidates = $this->getLanguageManager()->getFallbackCandidates();
+ $candidates = $this->languageManager->getFallbackCandidates();
$this->assertEqual(array_values($candidates), array(Language::LANGCODE_DEFAULT), 'Language fallback is not applied when the Language module is not enabled.');
}
- /**
- * Returns the language manager service.
- *
- * @return \Drupal\Core\Language\LanguageManager
- * The language manager.
- */
- protected function getLanguageManager() {
- return $this->container->get('language_manager');
- }
-
}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
index 8b2190d4746..a475c04cae7 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
@@ -72,11 +72,11 @@ class LanguageListTest extends WebTestBase {
);
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
$this->assertNoOptionSelected('edit-site-default-language', 'en', 'Default language updated.');
- $this->assertEqual($this->getUrl(), url($path, array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url($langcode . '/' . $path, array('absolute' => TRUE)), 'Correct page redirection.');
// Ensure we can't delete the default language.
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url($langcode . '/admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
$this->assertText(t('The default language cannot be deleted.'), 'Failed to delete the default language.');
// Ensure 'Edit' link works.
@@ -89,7 +89,7 @@ class LanguageListTest extends WebTestBase {
);
$this->drupalPostForm('admin/config/regional/language/edit/' . $langcode, $edit, t('Save language'));
$this->assertRaw($name, 'The language has been updated.');
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url($langcode . '/admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
// Change back the default language.
$edit = array(
@@ -104,7 +104,7 @@ class LanguageListTest extends WebTestBase {
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
// First test the 'cancel' link.
$this->clickLink(t('Cancel'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url('en/admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
$this->assertRaw($name, 'The language was not deleted.');
// Delete the language for real. This a confirm form, we do not need any
// fields changed.
@@ -112,19 +112,17 @@ class LanguageListTest extends WebTestBase {
// We need raw here because %language and %langcode will add HTML.
$t_args = array('%language' => $name, '%langcode' => $langcode);
$this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), 'The test language has been removed.');
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url('en/admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
// Verify that language is no longer found.
$this->drupalGet('admin/config/regional/language/delete/' . $langcode);
$this->assertResponse(404, 'Language no longer found.');
// Make sure the "language_count" state has been updated correctly.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
$languages = language_list();
- $language_count = $this->container->get('state')->get('language_count') ?: 1;
- $this->assertEqual($language_count, count($languages), 'Language count is correct.');
// Delete French.
$this->drupalPostForm('admin/config/regional/language/delete/fr', array(), t('Delete'));
// Get the count of languages.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
$languages = language_list();
// We need raw here because %language and %langcode will add HTML.
$t_args = array('%language' => 'French', '%langcode' => 'fr');
@@ -134,8 +132,6 @@ class LanguageListTest extends WebTestBase {
$this->drupalGet('admin/config/regional/language/delete/fr');
$this->assertResponse(404, 'Language no longer found.');
// Make sure the "language_count" state has not changed.
- $language_count = $this->container->get('state')->get('language_count') ?: 1;
- $this->assertEqual($language_count, count($languages), 'Language count is correct.');
// Ensure we can delete the English language. Right now English is the only
// language so we must add a new language and make it the default before
@@ -162,7 +158,7 @@ class LanguageListTest extends WebTestBase {
);
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
$this->assertNoOptionSelected('edit-site-default-language', 'en', 'Default language updated.');
- $this->assertEqual($this->getUrl(), url($path, array('absolute' => TRUE)), 'Correct page redirection.');
+ $this->assertEqual($this->getUrl(), url($langcode . '/' . $path, array('absolute' => TRUE)), 'Correct page redirection.');
$this->drupalPostForm('admin/config/regional/language/delete/en', array(), t('Delete'));
// We need raw here because %language and %langcode will add HTML.
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
index 6cff10616b8..471dab28ee0 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
@@ -8,6 +8,7 @@
namespace Drupal\language\Tests;
use Drupal\Core\Language\Language;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
use Drupal\simpletest\WebTestBase;
/**
@@ -22,6 +23,16 @@ class LanguageNegotiationInfoTest extends WebTestBase {
*/
public static $modules = array('language');
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\language\ConfigurableLanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * {@inheritdoc}
+ */
public static function getInfo() {
return array(
'name' => 'Language negotiation info',
@@ -30,9 +41,12 @@ class LanguageNegotiationInfoTest extends WebTestBase {
);
}
+ /**
+ * {@inheritdoc}
+ */
function setUp() {
parent::setUp();
- require_once DRUPAL_ROOT .'/core/includes/language.inc';
+ $this->languageManager = $this->container->get('language_manager');
$admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
$this->drupalLogin($admin_user);
$this->drupalPostForm('admin/config/regional/language/add', array('predefined_langcode' => 'it'), t('Add language'));
@@ -56,13 +70,13 @@ class LanguageNegotiationInfoTest extends WebTestBase {
\Drupal::state()->set('language_test.content_language_type', TRUE);
$this->languageNegotiationUpdate();
$type = Language::TYPE_CONTENT;
- $language_types = language_types_get_configurable();
+ $language_types = $this->languageManager->getLanguageTypes();
$this->assertTrue(in_array($type, $language_types), 'Content language type is configurable.');
// Enable some core and custom language negotiation methods. The test
// language type is supposed to be configurable.
$test_type = 'test_language_type';
- $interface_method_id = LANGUAGE_NEGOTIATION_INTERFACE;
+ $interface_method_id = LanguageNegotiationUI::METHOD_ID;
$test_method_id = 'test_language_negotiation_method';
$form_field = $type . '[enabled]['. $interface_method_id .']';
$edit = array(
@@ -83,7 +97,7 @@ class LanguageNegotiationInfoTest extends WebTestBase {
// Check that type-specific language negotiation methods can be assigned
// only to the corresponding language types.
- foreach (language_types_get_configurable() as $type) {
+ foreach ($this->languageManager->getLanguageTypes() as $type) {
$form_field = $type . '[enabled][test_language_negotiation_method_ts]';
if ($type == $test_type) {
$this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, format_string('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
@@ -96,7 +110,7 @@ class LanguageNegotiationInfoTest extends WebTestBase {
// Check language negotiation results.
$this->drupalGet('');
$last = \Drupal::state()->get('language_test.language_negotiation_last');
- foreach (language_types_get_all() as $type) {
+ foreach ($this->languageManager->getDefinedLanguageTypes() as $type) {
$langcode = $last[$type];
$value = $type == Language::TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
$this->assertEqual($langcode, $value, format_string('The negotiated language for %type is %language', array('%type' => $type, '%language' => $value)));
@@ -107,7 +121,7 @@ class LanguageNegotiationInfoTest extends WebTestBase {
$this->languageNegotiationUpdate('uninstall');
// Check that only the core language types are available.
- foreach (language_types_get_all() as $type) {
+ foreach ($this->languageManager->getDefinedLanguageTypes() as $type) {
$this->assertTrue(strpos($type, 'test') === FALSE, format_string('The %type language is still available', array('%type' => $type)));
}
@@ -139,17 +153,16 @@ class LanguageNegotiationInfoTest extends WebTestBase {
// Install/uninstall language_test only if we did not already before.
if ($last_op != $op) {
call_user_func(array($this->container->get('module_handler'), $op), $modules);
- // Reset hook implementation cache.
- $this->container->get('module_handler')->resetImplementations();
+ $last_op = $op;
}
-
- drupal_static_reset('language_types_info');
- drupal_static_reset('language_negotiation_info');
- $function = "language_modules_{$op}ed";
- if (function_exists($function)) {
- $function($modules);
+ else {
+ $function = "language_modules_{$op}ed";
+ if (function_exists($function)) {
+ $function($modules);
+ }
}
+ $this->languageManager->reset();
$this->drupalGet('admin/config/regional/language/detection');
}
@@ -157,9 +170,8 @@ class LanguageNegotiationInfoTest extends WebTestBase {
* Check that language negotiation for fixed types matches the stored one.
*/
protected function checkFixedLanguageTypes() {
- drupal_static_reset('language_types_info');
- $configurable = language_types_get_configurable();
- foreach (language_types_info() as $type => $info) {
+ $configurable = $this->languageManager->getLanguageTypes();
+ foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) {
if (!in_array($type, $configurable) && isset($info['fixed'])) {
$negotiation = variable_get("language_negotiation_$type", array());
$equal = count($info['fixed']) == count($negotiation);
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
index 731ccf0a2bb..840f8fc5071 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
@@ -51,7 +51,8 @@ class LanguagePathMonolingualTest extends WebTestBase {
$this->drupalPostForm('admin/config/regional/language/delete/en', array(), t('Delete'));
// Verify that French is the only language.
- $this->assertFalse(language_multilingual(), 'Site is mono-lingual');
+ $this->container->get('language_manager')->reset();
+ $this->assertFalse(\Drupal::languageManager()->isMultilingual(), 'Site is mono-lingual');
$this->assertEqual(language_default()->id, 'fr', 'French is the default language');
// Set language detection to URL.
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageTestBase.php b/core/modules/language/lib/Drupal/language/Tests/LanguageTestBase.php
new file mode 100644
index 00000000000..70a512204f8
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageTestBase.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageTestBase.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Test for dependency injected language object.
+ */
+abstract class LanguageTestBase extends DrupalUnitTestBase {
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * The state storage service.
+ *
+ * @var \Drupal\Core\KeyValueStore\StateInterface
+ */
+ protected $state;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->enableModules(array('system', 'language', 'language_test'));
+ $this->installSchema('system', array('variable'));
+ $this->installConfig(array('language'));
+
+ $this->state = $this->container->get('state');
+
+ // Ensure we are building a new Language object for each test.
+ $this->languageManager = $this->container->get('language_manager');
+ $this->languageManager->reset();
+ }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index 7c037b5f641..e8b3b2661f9 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -7,9 +7,15 @@
namespace Drupal\language\Tests;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
+use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
+use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Language\Language;
use Symfony\Component\HttpFoundation\Request;
+use Drupal\language\LanguageNegotiatorInterface;
/**
* Test UI language negotiation
@@ -48,12 +54,12 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
*
* @var array
*/
- public static $modules = array('locale', 'language_test', 'block');
+ public static $modules = array('locale', 'language_test', 'block', 'user');
public static function getInfo() {
return array(
'name' => 'UI language negotiation',
- 'description' => 'Test UI language switching by URL path prefix and domain.',
+ 'description' => 'Test UI language switching.',
'group' => 'Language',
);
}
@@ -64,7 +70,6 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$this->request = Request::create('http://example.com/');
$this->container->set('request', $this->request);
- require_once DRUPAL_ROOT . '/core/includes/language.inc';
$admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));
$this->drupalLogin($admin_user);
}
@@ -106,7 +111,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
// into database when seen by t(). Without doing this, our target string
// is for some reason not found when doing translate search. This might
// be some bug.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
$languages = language_list();
variable_set('language_default', (array) $languages['vi']);
// First visit this page to make sure our target string is searchable.
@@ -142,17 +147,14 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
);
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Save translations'));
- // Configure URL language rewrite.
- variable_set('language_negotiation_url_type', Language::TYPE_INTERFACE);
-
// Configure selected language negotiation to use zh-hans.
$edit = array('selected_langcode' => $langcode);
$this->drupalPostForm('admin/config/regional/language/detection/selected', $edit, t('Save configuration'));
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiationSelected::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED: UI language is switched based on selected language.',
);
@@ -161,10 +163,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
// An invalid language is selected.
\Drupal::config('language.negotiation')->set('selected_langcode', NULL)->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
);
@@ -173,10 +175,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
// No selected language is available.
\Drupal::config('language.negotiation')->set('selected_langcode', $langcode_unknown)->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'SELECTED > DEFAULT: UI language is switched based on selected language.',
);
@@ -185,46 +187,46 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$tests = array(
// Default, browser preference should have no influence.
array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
),
// Language prefix.
array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => "$langcode/admin/config",
'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+ 'expected_method_id' => LanguageNegotiationUrl::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
),
// Default, go by browser preference.
array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
+ 'language_negotiation' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationBrowser::METHOD_ID),
'path' => 'admin/config',
'expect' => $language_browser_fallback_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_BROWSER,
+ 'expected_method_id' => LanguageNegotiationBrowser::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
),
// Prefix, switch to the language.
array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
+ 'language_negotiation' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationBrowser::METHOD_ID),
'path' => "$langcode/admin/config",
'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+ 'expected_method_id' => LanguageNegotiationUrl::METHOD_ID,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: with language prefix, UI language is based on path prefix',
),
// Default, browser language preference is not one of site's lang.
array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUrl::METHOD_ID, LanguageNegotiationBrowser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => $http_header_blah,
'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
),
@@ -235,7 +237,8 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
}
// Unknown language prefix should return 404.
- variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_language_negotiation_info());
+ $definitions = \Drupal::languageManager()->getNegotiator()->getNegotiationMethods();
+ variable_set('language_negotiation_' . Language::TYPE_INTERFACE, array_flip(array_keys($definitions)));
$this->drupalGet("$langcode_unknown/admin/config", array(), $http_header_browser_fallback);
$this->assertResponse(404, "Unknown language path prefix should return 404");
@@ -245,10 +248,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: no preferred user language setting, the UI language is default',
);
@@ -260,10 +263,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: invalid preferred user language setting, the UI language is default',
);
@@ -274,10 +277,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUser::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_USER,
+ 'expected_method_id' => LanguageNegotiationUser::METHOD_ID,
'http_header' => array(),
'message' => 'USER > DEFAULT: defined prefereed user language setting, the UI language is based on user setting',
);
@@ -288,10 +291,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: no preferred user admin language setting, the UI language is default',
);
@@ -302,10 +305,10 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
+ 'expected_method_id' => LanguageNegotiatorInterface::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: invalid preferred user admin language setting, the UI language is default',
);
@@ -316,56 +319,20 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$account->save();
$test = array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_USER_ADMIN, LANGUAGE_NEGOTIATION_SELECTED),
+ 'language_negotiation' => array(LanguageNegotiationUserAdmin::METHOD_ID, LanguageNegotiationSelected::METHOD_ID),
'path' => 'admin/config',
'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_USER_ADMIN,
+ 'expected_method_id' => LanguageNegotiationUserAdmin::METHOD_ID,
'http_header' => array(),
'message' => 'USER ADMIN > DEFAULT: defined prefereed user admin language setting, the UI language is based on user setting',
);
$this->runTest($test);
-
- // Setup for domain negotiation, first configure the language to have domain
- // URL.
- $edit = array("domain[$langcode]" => $language_domain);
- $this->drupalPostForm("admin/config/regional/language/detection/url", $edit, t('Save configuration'));
- // Set the site to use domain language negotiation.
-
- $tests = array(
- // Default domain, browser preference should have no influence.
- array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
- 'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
- 'path' => 'admin/config',
- 'expect' => $default_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_SELECTED,
- 'http_header' => $http_header_browser_fallback,
- 'message' => 'URL (DOMAIN) > DEFAULT: default domain should get default language',
- ),
- // Language domain specific URL, we set the 'HTTP_HOST' property of
- // \Drupal::request()->server in \Drupal\language_test\LanguageTestManager
- // to simulate this.
- array(
- 'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
- 'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
- 'language_test_domain' => $language_domain . ':88',
- 'path' => 'admin/config',
- 'expect' => $language_string,
- 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
- 'http_header' => $http_header_browser_fallback,
- 'message' => 'URL (DOMAIN) > DEFAULT: domain example.cn should switch to Chinese',
- ),
- );
-
- foreach ($tests as $test) {
- $this->runTest($test);
- }
}
protected function runTest($test) {
if (!empty($test['language_negotiation'])) {
$method_weights = array_flip($test['language_negotiation']);
- language_negotiation_set(Language::TYPE_INTERFACE, $method_weights);
+ $this->container->get('language_negotiator')->saveConfiguration(Language::TYPE_INTERFACE, $method_weights);
}
if (!empty($test['language_negotiation_url_part'])) {
\Drupal::config('language.negotiation')
@@ -449,7 +416,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
// Change the domain for the Italian language.
$edit = array(
- 'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
+ 'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
'domain[it]' => 'it.example.com',
);
$this->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
index 07ee9a9762f..847348e9b91 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
@@ -7,6 +7,7 @@
namespace Drupal\language\Tests;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Drupal\simpletest\WebTestBase;
use Symfony\Component\HttpFoundation\Request;
@@ -46,8 +47,6 @@ class LanguageUrlRewritingTest extends WebTestBase {
$edit = array('language_interface[enabled][language-url]' => 1);
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
- // Reset static caching.
- drupal_static_reset('language_list');
}
/**
@@ -105,7 +104,7 @@ class LanguageUrlRewritingTest extends WebTestBase {
function testDomainNameNegotiationPort() {
$language_domain = 'example.fr';
$edit = array(
- 'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
+ 'language_negotiation_url_part' => LanguageNegotiationUrl::CONFIG_DOMAIN,
'domain[fr]' => $language_domain
);
$this->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
@@ -115,11 +114,11 @@ class LanguageUrlRewritingTest extends WebTestBase {
// Enable domain configuration.
\Drupal::config('language.negotiation')
- ->set('url.source', LANGUAGE_NEGOTIATION_URL_DOMAIN)
+ ->set('url.source', LanguageNegotiationUrl::CONFIG_DOMAIN)
->save();
// Reset static caching.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
// In case index.php is part of the URLs, we need to adapt the asserted
// URLs as well.
diff --git a/core/modules/language/tests/Drupal/language/Tests/LanguageNegotiationUrlTest.php b/core/modules/language/tests/Drupal/language/Tests/LanguageNegotiationUrlTest.php
new file mode 100644
index 00000000000..48a39a155fd
--- /dev/null
+++ b/core/modules/language/tests/Drupal/language/Tests/LanguageNegotiationUrlTest.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Tests\LanguageNegotiationUrlTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\Core\Session\UserSession;
+use Drupal\Tests\UnitTestCase;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Tests the URL and domain language negotiation.
+ *
+ * @group Language
+ *
+ * @see \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl
+ */
+class LanguageNegotiationUrlTest extends UnitTestCase {
+
+ protected $languageManager;
+ protected $user;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Language negotiation URL',
+ 'description' => 'Tests the URL/domain Language negotiation plugin',
+ 'group' => 'Language',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+
+ // Set up some languages to be used by the language-based path processor.
+ $languages = array(
+ 'de' => (object) array(
+ 'id' => 'de',
+ ),
+ 'en' => (object) array(
+ 'id' => 'en',
+ ),
+ );
+
+ // Create a language manager stub.
+ $language_manager = $this->getMockBuilder('Drupal\language\ConfigurableLanguageManagerInterface')
+ ->getMock();
+ $language_manager->expects($this->any())
+ ->method('getCurrentLanguage')
+ ->will($this->returnValue($languages['en']));
+ $language_manager->expects($this->any())
+ ->method('getLanguages')
+ ->will($this->returnValue($languages));
+ $this->languageManager = $language_manager;
+
+ // Create a user stub.
+ $this->user = $this->getMockBuilder('Drupal\Core\Session\AccountInterface')
+ ->getMock();
+ }
+
+ /**
+ * Test domain language negotiation.
+ *
+ * @dataProvider providerTestDomain
+ */
+ public function testDomain($http_host, $domains, $expected_langcode) {
+ $config_data = array(
+ 'source' => LanguageNegotiationUrl::CONFIG_DOMAIN,
+ 'domains' => $domains,
+ );
+
+ $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $config_object->expects($this->any())
+ ->method('get')
+ ->with('url')
+ ->will($this->returnValue($config_data));
+
+ $config = $this->getMockBuilder('Drupal\Core\Config\ConfigFactory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $config->expects($this->any())
+ ->method('get')
+ ->with('language.negotiation')
+ ->will($this->returnValue($config_object));
+
+ $request = Request::create('', 'GET', array(), array(), array(), array('HTTP_HOST' => $http_host));
+ $method = new LanguageNegotiationUrl();
+ $method->setLanguageManager($this->languageManager);
+ $method->setConfig($config);
+ $method->setCurrentUser($this->user);
+ $this->assertEquals($expected_langcode, $method->getLangcode($request));
+ }
+
+ /**
+ * Provides data for the domain test.
+ *
+ * @return array
+ * An array of data for checking domain negotation.
+ */
+ public function providerTestDomain() {
+
+ $domain_configuration[] = array(
+ 'http_host' => 'example.de',
+ 'domains' => array(
+ 'de' => 'http://example.de',
+ ),
+ 'expected_langocde' => 'de',
+ );
+ // No configuration.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.de',
+ 'domains' => array(),
+ 'expected_langocde' => FALSE,
+ );
+ // HTTP host with a port.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.de:8080',
+ 'domains' => array(
+ 'de' => 'http://example.de',
+ ),
+ 'expected_langocde' => 'de',
+ );
+ // Domain configuration with https://.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.de',
+ 'domains' => array(
+ 'de' => 'https://example.de',
+ ),
+ 'expected_langocde' => 'de',
+ );
+ // Non-matching HTTP host.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.com',
+ 'domains' => array(
+ 'de' => 'http://example.com',
+ ),
+ 'expected_langocde' => 'de',
+ );
+ // Testing a non-existing language.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.com',
+ 'domains' => array(
+ 'it' => 'http://example.it',
+ ),
+ 'expected_langocde' => FALSE,
+ );
+ // Multiple domain configurations.
+ $domain_configuration[] = array(
+ 'http_host' => 'example.com',
+ 'domains' => array(
+ 'de' => 'http://example.de',
+ 'en' => 'http://example.com',
+ ),
+ 'expected_langocde' => 'en',
+ );
+ return $domain_configuration;
+ }
+}
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index 31c0a848f65..38171374a7c 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -5,10 +5,8 @@
* Mock module for language layer tests.
*/
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-
use Drupal\Core\Language\Language;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
/**
* Implements hook_page_build().
@@ -47,47 +45,20 @@ function language_test_language_types_info_alter(array &$language_types) {
unset($language_types[Language::TYPE_CONTENT]['fixed']);
// By default languages are not configurable. Make Language::TYPE_CONTENT
// configurable.
- $configurable = \Drupal::config('system.language.types')->get('configurable');
+ $configurable = \Drupal::config('language.types')->get('configurable');
if (!in_array(Language::TYPE_CONTENT, $configurable)) {
$configurable[] = Language::TYPE_CONTENT;
- \Drupal::config('system.language.types')->set('configurable', $configurable)->save();
+ \Drupal::config('language.types')->set('configurable', $configurable)->save();
}
}
}
/**
- * Implements hook_language_negotiation_info().
- */
-function language_test_language_negotiation_info() {
- if (\Drupal::state()->get('language_test.language_negotiation_info')) {
- $info = array(
- 'callbacks' => array(
- 'negotiation' => 'language_test_language_negotiation_method',
- ),
- 'file' => drupal_get_path('module', 'language_test') .'/language_test.module',
- 'weight' => -10,
- 'description' => t('This is a test language negotiation method.'),
- );
-
- return array(
- 'test_language_negotiation_method' => array(
- 'name' => t('Test'),
- 'types' => array(Language::TYPE_CONTENT, 'test_language_type', 'fixed_test_language_type'),
- ) + $info,
- 'test_language_negotiation_method_ts' => array(
- 'name' => t('Type-specific test'),
- 'types' => array('test_language_type'),
- ) + $info,
- );
- }
-}
-
-/**
* Implements hook_language_negotiation_info_alter().
*/
function language_test_language_negotiation_info_alter(array &$negotiation_info) {
if (\Drupal::state()->get('language_test.language_negotiation_info_alter')) {
- unset($negotiation_info[LANGUAGE_NEGOTIATION_INTERFACE]);
+ unset($negotiation_info[LanguageNegotiationUI::METHOD_ID]);
}
}
@@ -95,19 +66,13 @@ function language_test_language_negotiation_info_alter(array &$negotiation_info)
* Store the last negotiated languages.
*/
function language_test_store_language_negotiation() {
- $last = array();
- print_r(language_types_get_all());
- foreach (language_types_get_all() as $type) {
- $last[$type] = language($type)->id;
+ if (\Drupal::moduleHandler()->moduleExists('language')) {
+ $last = array();
+ foreach (\Drupal::languageManager()->getDefinedLanguageTypes() as $type) {
+ $last[$type] = \Drupal::languageManager()->getCurrentLanguage($type)->id;
+ }
+ \Drupal::state()->set('language_test.language_negotiation_last', $last);
}
- \Drupal::state()->set('language_test.language_negotiation_last', $last);
-}
-
-/**
- * Provides a test language negotiation method.
- */
-function language_test_language_negotiation_method($languages) {
- return 'it';
}
/**
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestManager.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestManager.php
deleted file mode 100644
index 3c460b658a0..00000000000
--- a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestManager.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\language_test\LanguageTestManager.
- */
-
-namespace Drupal\language_test;
-
-use Drupal\Core\Language\LanguageManager;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Defines a LanguageManager service to test URL negotiation.
- */
-class LanguageTestManager extends LanguageManager {
-
- /**
- * Overrides \Drupal\Core\Language\LanguageManager::init().
- */
- public function init() {
- if ($test_domain = \Drupal::state()->get('language_test.domain')) {
- \Drupal::request()->server->set('HTTP_HOST', $test_domain);
- }
- return parent::init();
- }
-
-}
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestServiceProvider.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestServiceProvider.php
deleted file mode 100644
index 39aef04470d..00000000000
--- a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestServiceProvider.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\language_test\LanguageTestServiceProvider.
- */
-
-namespace Drupal\language_test;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\DependencyInjection\ServiceModifierInterface;
-
-/**
- * Defines the LanguageTest service provider.
- */
-class LanguageTestServiceProvider implements ServiceModifierInterface {
-
- /**
- * {@inheritdoc}
- */
- public function alter(ContainerBuilder $container) {
- // Overrides language_manager class to test domain language negotiation.
- $definition = $container->getDefinition('language_manager');
- $definition->setClass('Drupal\language_test\LanguageTestManager');
- }
-
-}
-
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTest.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTest.php
new file mode 100644
index 00000000000..a726c5cf585
--- /dev/null
+++ b/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTest.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language_test\\Plugin\LanguageNegotiation\LanguageNegotiationTest.
+ */
+
+namespace Drupal\language_test\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language from a selected language.
+ *
+ * @Plugin(
+ * id = "test_language_negotiation_method",
+ * weight = -10,
+ * name = @Translation("Test"),
+ * description = @Translation("This is a test language negotiation method."),
+ * types = {Drupal\Core\Language\Language::TYPE_CONTENT, "test_language_type", "fixed_test_language_type"}
+ * )
+ */
+class LanguageNegotiationTest extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'test_language_negotiation_method';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ return 'it';
+ }
+
+}
diff --git a/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTestTs.php b/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTestTs.php
new file mode 100644
index 00000000000..cef125c804b
--- /dev/null
+++ b/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTestTs.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language_test\\Plugin\LanguageNegotiation\LanguageNegotiationTestTs.
+ */
+
+namespace Drupal\language_test\Plugin\LanguageNegotiation;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language from a selected language.
+ *
+ * @Plugin(
+ * id = "test_language_negotiation_method_ts",
+ * weight = -10,
+ * name = @Translation("Type-specific test"),
+ * description = @Translation("This is a test language negotiation method."),
+ * types = {"test_language_type"}
+ * )
+ */
+class LanguageNegotiationTestTs extends LanguageNegotiationTest {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'test_language_negotiation_method_ts';
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php b/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php
index 34c93bede91..d6e4b0963f1 100644
--- a/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php
+++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php
@@ -29,7 +29,7 @@ class TranslateEditForm extends TranslateFormBase {
$filter_values = $this->translateFilterValues();
$langcode = $filter_values['langcode'];
- drupal_static_reset('language_list');
+ $this->languageManager->reset();
$languages = language_list();
$langname = isset($langcode) ? $languages[$langcode]->name : "- None -";
diff --git a/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php b/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php
index ea4c9ce052d..c5447e02f4f 100644
--- a/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php
+++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php
@@ -161,7 +161,7 @@ abstract class TranslateFormBase extends FormBase {
$filters = array();
// Get all languages, except English.
- drupal_static_reset('language_list');
+ $this->languageManager->reset();
$languages = language_list();
$language_options = array();
foreach ($languages as $langcode => $language) {
@@ -171,7 +171,7 @@ abstract class TranslateFormBase extends FormBase {
}
// Pick the current interface language code for the filter.
- $default_langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $default_langcode = $this->languageManager->getCurrentLanguage()->id;
if (!isset($language_options[$default_langcode])) {
$available_langcodes = array_keys($language_options);
$default_langcode = array_shift($available_langcodes);
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
index 87febe49f26..1c2c5972758 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
@@ -47,7 +47,6 @@ class LocaleContentTest extends WebTestBase {
$edit = array();
$edit['predefined_langcode'] = 'ar';
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
- drupal_static_reset('language_list');
$edit = array(
'site_default_language' => 'ar',
@@ -84,7 +83,6 @@ class LocaleContentTest extends WebTestBase {
'direction' => '0',
);
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
- drupal_static_reset('language_list');
// Set the content type to use multilingual support.
$this->drupalGet("admin/structure/types/manage/{$type2->type}");
@@ -95,7 +93,7 @@ class LocaleContentTest extends WebTestBase {
$this->drupalPostForm("admin/structure/types/manage/{$type2->type}", $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => $type2->name)));
$this->drupalLogout();
- drupal_static_reset('language_list');
+ \Drupal::languageManager()->reset();
// Verify language selection is not present on the node add form.
$this->drupalLogin($web_user);
@@ -152,13 +150,12 @@ class LocaleContentTest extends WebTestBase {
$edit = array();
$edit['predefined_langcode'] = 'ar';
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
- drupal_static_reset('language_list');
+ \Drupal::languageManager()->reset();
// Install Spanish language.
$edit = array();
$edit['predefined_langcode'] = 'es';
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
- drupal_static_reset('language_list');
// Set the content type to use multilingual support.
$this->drupalGet("admin/structure/types/manage/{$type->type}");
@@ -222,7 +219,6 @@ class LocaleContentTest extends WebTestBase {
// Enable multiple languages.
$this->drupalPostForm('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language'));
$this->drupalPostForm('admin/config/regional/language/add', array('predefined_langcode' => 'zh-hant'), t('Add language'));
- drupal_static_reset('language_list');
// Create two nodes: English and Chinese.
$node_en = $this->drupalCreateNode(array('langcode' => 'en'));
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php
index 5c67d4ea449..91e4c8146cd 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php
@@ -224,7 +224,7 @@ class LocaleTranslationUiTest extends WebTestBase {
'direction' => '0',
);
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
// Build the JavaScript translation file.
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index cd8ec733c60..989ac42907b 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -7,9 +7,13 @@
namespace Drupal\locale\Tests;
-use Drupal\simpletest\WebTestBase;
-use Drupal\Core\Language\Language;
use Drupal\Component\Utility\String;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
+use Drupal\simpletest\WebTestBase;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Locale uninstall with English UI functional test.
@@ -90,14 +94,18 @@ class LocaleUninstallTest extends WebTestBase {
// Change language negotiation options.
drupal_load('module', 'locale');
- \Drupal::config('system.language.types')->set('configurable', language_types_get_default() + array('language_custom' => TRUE))->save();
- variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_language_negotiation_info());
- variable_set('language_negotiation_' . Language::TYPE_CONTENT, language_language_negotiation_info());
- variable_set('language_negotiation_' . Language::TYPE_URL, language_language_negotiation_info());
+ // Pick only core language types.
+ $language_manager = new LanguageManager();
+ $default_types = $language_manager->getLanguageTypes();
+ \Drupal::config('language.types')->set('configurable', $default_types + array('language_custom' => TRUE))->save();
+ $config = array_flip(array_keys(\Drupal::service('plugin.manager.language_negotiation_method')->getDefinitions()));
+ variable_set('language_negotiation_' . Language::TYPE_INTERFACE, $config);
+ variable_set('language_negotiation_' . Language::TYPE_CONTENT, $config);
+ variable_set('language_negotiation_' . Language::TYPE_URL, $config);
// Change language negotiation settings.
\Drupal::config('language.negotiation')
- ->set('url.source', LANGUAGE_NEGOTIATION_URL_PREFIX)
+ ->set('url.source', LanguageNegotiationUrl::CONFIG_PATH_PREFIX)
->set('session.parameter', TRUE)
->save();
@@ -113,19 +121,16 @@ class LocaleUninstallTest extends WebTestBase {
// Check JavaScript files deletion.
$this->assertTrue($result = !file_exists($js_file), String::format('JavaScript file deleted: %file', array('%file' => $result ? $js_file : 'found')));
- // Check language count.
- $language_count = $this->container->get('state')->get('language_count') ?: 1;
- $this->assertEqual($language_count, 1, String::format('Language count: %count', array('%count' => $language_count)));
-
// Check language negotiation.
- require_once DRUPAL_ROOT . '/core/includes/language.inc';
- $this->assertTrue(count(language_types_get_all()) == count(language_types_get_default()), 'Language types reset');
- $language_negotiation = language_negotiation_method_get_first(Language::TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_SELECTED;
- $this->assertTrue($language_negotiation, String::format('Interface language negotiation: %setting', array('%setting' => $language_negotiation ? 'none' : 'set')));
- $language_negotiation = language_negotiation_method_get_first(Language::TYPE_CONTENT) == LANGUAGE_NEGOTIATION_SELECTED;
- $this->assertTrue($language_negotiation, String::format('Content language negotiation: %setting', array('%setting' => $language_negotiation ? 'none' : 'set')));
- $language_negotiation = language_negotiation_method_get_first(Language::TYPE_URL) == LANGUAGE_NEGOTIATION_SELECTED;
- $this->assertTrue($language_negotiation, String::format('URL language negotiation: %setting', array('%setting' => $language_negotiation ? 'none' : 'set')));
+ try {
+ $message = 'Language negotiation is not available.';
+ $this->assertTrue(count($this->container->get('language_manager')->getLanguageTypes()) == count($default_types), 'Language types reset');
+ \Drupal::service('language_negotiator');
+ $this->fail($message);
+ }
+ catch (InvalidArgumentException $e) {
+ $this->pass($message);
+ }
// Check language negotiation method settings.
$this->assertFalse(\Drupal::config('language.negotiation')->get('url.source'), 'URL language negotiation method indicator settings cleared.');
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php
index 64e93331981..8ae5a8ed18a 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php
@@ -80,7 +80,7 @@ class LocaleUpdateBase extends WebTestBase {
protected function addLanguage($langcode) {
$edit = array('predefined_langcode' => $langcode);
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
$this->assertTrue(language_load($langcode), String::format('Language %langcode added.', array('%langcode' => $langcode)));
}
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index 52562443298..eb0dfe495ce 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -21,7 +21,7 @@ use Drupal\file\FileInterface;
* @deprecated Use \Drupal\locale\Form\LocaleForm::import()
*/
function locale_translate_import_form($form, &$form_state) {
- drupal_static_reset('language_list');
+ Drupal::languageManager()->reset();
$languages = language_list();
// Initialize a language list to the ones available, including English if we
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 960381c8670..708fe6a7704 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -6,6 +6,7 @@
*/
use Drupal\Core\Language\Language;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
/**
* Implements hook_install().
@@ -500,20 +501,10 @@ function locale_update_8004() {
$types = update_variable_get('language_types', NULL);
if (!empty($types)) {
foreach ($types as $type => $configurable) {
- // Rename the negotiation and language switch callback keys.
+ // Change the structure of the language negotiation configuration.
$negotiation = update_variable_get('language_negotiation_' . $type, NULL);
if (!empty($negotiation)) {
- foreach ($negotiation as &$method) {
- if (isset($method['callbacks']['language'])) {
- $method['callbacks']['negotiation'] = $method['callbacks']['language'];
- unset($method['callbacks']['language']);
- }
- if (isset($method['callbacks']['switcher'])) {
- $method['callbacks']['language_switch'] = $method['callbacks']['switcher'];
- unset($method['callbacks']['switcher']);
- }
- }
- update_variable_set('language_negotiation_' . $type, $negotiation);
+ update_variable_set('language_negotiation_' . $type, array_keys($negotiation));
}
// Rename the language negotiation methods weight variable.
@@ -646,16 +637,11 @@ function locale_update_8005() {
}
/**
- * Convert language_negotiation_* variables to use the new callbacks.
+ * Convert language_negotiation_* variables.
*
* @ingroup config_upgrade
*/
function locale_update_8007() {
- $variable_names = array(
- 'language_negotiation_language_interface',
- 'language_negotiation_language_content',
- 'language_negotiation_language_url',
- );
// Add all language type weight variables. As the function language_types()
// is not available its functionality is rebuild.
$language_types = update_variable_get('language_types', array(
@@ -664,20 +650,9 @@ function locale_update_8007() {
Language::TYPE_URL => FALSE,
));
foreach ($language_types as $language_type => $configurable) {
- $variable_names[] = 'language_negotiation_methods_weight_' . $language_type;
+ $variable_names['language_negotiation_' . $language_type] = 'language_negotiation_methods_weight_' . $language_type;
}
- $callback_map = array(
- 'locale_language_from_url' => 'language_from_url',
- 'locale_language_switcher_url' => 'language_switcher_url',
- 'locale_language_url_rewrite_url' => 'language_url_rewrite_url',
- 'locale_language_from_session' => 'language_from_session',
- 'locale_language_switcher_session' => 'language_switcher_session',
- 'locale_language_url_rewrite_session' => 'language_url_rewrite_session',
- 'locale_language_from_user' => 'language_from_user',
- 'locale_language_from_browser' => 'language_from_browser',
- 'locale_language_url_fallback' => 'language_url_fallback',
- 'locale_language_from_interface' => 'language_from_interface',
- );
+
$type_map = array(
'locale-interface' => 'language-interface',
'locale-url' => 'language-url',
@@ -686,37 +661,24 @@ function locale_update_8007() {
'locale-user' => 'language-user',
'locale-session' => 'language-session',
);
- foreach ($variable_names as $variable_name) {
- $value = update_variable_get($variable_name);
+ foreach ($variable_names as $variable_name => $weight_variable_name) {
+ $value = update_variable_get($weight_variable_name);
// Skip processing if the variable is not stored in the db.
if ($value === NULL) {
+ update_variable_del($variable_name);
continue;
}
- $new_value = $value;
- foreach ($value as $type => $type_settings) {
- // Convert the file.
- if (isset($type_settings['file']) && (strpos($type_settings['file'], 'core/includes/locale.inc') !== FALSE)) {
- $new_value[$type]['file'] = 'core/modules/language/language.negotiation.inc';
- }
- // Convert the callbacks.
- if (is_array($type_settings) && isset($type_settings['callbacks'])) {
- foreach ($type_settings['callbacks'] as $key => $callback) {
- if (isset($callback_map[$callback])) {
- $new_value[$type]['callbacks'][$key] = $callback_map[$callback];
- }
- }
- }
+ $new_value = array();
+ foreach ($value as $type => $weight) {
// Convert the type.
if (isset($type_map[$type])) {
- $new_value[$type_map[$type]] = $new_value[$type];
- unset($new_value[$type]);
+ $type = $type_map[$type];
}
+ $new_value[$type] = $weight;
}
- // If necessary maintain the order of the values / keys of the variable.
- if (stristr($variable_name, 'language_negotiation_methods_weight_') !== FALSE) {
- asort($new_value);
- }
+ asort($new_value);
update_variable_set($variable_name, $new_value);
+ update_variable_del($weight_variable_name);
}
}
@@ -845,25 +807,11 @@ function locale_update_8011() {
* Renames language_default language negotiation method to language_selected.
*/
function locale_update_8013() {
- // @todo We only need language.inc here because LANGUAGE_NEGOTIATION_SELECTED
- // is defined there. Remove this line once that has been converted to a class
- // constant.
- require_once DRUPAL_ROOT . '/core/includes/language.inc';
- $weight = update_variable_get('language_negotiation_methods_weight_language_interface', NULL);
+ $weight = update_variable_get('language_negotiation_language_interface', NULL);
if ($weight !== NULL) {
- $weight[LANGUAGE_NEGOTIATION_SELECTED] = $weight['language-default'];
+ $weight[LanguageNegotiationSelected::METHOD_ID] = $weight['language-default'];
unset($weight['language-default']);
- update_variable_set('language_negotiation_methods_weight_language_interface', $weight);
- }
-
- $negotiation_interface = update_variable_get('language_negotiation_language_interface', NULL);
- if ($negotiation_interface !== NULL) {
- if (isset($negotiation_interface['language-default'])) {
- $negotiation_interface[LANGUAGE_NEGOTIATION_SELECTED] = $negotiation_interface['language-default'];
- $negotiation_interface[LANGUAGE_NEGOTIATION_SELECTED]['callbacks']['negotiation'] = 'language_from_selected';
- unset($negotiation_interface['language-default']);
- update_variable_set('language_negotiation_language_interface', $negotiation_interface);
- }
+ update_variable_set('language_negotiation_language_interface', $weight);
}
}
diff --git a/core/modules/node/lib/Drupal/node/Controller/NodeController.php b/core/modules/node/lib/Drupal/node/Controller/NodeController.php
index a60696ccbb1..126332f8302 100644
--- a/core/modules/node/lib/Drupal/node/Controller/NodeController.php
+++ b/core/modules/node/lib/Drupal/node/Controller/NodeController.php
@@ -69,7 +69,7 @@ class NodeController extends ControllerBase {
'uid' => $account->id(),
'name' => $account->getUsername() ?: '',
'type' => $node_type->type,
- 'langcode' => $langcode ? $langcode : $this->languageManager()->getLanguage()->id,
+ 'langcode' => $langcode ? $langcode : $this->languageManager()->getCurrentLanguage()->id,
));
$form = $this->entityManager()->getForm($node);
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index c22dbeda599..90d4fac4b9a 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -199,7 +199,7 @@ class Node extends ContentEntityBase implements NodeInterface {
// Load languages the node exists in.
$node_translations = $this->getTranslationLanguages();
// Load the language from content negotiation.
- $content_negotiation_langcode = \Drupal::languageManager()->getLanguage(Language::TYPE_CONTENT)->id;
+ $content_negotiation_langcode = \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT)->id;
// If there is a translation available, use it.
if (isset($node_translations[$content_negotiation_langcode])) {
$langcode = $content_negotiation_langcode;
diff --git a/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php b/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
index 9efe421941c..c9b54c50c96 100644
--- a/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
+++ b/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
@@ -159,7 +159,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
$subquery->condition('na.grant_' . $op, 1, '>=');
// Add langcode-based filtering if this is a multilingual site.
- if (language_multilingual()) {
+ if (\Drupal::languageManager()->isMultilingual()) {
// If no specific langcode to check for is given, use the grant entry
// which is set as a fallback.
// If a specific langcode is given, use the grant entry for it.
diff --git a/core/modules/node/lib/Drupal/node/NodeListController.php b/core/modules/node/lib/Drupal/node/NodeListController.php
index 8d488ca015f..b9582ae05e4 100644
--- a/core/modules/node/lib/Drupal/node/NodeListController.php
+++ b/core/modules/node/lib/Drupal/node/NodeListController.php
@@ -81,7 +81,7 @@ class NodeListController extends EntityListController {
'class' => array(RESPONSIVE_PRIORITY_LOW),
),
);
- if (language_multilingual()) {
+ if (\Drupal::languageManager()->isMultilingual()) {
$header['language_name'] = array(
'data' => $this->t('Language'),
'class' => array(RESPONSIVE_PRIORITY_LOW),
@@ -114,8 +114,9 @@ class NodeListController extends EntityListController {
);
$row['status'] = $entity->isPublished() ? $this->t('published') : $this->t('not published');
$row['changed'] = $this->dateService->format($entity->getChangedTime(), 'short');
- if (language_multilingual()) {
- $row['language_name'] = language_name($langcode);
+ $language_manager = \Drupal::languageManager();
+ if ($language_manager->isMultilingual()) {
+ $row['language_name'] = $language_manager->getLanguageName($langcode);
}
$row['operations']['data'] = $this->buildOperations($entity);
return $row + parent::buildRow($entity);
diff --git a/core/modules/node/lib/Drupal/node/NodeViewBuilder.php b/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
index eda9b4c8126..fcaeaede7e9 100644
--- a/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
+++ b/core/modules/node/lib/Drupal/node/NodeViewBuilder.php
@@ -50,7 +50,7 @@ class NodeViewBuilder extends EntityViewBuilder {
$entity->content['langcode'] = array(
'#type' => 'item',
'#title' => t('Language'),
- '#markup' => language_name($langcode),
+ '#markup' => $this->languageManager->getLanguageName($langcode),
'#prefix' => '<div id="field-language-display">',
'#suffix' => '</div>'
);
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
index f53518225ca..67b34e7c4f7 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
@@ -7,6 +7,7 @@
namespace Drupal\node\Tests;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Language\Language;
@@ -99,7 +100,7 @@ class NodeFieldMultilingualTestCase extends WebTestBase {
$this->assertTrue($node->language()->id == $langcode && $node->body->value == $body_value, 'Field language correctly changed.');
// Enable content language URL detection.
- language_negotiation_set(Language::TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0));
+ $this->container->get('language_negotiator')->saveConfiguration(Language::TYPE_CONTENT, array(LanguageNegotiationUrl::METHOD_ID => 0));
// Test multilingual field language fallback logic.
$this->drupalGet("it/node/{$node->id()}");
diff --git a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
index 4f94f43cceb..065374316bf 100644
--- a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
+++ b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
@@ -104,7 +104,7 @@ class PathLanguageTest extends PathTestBase {
$this->container->get('path.alias_manager')->cacheClear();
// Languages are cached on many levels, and we need to clear those caches.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
$this->rebuildContainer();
$languages = language_list();
@@ -117,7 +117,10 @@ class PathLanguageTest extends PathTestBase {
$this->drupalGet('fr/' . $edit['path[alias]']);
$this->assertText($french_node->body->value, 'Alias for French translation works.');
- // Confirm that the alias is returned by url().
+ // Confirm that the alias is returned by url(). Languages are cached on
+ // many levels, and we need to clear those caches.
+ $this->container->get('language_manager')->reset();
+ $languages = language_list();
$url = $this->container->get('url_generator')->generateFromPath('node/' . $french_node->id(), array('language' => $languages['fr']));
$this->assertTrue(strpos($url, $edit['path[alias]']), 'URL contains the path alias.');
diff --git a/core/modules/path/path.admin.inc b/core/modules/path/path.admin.inc
index b2941a0328c..65742080516 100644
--- a/core/modules/path/path.admin.inc
+++ b/core/modules/path/path.admin.inc
@@ -57,7 +57,7 @@ function path_admin_overview($keys = NULL) {
'attributes' => array('title' => $data->source),
));
if ($multilanguage) {
- $row['data']['language_name'] = language_name($data->langcode);
+ $row['data']['language_name'] = \Drupal::languageManager()->getLanguageName($data->langcode);
}
$operations = array();
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 560afb1ec15..669c6150b81 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -20,6 +20,7 @@ use Drupal\Core\Language\Language;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Utility\Error;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\DependencyInjection\Reference;
/**
* Base class for Drupal tests.
@@ -969,8 +970,11 @@ abstract class TestBase {
// Reset and create a new service container.
$this->container = new ContainerBuilder();
- // @todo Remove this once this class has no calls to t() and format_plural()
- $this->container->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager');
+
+ // @todo Remove this once this class has no calls to t() and format_plural()
+ $this->container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
+ $this->container->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
+ ->addArgument(new Reference('language_manager'));
// Register info parser.
$this->container->register('info_parser', 'Drupal\Core\Extension\InfoParser');
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index 9d585f08da9..9acf83dbc26 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -175,23 +175,6 @@ system.filter:
- type: string
label: 'Protocol'
-system.language.types:
- type: mapping
- label: 'Language types'
- mapping:
- all:
- type: sequence
- label: 'All language types'
- sequence:
- - type: string
- label: 'Language type'
- configurable:
- type: sequence
- label: 'Configurable language types'
- sequence:
- - type: string
- label: 'Language type'
-
system.logging:
type: mapping
label: 'Logging settings'
diff --git a/core/modules/system/language.api.php b/core/modules/system/language.api.php
index baafb7ae7ab..8684406741e 100644
--- a/core/modules/system/language.api.php
+++ b/core/modules/system/language.api.php
@@ -35,123 +35,6 @@ function hook_language_switch_links_alter(array &$links, $type, $path) {
}
/**
- * Define language types.
- *
- * @return
- * An associative array of language type definitions. The keys are the
- * identifiers, which are also used as names for global variables representing
- * the types in the bootstrap phase. The values are associative arrays that
- * may contain the following elements:
- * - name: The human-readable language type identifier.
- * - description: A description of the language type.
- * - locked: A boolean indicating if the user can choose wether to configure
- * the language type or not using the UI.
- * - fixed: A fixed array of language negotiation method identifiers to use to
- * initialize this language. If locked is set to TRUE and fixed is set, it
- * will always use the specified methods in the given priority order. If not
- * present and locked is TRUE then LANGUAGE_NEGOTIATION_INTERFACE will be
- * used.
- *
- * @todo Rename the 'fixed' key to something more meaningful, for instance
- * 'negotiation settings'.
- *
- * @see hook_language_types_info_alter()
- * @ingroup language_negotiation
- */
-function hook_language_types_info() {
- return array(
- 'custom_language_type' => array(
- 'name' => t('Custom language'),
- 'description' => t('A custom language type.'),
- 'locked' => FALSE,
- ),
- 'fixed_custom_language_type' => array(
- 'locked' => TRUE,
- 'fixed' => array('custom_language_negotiation_method'),
- ),
- );
-}
-
-/**
- * Perform alterations on language types.
- *
- * @param $language_types
- * Array of language type definitions.
- *
- * @see hook_language_types_info()
- * @ingroup language_negotiation
- */
-function hook_language_types_info_alter(array &$language_types) {
- if (isset($language_types['custom_language_type'])) {
- $language_types['custom_language_type_custom']['description'] = t('A far better description.');
- }
-}
-
-/**
- * Define language negotiation methods.
- *
- * @return
- * An associative array of language negotiation method definitions. The keys
- * are method identifiers, and the values are associative arrays defining
- * each method, with the following elements:
- * - types: An array of allowed language types. If a language negotiation
- * method does not specify which language types it should be used with, it
- * will be available for all the configurable language types.
- * - callbacks: An associative array of functions that will be called to
- * perform various tasks. Possible elements are:
- * - negotiation: (required) Name of the callback function that determines
- * the language value.
- * - language_switch: (optional) Name of the callback function that
- * determines links for a language switcher block associated with this
- * method. See language_switcher_url() for an example.
- * - url_rewrite: (optional) Name of the callback function that provides URL
- * rewriting, if needed by this method.
- * - file: The file where callback functions are defined (this file will be
- * included before the callbacks are invoked).
- * - weight: The default weight of the method.
- * - name: The translated human-readable name for the method.
- * - description: A translated longer description of the method.
- * - config: An internal path pointing to the method's configuration page.
- * - cache: The value Drupal's page cache should be set to for the current
- * method to be invoked.
- *
- * @see hook_language_negotiation_info_alter()
- * @ingroup language_negotiation
- */
-function hook_language_negotiation_info() {
- return array(
- 'custom_language_negotiation_method' => array(
- 'callbacks' => array(
- 'negotiation' => 'custom_negotiation_callback',
- 'language_switch' => 'custom_language_switch_callback',
- 'url_rewrite' => 'custom_url_rewrite_callback',
- ),
- 'file' => drupal_get_path('module', 'custom') . '/custom.module',
- 'weight' => -4,
- 'types' => array('custom_language_type'),
- 'name' => t('Custom language negotiation method'),
- 'description' => t('This is a custom language negotiation method.'),
- 'cache' => 0,
- ),
- );
-}
-
-/**
- * Perform alterations on language negotiation methods.
- *
- * @param $negotiation_info
- * Array of language negotiation method definitions.
- *
- * @see hook_language_negotiation_info()
- * @ingroup language_negotiation
- */
-function hook_language_negotiation_info_alter(array &$negotiation_info) {
- if (isset($negotiation_info['custom_language_method'])) {
- $negotiation_info['custom_language_method']['config'] = 'admin/config/regional/language/detection/custom-language-method';
- }
-}
-
-/**
* @} End of "addtogroup hooks".
*/
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
index 373c90be95a..663ef4c4cde 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -15,9 +15,7 @@ use Drupal\Core\Entity\EntityAccessController;
/**
* Tests the entity access controller.
*/
-class EntityAccessTest extends EntityUnitTestBase {
-
- public static $modules = array('language', 'locale');
+class EntityAccessTest extends EntityLanguageTestBase {
public static function getInfo() {
return array(
@@ -29,16 +27,7 @@ class EntityAccessTest extends EntityUnitTestBase {
function setUp() {
parent::setUp();
- $this->installSchema('system', array('variable', 'url_alias'));
- $this->installConfig(array('language'));
-
- // Create the default languages.
- $default_language = language_save(language_default());
- $languages = language_default_locked_languages($default_language->weight);
- foreach ($languages as $language) {
- language_save($language);
- }
-
+ $this->installSchema('system', 'url_alias');
}
/**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityLanguageTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityLanguageTestBase.php
index dbf4f9cf066..ee1c0d02ffe 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityLanguageTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityLanguageTestBase.php
@@ -15,6 +15,18 @@ use Drupal\field\Field as FieldService;
*/
abstract class EntityLanguageTestBase extends EntityUnitTestBase {
+ /**
+ * The language manager service.
+ *
+ * @var \Drupal\Core\Language\LanguageManagerInterface
+ */
+ protected $languageManager;
+
+ /**
+ * The available language codes.
+ *
+ * @var array
+ */
protected $langcodes;
/**
@@ -36,6 +48,8 @@ abstract class EntityLanguageTestBase extends EntityUnitTestBase {
function setUp() {
parent::setUp();
+ $this->languageManager = $this->container->get('language_manager');
+
$this->installSchema('system', 'variable');
$this->installSchema('entity_test', array(
'entity_test_mul',
@@ -92,8 +106,8 @@ abstract class EntityLanguageTestBase extends EntityUnitTestBase {
}
// Create the default languages.
- $default_language = language_save(language_default());
- $languages = language_default_locked_languages($default_language->weight);
+ $default_language = language_save($this->languageManager->getDefaultLanguage());
+ $languages = $this->languageManager->getDefaultLockedLanguages($default_language->weight);
foreach ($languages as $language) {
language_save($language);
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
index a084ebf9afd..eb234b4166f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
@@ -446,7 +446,7 @@ class EntityTranslationTest extends EntityLanguageTestBase {
* Tests language fallback applied to field and entity translations.
*/
function testLanguageFallback() {
- $current_langcode = $this->container->get('language_manager')->getLanguage(Language::TYPE_CONTENT)->id;
+ $current_langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id;
$this->langcodes[] = $current_langcode;
$values = array();
@@ -473,7 +473,7 @@ class EntityTranslationTest extends EntityLanguageTestBase {
$this->assertEqual($translation->language()->id, $default_langcode, 'The current translation language matches the expected one.');
// Check that language fallback respects language weight by default.
- $languages = language_list();
+ $languages = $this->languageManager->getLanguages();
$languages[$langcode]->weight = -1;
language_save($languages[$langcode]);
$translation = $this->entityManager->getTranslationFromContext($entity, $langcode2);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php
index dcb700bdb7a..f6a59f9e80b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/LanguageSelectElementTest.php
@@ -47,6 +47,8 @@ class LanguageSelectElementTest extends WebTestBase {
));
language_save($language);
+ \Drupal::languageManager()->reset();
+
$this->drupalGet('form-test/language_select');
// Check that the language fields were rendered on the page.
$ids = array('edit-languages-all' => Language::STATE_ALL,
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php
index 10de2a8accc..2e734ef601a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php
@@ -69,6 +69,7 @@ class CacheDecoratorLanguageTest extends WebTestBase {
$custom_strings[$definition['label']] = $langcode . ' ' . $definition['label'];
}
$this->addCustomTranslations($langcode, array('' => $custom_strings));
+ $this->rebuildContainer();
}
// Write test settings.php with new translations.
$this->writeCustomTranslations();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php
index 48d1e1f02e3..8ce7d1a6fdd 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigTransTest.php
@@ -84,7 +84,7 @@ class TwigTransTest extends WebTestBase {
$this->drupalPostForm('admin/config/regional/settings', $edit, t('Save configuration'));
// Reset the static cache of the language list.
- drupal_static_reset('language_list');
+ $this->container->get('language_manager')->reset();
// Check that lolspeak is the default language for the site.
$this->assertEqual(language_default()->id, 'xx', 'Lolspeak is the default language');
@@ -251,6 +251,7 @@ class TwigTransTest extends WebTestBase {
drupal_unlink($filename);
}
}
+ $this->container->get('language_manager')->reset();
}
/**
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 4fd03afa41b..7d121af6230 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -2252,7 +2252,7 @@ function system_update_8058() {
* @ingroup config_upgrade
*/
function system_update_8059() {
- update_variables_to_config('system.language.types', array(
+ update_variables_to_config('language.types', array(
'language_interface' => 'configurable.language_interface',
'language_content' => 'configurable.language_content',
'language_url' => 'configurable.language_content',
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 082e050268c..096c4894634 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -637,7 +637,7 @@ function toolbar_user_role_update(RoleInterface $role) {
* A unique cache ID for the user.
*/
function _toolbar_get_user_cid($uid) {
- return 'toolbar_' . $uid . ':' . \Drupal::languageManager()->getLanguage(Language::TYPE_INTERFACE)->id;
+ return 'toolbar_' . $uid . ':' . \Drupal::languageManager()->getCurrentLanguage()->id;
}
/**
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index 4983b0f0bed..e67520b0d27 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -10,7 +10,10 @@ namespace Drupal\user;
use Drupal\Core\Entity\ContentEntityFormController;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
+use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -21,7 +24,7 @@ abstract class AccountFormController extends ContentEntityFormController {
/**
* The language manager.
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -30,10 +33,10 @@ abstract class AccountFormController extends ContentEntityFormController {
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
- public function __construct(EntityManagerInterface $entity_manager, LanguageManager $language_manager) {
+ public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
parent::__construct($entity_manager);
$this->languageManager = $language_manager;
}
@@ -214,9 +217,12 @@ abstract class AccountFormController extends ContentEntityFormController {
$user_preferred_admin_langcode = $register ? $language_interface->id : $account->getPreferredAdminLangcode();
- // 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_SELECTED;
+ // Is the user preferred language enabled?
+ $user_language_enabled = FALSE;
+ if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) {
+ $negotiator = $this->languageManager->getNegotiator();
+ $user_language_enabled = $negotiator && $negotiator->isNegotiationMethodEnabled(LanguageNegotiationUser::METHOD_ID, Language::TYPE_INTERFACE);
+ }
$form['language'] = array(
'#type' => $this->languageManager->isMultilingual() ? 'details' : 'container',
'#title' => $this->t('Language settings'),
@@ -230,26 +236,22 @@ abstract class AccountFormController extends ContentEntityFormController {
'#title' => $this->t('Site language'),
'#languages' => Language::STATE_CONFIGURABLE,
'#default_value' => $user_preferred_langcode,
- '#description' => $interface_language_is_default ? $this->t("This account's preferred language for e-mails and site presentation.") : $this->t("This account's preferred language for e-mails."),
+ '#description' => $user_language_enabled ? $this->t("This account's preferred language for e-mails and site presentation.") : $this->t("This account's preferred language for e-mails."),
);
// Only show the account setting for Administration pages language to users
// if one of the detection and selection methods uses it.
$show_admin_language = FALSE;
- if ($this->moduleHandler->moduleExists('language') && $this->languageManager->isMultilingual()) {
- foreach (language_types_info() as $type_key => $language_type) {
- $negotiation_settings = variable_get("language_negotiation_{$type_key}", array());
- if ($show_admin_language = isset($negotiation_settings[LANGUAGE_NEGOTIATION_USER_ADMIN])) {
- break;
- }
- }
+ if ($account->hasPermission('access administration pages') && $this->languageManager instanceof ConfigurableLanguageManagerInterface) {
+ $negotiator = $this->languageManager->getNegotiator();
+ $show_admin_language = $negotiator && $negotiator->isNegotiationMethodEnabled(LanguageNegotiationUserAdmin::METHOD_ID);
}
$form['language']['preferred_admin_langcode'] = array(
'#type' => 'language_select',
'#title' => $this->t('Administration pages language'),
'#languages' => Language::STATE_CONFIGURABLE,
'#default_value' => $user_preferred_admin_langcode,
- '#access' => $show_admin_language && user_access('access administration pages', $account),
+ '#access' => $show_admin_language,
);
// User entities contain both a langcode property (for identifying the
// language of the entity data) and a preferred_langcode property (see
diff --git a/core/modules/user/lib/Drupal/user/Form/UserPasswordForm.php b/core/modules/user/lib/Drupal/user/Form/UserPasswordForm.php
index 236b293eb02..f7f7cfe9d95 100644
--- a/core/modules/user/lib/Drupal/user/Form/UserPasswordForm.php
+++ b/core/modules/user/lib/Drupal/user/Form/UserPasswordForm.php
@@ -128,7 +128,7 @@ class UserPasswordForm extends FormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
- $langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $langcode = $this->languageManager->getCurrentLanguage()->id;
$account = $form_state['values']['account'];
// Mail one time login URL and instructions using current language.
diff --git a/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUser.php b/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUser.php
new file mode 100644
index 00000000000..f2c99fe5d2e
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUser.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl.
+ */
+
+namespace Drupal\user\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Class for identifying language from the user preferences.
+ *
+ * @Plugin(
+ * id = \Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser::METHOD_ID,
+ * weight = -4,
+ * name = @Translation("User"),
+ * description = @Translation("Follow the user's language preference.")
+ * )
+ */
+class LanguageNegotiationUser extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-user';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ // User preference (only for authenticated users).
+ if ($this->languageManager && $this->currentUser->isAuthenticated()) {
+ $preferred_langcode = $this->currentUser->getPreferredLangcode();
+ $default_langcode = $this->languageManager->getDefaultLanguage()->id;
+ $languages = $this->languageManager->getLanguages();
+ if (!empty($preferred_langcode) && $preferred_langcode != $default_langcode && isset($languages[$preferred_langcode])) {
+ $langcode = $preferred_langcode;
+ }
+ }
+
+ // No language preference from the user.
+ return $langcode;
+ }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
new file mode 100644
index 00000000000..c7a42eb87f6
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin.
+ */
+
+namespace Drupal\user\Plugin\LanguageNegotiation;
+
+use Drupal\language\LanguageNegotiationMethodBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Identifies admin language from the user preferences.
+ *
+ * @Plugin(
+ * id = Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin::METHOD_ID,
+ * types = {Drupal\Core\Language\Language::TYPE_INTERFACE},
+ * weight = 10,
+ * name = @Translation("Account administration pages"),
+ * description = @Translation("Account administration pages language setting.")
+ * )
+ */
+class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase {
+
+ /**
+ * The language negotiation method id.
+ */
+ const METHOD_ID = 'language-user-admin';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLangcode(Request $request = NULL) {
+ $langcode = NULL;
+
+ // User preference (only for authenticated users).
+ if ($this->languageManager && $this->currentUser->isAuthenticated() && $this->isAdminPath($request)) {
+ $preferred_admin_langcode = $this->currentUser->getPreferredAdminLangcode();
+ $default_langcode = $this->languageManager->getDefaultLanguage()->id;
+ $languages = $this->languageManager->getLanguages();
+ if (!empty($preferred_admin_langcode) && $preferred_admin_langcode != $default_langcode && isset($languages[$preferred_admin_langcode])) {
+ $langcode = $preferred_admin_langcode;
+ }
+ }
+
+ // No language preference from the user or not on an admin path.
+ return $langcode;
+ }
+
+ /**
+ * Checks whether the given path is an administrative one.
+ *
+ * @param string $path
+ * A Drupal path.
+ *
+ * @return bool
+ * TRUE if the path is administrative, FALSE otherwise.
+ */
+ public function isAdminPath(Request $request) {
+ $result = FALSE;
+ if ($request && function_exists('path_is_admin')) {
+ $path = urldecode(trim($request->getPathInfo(), '/'));
+ $result = path_is_admin($path);
+ }
+ return $result;
+ }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index 847da687ca6..83e226f2244 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -157,7 +157,7 @@ abstract class DisplayPluginBase extends PluginBase {
$skip_cache = \Drupal::config('views.settings')->get('skip_cache');
if (empty($view->editing) || !$skip_cache) {
- $cid = 'unpackOptions:' . hash('sha256', serialize(array($this->options, $options))) . ':' . \Drupal::languageManager()->getLanguage()->id;
+ $cid = 'unpackOptions:' . hash('sha256', serialize(array($this->options, $options))) . ':' . \Drupal::languageManager()->getCurrentLanguage()->id;
if (empty(static::$unpackOptions[$cid])) {
$cache = \Drupal::cache('views_info')->get($cid);
if (!empty($cache->data)) {
diff --git a/core/modules/views/lib/Drupal/views/ViewsData.php b/core/modules/views/lib/Drupal/views/ViewsData.php
index 988c3c800fc..c297c0335a6 100644
--- a/core/modules/views/lib/Drupal/views/ViewsData.php
+++ b/core/modules/views/lib/Drupal/views/ViewsData.php
@@ -11,7 +11,7 @@ use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
/**
* Class to manage and lazy load cached views data.
@@ -75,7 +75,7 @@ class ViewsData {
/**
* The language manager
*
- * @var \Drupal\Core\Language\LanguageManager
+ * @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
@@ -88,15 +88,15 @@ class ViewsData {
* The configuration factory object to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler class to use for invoking hooks.
- * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
- public function __construct(CacheBackendInterface $cache_backend, ConfigFactory $config, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
+ public function __construct(CacheBackendInterface $cache_backend, ConfigFactory $config, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) {
$this->cacheBackend = $cache_backend;
$this->moduleHandler = $module_handler;
$this->languageManager = $language_manager;
- $this->langcode = $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id;
+ $this->langcode = $this->languageManager->getCurrentLanguage()->id;
$this->skipCache = $config->get('views.settings')->get('skip_cache');
}
diff --git a/core/modules/views/tests/Drupal/views/Tests/ViewsDataTest.php b/core/modules/views/tests/Drupal/views/Tests/ViewsDataTest.php
index b6e688013ef..1850903831d 100644
--- a/core/modules/views/tests/Drupal/views/Tests/ViewsDataTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/ViewsDataTest.php
@@ -76,11 +76,9 @@ class ViewsDataTest extends UnitTestCase {
$configs['views.settings']['skip_cache'] = FALSE;
$this->configFactory = $this->getConfigFactoryStub($configs);
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
- $this->languageManager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$this->languageManager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
$this->viewsData = new ViewsData($this->cacheBackend, $this->configFactory, $this->moduleHandler, $this->languageManager);
diff --git a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
index 55f24713c47..57cfe001401 100644
--- a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
+++ b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
@@ -60,9 +60,7 @@ class DateTest extends UnitTestCase {
protected function setUp() {
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
- $this->languageManager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$this->stringTranslation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
$this->date = new Date($this->entityManager, $this->languageManager, $this->stringTranslation, $this->getConfigFactoryStub());
diff --git a/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
index fa27a3e2cc7..0e52b9f5988 100644
--- a/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
@@ -113,11 +113,9 @@ class ContextualLinkManagerTest extends UnitTestCase {
$property->setAccessible(TRUE);
$property->setValue($this->contextualLinkManager, $this->accessManager);
- $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
$this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
index 47384aca2d5..aaaa6259fc9 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
@@ -102,11 +102,9 @@ abstract class LocalTaskIntegrationTest extends UnitTestCase {
$property->setAccessible(TRUE);
$property->setValue($manager, $factory);
- $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
$cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
index da5f90d6e25..6fc7c1ceea1 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
@@ -265,11 +265,9 @@ class LocalTaskManagerTest extends UnitTestCase {
$property->setAccessible(TRUE);
$property->setValue($this->manager, $this->factory);
- $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
- ->disableOriginalConstructor()
- ->getMock();
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
$this->manager->setCacheBackend($this->cacheBackend, $language_manager, 'local_task', array('local_task' => 1));
diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php
index f49184f83a9..9197085666e 100644
--- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php
+++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php
@@ -8,17 +8,21 @@
namespace Drupal\Tests\Core\PathProcessor;
use Drupal\Component\Utility\Settings;
+use Drupal\Core\Language\Language;
use Drupal\Core\PathProcessor\PathProcessorAlias;
use Drupal\Core\PathProcessor\PathProcessorDecode;
use Drupal\Core\PathProcessor\PathProcessorFront;
use Drupal\Core\PathProcessor\PathProcessorManager;
use Drupal\language\HttpKernel\PathProcessorLanguage;
+use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Tests\UnitTestCase;
/**
* Tests path processor functionality.
+ *
+ * @group PathApi
*/
class PathProcessorTest extends UnitTestCase {
@@ -45,12 +49,44 @@ class PathProcessorTest extends UnitTestCase {
}
$this->languages = $languages;
+ // Create a stub configuration.
+ $language_prefixes = array_keys($this->languages);
+ $config = array(
+ 'url' => array(
+ 'prefixes' => array_combine($language_prefixes, $language_prefixes)
+ )
+ );
+
+ // Create a URL-based language negotiation method definition.
+ $method_definitions = array(
+ LanguageNegotiationUrl::METHOD_ID => array(
+ 'class' => '\Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl',
+ ),
+ );
+
+ // Create a URL-based language negotiation method.
+ $method_instance = new LanguageNegotiationUrl($config);
+
// Create a language manager stub.
- $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $language_manager = $this->getMockBuilder('Drupal\language\ConfigurableLanguageManagerInterface')
+ ->getMock();
$language_manager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue($languages['en']));
+ $language_manager->expects($this->any())
+ ->method('getLanguages')
+ ->will($this->returnValue($this->languages));
+ $language_manager->expects($this->any())
+ ->method('getLanguageTypes')
+ ->will($this->returnValue(array(Language::TYPE_INTERFACE)));
+ $language_manager->expects($this->any())
+ ->method('getNegotiationMethods')
+ ->will($this->returnValue($method_definitions));
+ $language_manager->expects($this->any())
+ ->method('getNegotiationMethodInstance')
+ ->will($this->returnValue($method_instance));
+ $method_instance->setLanguageManager($language_manager);
$this->languageManager = $language_manager;
}
@@ -79,23 +115,41 @@ class PathProcessorTest extends UnitTestCase {
// Create a stub config factory with all config settings that will be checked
// during this test.
- $language_prefixes = array_keys($this->languages);
$config_factory_stub = $this->getConfigFactoryStub(
array(
'system.site' => array(
'page.front' => 'user'
),
'language.negotiation' => array(
- 'url.prefixes' => array_combine($language_prefixes, $language_prefixes)
- )
+ 'url' => array(
+ 'prefixes' => array('fr' => 'fr'),
+ ),
+ ),
)
);
+ // Create a language negotiator stub.
+ $negotiator = $this->getMockBuilder('Drupal\language\LanguageNegotiatorInterface')
+ ->getMock();
+ $negotiator->expects($this->any())
+ ->method('getNegotiationMethods')
+ ->will($this->returnValue(array(LanguageNegotiationUrl::METHOD_ID => array('class' => 'Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl'))));
+ $method = new LanguageNegotiationUrl();
+ $method->setConfig($config_factory_stub);
+ $method->setLanguageManager($this->languageManager);
+ $negotiator->expects($this->any())
+ ->method('getNegotiationMethodInstance')
+ ->will($this->returnValue($method));
+
+ // Create a user stub.
+ $current_user = $this->getMockBuilder('Drupal\Core\Session\AccountInterface')
+ ->getMock();
+
// Create the processors.
$alias_processor = new PathProcessorAlias($alias_manager);
$decode_processor = new PathProcessorDecode();
$front_processor = new PathProcessorFront($config_factory_stub);
- $language_processor = new PathProcessorLanguage($config_factory_stub, new Settings(array()), $this->languageManager, $this->languages);
+ $language_processor = new PathProcessorLanguage($config_factory_stub, new Settings(array()), $this->languageManager, $negotiator, $current_user);
// First, test the processor manager with the processors in the incorrect
// order. The alias processor will run before the language processor, meaning
diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
index 3e86b66db65..ec84708fa88 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -113,9 +113,9 @@ class DefaultPluginManagerTest extends UnitTestCase {
->with($cid . ':en', $this->expectedDefinitions);
$language = new Language(array('id' => 'en'));
- $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->once())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->with(Language::TYPE_INTERFACE)
->will($this->returnValue($language));
@@ -144,9 +144,9 @@ class DefaultPluginManagerTest extends UnitTestCase {
->method('set');
$language = new Language(array('id' => 'en'));
- $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->once())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->with(Language::TYPE_INTERFACE)
->will($this->returnValue($language));
@@ -173,9 +173,9 @@ class DefaultPluginManagerTest extends UnitTestCase {
->method('deleteMultiple');
$language = new Language(array('id' => 'en'));
- $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$language_manager->expects($this->once())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->with(Language::TYPE_INTERFACE)
->will($this->returnValue($language));
diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
index 6b7334fa395..469b0e39f58 100644
--- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
@@ -79,7 +79,7 @@ class LinkGeneratorTest extends UnitTestCase {
$this->urlGenerator = $this->getMock('\Drupal\Core\Routing\UrlGenerator', array(), array(), '', FALSE);
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
- $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManager');
+ $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler, $this->languageManager);
}
@@ -89,7 +89,7 @@ class LinkGeneratorTest extends UnitTestCase {
*/
public function setUpLanguageManager() {
$this->languageManager->expects($this->any())
- ->method('getLanguage')
+ ->method('getCurrentLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
}