diff --git a/core/core.services.yml b/core/core.services.yml index 7007138..329eb57 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -194,9 +194,6 @@ services: http_kernel: class: Drupal\Core\HttpKernel arguments: ['@event_dispatcher', '@service_container', '@controller_resolver'] - language_manager: - class: Drupal\Core\Language\LanguageManager - arguments: ['@state'] string_translator.custom_strings: class: Drupal\Core\StringTranslation\Translator\CustomStrings tags: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 32f47fa..7217bd4 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2366,33 +2366,6 @@ function language($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 @@ -2415,65 +2388,7 @@ function language_multilingual() { * 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() || module_exists('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); - } - else { - // 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; + return Drupal::languageManager()->getLanguageList($flags); } /** @@ -2487,24 +2402,7 @@ function language_list($flags = Language::STATE_CONFIGURABLE) { * An array of language objects. */ 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; + return Drupal::languageManager()->getDefaultLockedLanguages($weight); } /** @@ -2515,10 +2413,11 @@ function language_default_locked_languages($weight = 0) { * * @return \Drupal\core\Language\Language|null * A fully-populated language object or NULL. + * + * @see \Druoal\Core\Language\LanguageManager::loadLanguage(). */ function language_load($langcode) { - $languages = language_list(Language::STATE_ALL); - return isset($languages[$langcode]) ? $languages[$langcode] : NULL; + return Drupal::languageManager()->loadLanguage($langcode); } /** @@ -2565,15 +2464,8 @@ function language_is_locked($langcode) { * 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); + $default_info = variable_get('language_default', Language::$defaultValues); + return new Language($default_info + array('default' => TRUE)); } /** diff --git a/core/includes/common.inc b/core/includes/common.inc index be97724..7f51dc2 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4794,6 +4794,14 @@ function drupal_flush_all_caches() { } /** + * Rebuild the container to store updated language negotiation settings. + */ +function drupal_rebuild_language_negotiation_settings() { + Drupal::service('plugin.manager.language_negotiation_method')->clearCachedDefinitions(); + PhpStorageFactory::get('service_container')->deleteAll(); +} + +/** * Changes the dummy query string added to all CSS and JavaScript files. * * Changing the dummy query string appended to CSS and JavaScript files forces diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 1f7a074..17ba9b6 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -9,6 +9,7 @@ use Drupal\Core\Database\Install\TaskException; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; +use Drupal\Core\Language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser; use Drupal\Core\StringTranslation\Translator\FileTranslation; use Drupal\Core\DependencyInjection\ContainerBuilder; @@ -370,6 +371,14 @@ function install_begin_request(&$install_state) { else { // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. $container = new ContainerBuilder(); + // Register Core's namespaces just for the installer. + $namespaces = array( + 'Drupal\Core' => DRUPAL_ROOT . '/core/lib', + 'Drupal\Component' => DRUPAL_ROOT . '/core/lib', + ); + $container->register('container.namespaces', 'ArrayObject') + ->addArgument('%container.namespaces%'); + $container->setParameter('container.namespaces', $namespaces); $container->register('event_dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher'); @@ -386,9 +395,12 @@ function install_begin_request(&$install_state) { ->addArgument(new Reference('config.context')); // Register the 'language_manager' service. - $container - ->register('language_manager', 'Drupal\Core\Language\LanguageManager') - ->addArgument(NULL); + $container->register('plugin.manager.language_negotiation_method', 'Drupal\Core\Language\LanguageNegotiationMethodManager') + ->addArgument(new Reference('container.namespaces')) + ->addArgument(new Reference('cache.cache')); + $container->register('language_manager', 'Drupal\Core\Language\InstallLanguageManager') + ->addArgument(array()) + ->addArgument(new Reference('plugin.manager.language_negotiation_method')); // Register the translation services. install_register_translation_service($container); @@ -1582,7 +1594,8 @@ function install_select_language_form($form, &$form_state, $files = array()) { } } - $browser_langcode = language_from_browser($browser_options); + $method = new LanguageNegotiationBrowser(array('browser' => array('mappings' => array()))); + $browser_langcode = $method->negotiateLanguage($browser_options, Request::createFromGlobals()); $form['langcode'] = array( '#type' => 'select', '#title' => t('Choose language'), diff --git a/core/includes/language.inc b/core/includes/language.inc index 79bae62..af20cc9 100644 --- a/core/includes/language.inc +++ b/core/includes/language.inc @@ -113,42 +113,6 @@ */ /** - * 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 @@ -315,28 +279,7 @@ function language_negotiation_method_enabled($method_id, $type = NULL) { * 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; + return Drupal::languageManager()->getLanguageNegotiationSwitchLinks($type, $path); } /** @@ -411,129 +354,7 @@ function language_negotiation_set($type, $method_weights) { * 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']; - } - // 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'] == variable_get('cache', 0); - $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); + return Drupal::service('plugin.manager.language_negotiation_method')->getDefinitions(); } /** diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index a6cb957..7fbd029 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -13,6 +13,7 @@ use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterLanguageNegotiationPass; use Drupal\Core\DependencyInjection\Compiler\RegisterPathProcessorsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterRouteFiltersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass; @@ -50,6 +51,7 @@ public function register(ContainerBuilder $container) { $container->addScope(new Scope('request')); $this->registerTwig($container); $this->registerModuleHandler($container); + $this->registerLanguage($container); $container->addCompilerPass(new RegisterRouteFiltersPass()); // Add a compiler pass for registering event subscribers. @@ -133,4 +135,24 @@ public static function registerTwig(ContainerBuilder $container) { ->addMethodCall('addExtension', array(new Definition('Twig_Extension_Debug'))); } + /** + * Registers language related services. + */ + protected function registerLanguage(ContainerBuilder $container) { + // @todo Refactor this when all language negotiation settings are converted + // a single configuration object. + $storage = $container->get('kernel.config.storage'); + $config = $storage->read('language.negotiation') ?: array(); + $config += array('browser' => array('mappings' => $storage->read('language.mappings'))); + + // Register the 'language_manager' service. + $container->register('plugin.manager.language_negotiation_method', 'Drupal\Core\Language\LanguageNegotiationMethodManager') + ->addArgument(new Reference('container.namespaces')) + ->addArgument(new Reference('cache.cache')); + $container->register('language_manager', 'Drupal\Core\Language\LanguageManager') + ->addArgument($config) + ->addArgument(new Reference('plugin.manager.language_negotiation_method')) + ->addArgument(new Reference('state')); + } + } diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 1bf9c05..a0a9d5d 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -509,6 +509,8 @@ protected function buildContainer() { $container->register('class_loader')->setSynthetic(TRUE); $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE); $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE); + // Register the kernel-level config storage. + $container->set('kernel.config.storage', $this->configStorage); $yaml_loader = new YamlFileLoader($container); foreach ($this->serviceYamls as $filename) { $yaml_loader->load($filename); diff --git a/core/lib/Drupal/Core/Language/InstallLanguageManager.php b/core/lib/Drupal/Core/Language/InstallLanguageManager.php new file mode 100644 index 0000000..b70ee3f --- /dev/null +++ b/core/lib/Drupal/Core/Language/InstallLanguageManager.php @@ -0,0 +1,40 @@ +config = $config; + $this->negotiatorManager = $negotiator_manager; + } + + /** + * {@inheritdoc} + */ + public function isMultilingual() { + // No state service in install time. + return FALSE; + } + +} diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php index 7181b32..ceea20f 100644 --- a/core/lib/Drupal/Core/Language/Language.php +++ b/core/lib/Drupal/Core/Language/Language.php @@ -17,6 +17,23 @@ * @see language_default() */ class Language { + + /** + * The values to use to instantiate the default language. + * + * @todo Remove once converted to config. + * + * @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. public $name = ''; public $id = ''; diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php index 7bc716d..8081cea 100644 --- a/core/lib/Drupal/Core/Language/LanguageManager.php +++ b/core/lib/Drupal/Core/Language/LanguageManager.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Language; +use Drupal\Component\Plugin\PluginManagerInterface; use Symfony\Component\HttpFoundation\Request; use Drupal\Core\KeyValueStore\KeyValueStoreInterface; @@ -16,18 +17,16 @@ class LanguageManager { /** - * A request object. - * - * @var \Symfony\Component\HttpFoundation\Request + * The language negotiation method id for the language manager. */ - protected $request; + const METHOD_ID = 'language-default'; /** * The Key/Value Store to use for state. * * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface */ - protected $state = NULL; + protected $state; /** * An array of language objects keyed by language type. @@ -37,6 +36,34 @@ class LanguageManager { protected $languages; /** + * An array of all the available languages keyed by language code. + * + * @var array + */ + protected $languageList; + + /** + * An array of configuration. + * + * @var array + */ + protected $config; + + /** + * The language negotiation method plugin manager. + * + * @var \Drupal\Component\Plugin\PluginManagerInterface + */ + protected $negotiatorManager; + + /** + * A request object. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** * Whether or not the language manager has been initialized. * * @var bool @@ -46,20 +73,23 @@ class LanguageManager { /** * 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 */ protected $initializing = FALSE; /** - * Constructs an LanguageManager object. + * Constructs a new LanguageManager object. * - * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state - * The state keyvalue store. + * @param array $config + * An array of configuration. + * @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager + * The language negotiation methods plugin manager + * @param \Drupal\Core\KeyValueStoreInterface $state + * The state key value store. */ - public function __construct(KeyValueStoreInterface $state = NULL) { + public function __construct(array $config, PluginManagerInterface $negotiator_manager, KeyValueStoreInterface $state) { + $this->config = $config; + $this->negotiatorManager = $negotiator_manager; $this->state = $state; } @@ -71,9 +101,11 @@ public function init() { return; } if ($this->isMultilingual()) { - foreach ($this->getLanguageTypes() as $type) { - $this->getLanguage($type); - } + // This is still assumed by various functions to be loaded. + include_once DRUPAL_ROOT . '/core/includes/language.inc'; + } + foreach ($this->getLanguageTypes() as $type) { + $this->getLanguage($type); } $this->initialized = TRUE; } @@ -105,31 +137,109 @@ public function getLanguage($type = Language::TYPE_INTERFACE) { return $this->languages[$type]; } + // Ensure we have a valid value for this language type. + $this->languages[$type] = $this->getLanguageDefault(); + 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->languages[$type] = $this->initializeType($type); $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(); + // If the current interface language needs to be retrieved during + // initialization we return the system language. This way t() calls + // happening during initialization will return the original strings which + // can be translated by calling t() 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)); } } - else { - $this->languages[$type] = $this->getLanguageDefault(); - } + return $this->languages[$type]; } /** + * Initializes the specified language type. + * + * @param string $type + * The language type to be initialized. + */ + public function initializeType($type) { + // Execute the language negotiation methods in the order they were set up + // and return the first valid language found. + foreach ($this->getNegotiationForType($type) as $method_id) { + if (!isset($this->negotiated[$method_id])) { + $this->negotiated[$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->negotiated[$method_id]) ? clone($this->negotiated[$method_id]) : FALSE; + + 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 = $this->getLanguageDefault(); + $language->method_id = LanguageManager::METHOD_ID; + return $language; + } + + /** + * Returns the negotiation settings for the specified language type. + * + * @param string $type + * The type of the language to retireve the negotiation settings for. + * + * @returns array + * An array of language negotiation method identifiers ordered by method + * weight. + */ + protected function getNegotiationForType($type) { + // @todo convert to CMI https://drupal.org/node/1827038 + return array_keys(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|FALSE + * Negotiated language object for given type and method, FALSE otherwise. + */ + protected function negotiateLanguage($type, $method_id) { + global $user; + $langcode = FALSE; + $languages = $this->getLanguageList(); + $method = $this->negotiatorManager->getDefinition($method_id); + + if (!isset($method['types']) || in_array($type, $method['types'])) { + // 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'] == \Drupal::config('system.performance')->get('cache.page.use_internal'); + if ($cache) { + $negotiator = $this->negotiatorManager->createInstance($method_id, $this->config); + $negotiator->setLanguageManager($this); + $langcode = $negotiator->negotiateLanguage($languages, $this->request); + } + } + + return isset($languages[$langcode]) ? $languages[$langcode] : FALSE; + } + + /** * Resets the given language type or all types if none specified. * * @param string|null $type @@ -141,6 +251,7 @@ public function reset($type = NULL) { if (!isset($type)) { $this->languages = array(); $this->initialized = FALSE; + $this->languageList = NULL; } elseif (isset($this->languages[$type])) { unset($this->languages[$type]); @@ -154,21 +265,70 @@ public function reset($type = NULL) { * TRUE if more than one language is enabled, FALSE otherwise. */ public function isMultilingual() { - if (!isset($this->state)) { - // No state service in install time. - return FALSE; - } return ($this->state->get('language_count') ?: 1) > 1; } /** * Returns an array of the available language types. * - * @return array() - * An array of all 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). */ - protected function getLanguageTypes() { - return language_types_get_all(); + public function getLanguageTypes() { + $types = \Drupal::config('system.language.types')->get('all'); + return $types ? $types : array_keys($this->getTypeDefaults()); + } + + /** + * 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). + */ + public function getTypeDefaults() { + return array( + Language::TYPE_INTERFACE => TRUE, + Language::TYPE_CONTENT => FALSE, + Language::TYPE_URL => 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 array + * A keyed array of links ready to be themed. + */ + function getLanguageNegotiationSwitchLinks($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::moduleHandler()->alter('language_switch_links', $result, $type, $path); + $links = (object) array('links' => $result, 'method_id' => $method_id); + break; + } + } + } + + return $links; } /** @@ -177,16 +337,104 @@ protected function getLanguageTypes() { * @return \Drupal\Core\Language\Language * A language object. */ - protected 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 getLanguageDefault() { + // @todo convert to CMI https://drupal.org/node/1827038 + $default_info = variable_get('language_default', Language::$defaultValues); + return new Language($default_info + array('default' => TRUE)); + } + + /** + * 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 getLanguageList($flags = Language::STATE_CONFIGURABLE) { + // Initialize master language list. + if (!isset($this->languageList)) { + // Initialize local language list cache. + $this->languageList = array(); + // Fill in master language list based on current configuration. + $default = $this->getLanguageDefault(); + // No language module, so use the default language only. + $this->languageList = array($default->id => $default); + // Add the special languages, they will be filtered later if needed. + $this->languageList += $this->getDefaultLockedLanguages($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 : $this->getLanguageDefault(); + // Rename the default language. + $default->name = t("Site's default language (@lang_name)", array('@lang_name' => $default->name)); + $filtered_languages['site_default'] = $default; + } + + foreach ($this->languageList as $id => $language) { + if (($language->locked && !($flags & Language::STATE_LOCKED)) || (!$language->locked && !($flags & Language::STATE_CONFIGURABLE))) { + continue; + } + $filtered_languages[$id] = $language; + } + + return $filtered_languages; + } + + /** + * Loads a language object from the database. + * + * @param string $langcode + * The language code. + * + * @return \Drupal\core\Language\Language|null + * A fully-populated language object or NULL. + */ + public function loadLanguage($langcode) { + $languages = $this->getLanguageList(Language::STATE_ALL); + return isset($languages[$langcode]) ? $languages[$langcode] : NULL; + } + + /** + * 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) { + $languages = array(); + + $locked_language = array( + 'default' => FALSE, + 'locked' => TRUE, + 'enabled' => TRUE, + ); + $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; } /** @@ -308,4 +556,14 @@ public static function getStandardLanguageList() { ); } + /** + * 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). + */ + public function getTypes() { + } + } diff --git a/core/lib/Drupal/Core/Language/LanguageNegotiationInterface.php b/core/lib/Drupal/Core/Language/LanguageNegotiationInterface.php new file mode 100644 index 0000000..9b1c666 --- /dev/null +++ b/core/lib/Drupal/Core/Language/LanguageNegotiationInterface.php @@ -0,0 +1,37 @@ +config = $config; + } + + /** + * Implements \Drupal\Core\Language\LanguageNegotiationInterface::setLanguageManager(). + */ + public function setLanguageManager(LanguageManager $languageManager) { + $this->languageManager = $languageManager; + } + +} diff --git a/core/lib/Drupal/Core/Language/LanguageNegotiationMethodManager.php b/core/lib/Drupal/Core/Language/LanguageNegotiationMethodManager.php new file mode 100644 index 0000000..0410d26 --- /dev/null +++ b/core/lib/Drupal/Core/Language/LanguageNegotiationMethodManager.php @@ -0,0 +1,39 @@ +cacheBackend = $cache_backend; + $this->cacheKeyPrefix = 'language_negotiation_plugins'; + $this->cacheKey = 'language_negotiation_plugins'; + } + + /** + * {@inheritdoc} + */ + public function clearCachedDefinitions() { + $this->cacheBackend->delete($this->cacheKey); + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php new file mode 100644 index 0000000..8e8ce12 --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationBrowser.php @@ -0,0 +1,150 @@ +server->get('HTTP_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($request->server->get('HTTP_ACCEPT_LANGUAGE')), $matches, PREG_SET_ORDER)) { + // Load custom mappings to support browsers that are sending non standard + // language codes. + $mappings = $this->config['browser']['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; + $browser_langcodes[$langcode] = (int) ($qvalue * 1000); + } + } + + // 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 occurence 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 occurence 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; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php new file mode 100644 index 0000000..8dce46d --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSelected.php @@ -0,0 +1,42 @@ +config['selected_langcode']) ? $this->config['selected_langcode'] : FALSE; + return $langcode != 'site_default' ? $langcode : $this->languageManager->getLanguageDefault()->id; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php new file mode 100644 index 0000000..07fbb6a --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationSession.php @@ -0,0 +1,58 @@ +config['session']['parameter']; + + // Request parameter: we need to update the session parameter only if we + // have an authenticated user. + $langcode = $request->query->get($param); + if ($langcode) { + global $user; + $languages = $this->languageManager->getLanguageList(); + if ($user->isAuthenticated() && isset($languages[$langcode])) { + $_SESSION[$param] = $langcode; + } + } + + // Session parameter. + if (isset($_SESSION[$param])) { + return $_SESSION[$param]; + } + + return FALSE; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php new file mode 100644 index 0000000..7cba9bf --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUI.php @@ -0,0 +1,41 @@ +languageManager->getLanguage()->id; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php new file mode 100644 index 0000000..02147bc --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php @@ -0,0 +1,100 @@ +config['url']['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. + $prefixes = $this->config['url']['prefixes']; + $negotiated_language = FALSE; + foreach ($languages as $language) { + if (isset($prefixes[$language->id]) && $prefixes[$language->id] == $prefix) { + $negotiated_language = $language; + break; + } + } + + if ($negotiated_language !== FALSE) { + $langcode = $negotiated_language->id; + } + break; + + case LanguageNegotiationUrl::CONFIG_DOMAIN: + // Get only the host, not the port. + $http_host = $request->server->get('HTTP_HOST'); + if (strpos($http_host, ':') !== FALSE) { + $http_host_tmp = explode(':', $http_host); + $http_host = current($http_host_tmp); + } + $domains = $this->config['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) { + $langcode = $language->id; + break; + } + } + } + break; + } + + return $langcode; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php new file mode 100644 index 0000000..637fa4e --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUrlFallback.php @@ -0,0 +1,73 @@ +languageManager->getLanguageDefault(); + $prefix = ($this->config['url']['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. + $domains = $this->config['url']['domains']; + $prefixes = $this->config['url']['prefixes']; + if (($prefix && empty($prefixes[$default->id])) || (!$prefix && empty($domains[$default->id]))) { + return $default->id; + } + else { + return $this->languageManager->getLanguage()->id; + } + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUser.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUser.php new file mode 100644 index 0000000..85d2da2 --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUser.php @@ -0,0 +1,47 @@ +attributes->get('_account'); + + if ($user->isAuthenticated() && isset($languages[$user->getPreferredLangcode()])) { + return $user->getPreferredLangcode(); + } + + // No language preference from the user. + return FALSE; + } + +} diff --git a/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php new file mode 100644 index 0000000..6a9ff9f --- /dev/null +++ b/core/lib/Drupal/Core/Language/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php @@ -0,0 +1,51 @@ +attributes->get('_account'); + + // @todo Avoid calling _current_path() and path_is_admin() directly. + $request_path = $request ? urldecode(trim($request->getPathInfo(), '/')) : _current_path(); + if ($user->isAuthenticated() && isset($languages[$user->getPreferredAdminLangcode()]) && path_is_admin($request_path)) { + return $user->getPreferredAdminLangcode(); + } + + // No language preference from the user or not on an admin path. + return FALSE; + } + +} diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php index 915e4bb..0ecfb36 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockLanguageTest.php @@ -74,10 +74,9 @@ public function testLanguageBlockVisibility() { $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('', array('language' => language_load('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. diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php index c35bc78..c344ad3 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php @@ -80,7 +80,6 @@ function setUp() { * 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/language/language.admin.inc b/core/modules/language/language.admin.inc index c3f669c..3e8743a 100644 --- a/core/modules/language/language.admin.inc +++ b/core/modules/language/language.admin.inc @@ -279,6 +279,9 @@ function language_negotiation_configure_form_submit($form, &$form_state) { \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); } + // Rebuild the container to update the submitted settings. + drupal_rebuild_language_negotiation_settings(); + $form_state['redirect'] = 'admin/config/regional/language/detection'; drupal_set_message(t('Language negotiation configuration saved.')); } diff --git a/core/modules/language/language.install b/core/modules/language/language.install index c435c07..ba5a7eb 100644 --- a/core/modules/language/language.install +++ b/core/modules/language/language.install @@ -39,7 +39,7 @@ function language_uninstall() { variable_del('language_content_type_default'); variable_del('language_content_type_negotiation'); - foreach (language_types_get_all() as $type) { + foreach (Drupal::languageManager()->getLanguageTypes() as $type) { variable_del("language_negotiation_$type"); variable_del("language_negotiation_methods_weight_$type"); } diff --git a/core/modules/language/language.module b/core/modules/language/language.module index d85aad0..0865672 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -499,8 +499,8 @@ function language_save($language) { variable_set('language_default', (array) $language); } - // Kill the static cache in language_list(). - drupal_static_reset('language_list'); + // Reset the language information. + Drupal::languageManager()->reset(); // Update language count based on unlocked language count. language_update_count(); @@ -553,13 +553,13 @@ function language_delete($langcode) { // Remove the language. entity_delete_multiple('language_entity', array($language->id)); - drupal_static_reset('language_list'); - language_update_count(); // Update weight of locked system languages. language_update_locked_weights(); + Drupal::languageManager()->reset(); + $t_args = array('%language' => $language->name, '%langcode' => $language->id); watchdog('language', 'The %language (%langcode) language has been removed.', $t_args); return TRUE; @@ -624,88 +624,6 @@ function language_language_types_info() { } /** - * Implements hook_language_negotiation_info(). - */ -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.'), - ); - - $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.'), - ); - - $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."), - ); - - return $negotiation_info; -} - -/** * Include negotiation backend functionality. */ function language_negotiation_include() { @@ -856,4 +774,5 @@ function language_system_regional_settings_form_submit($form, &$form_state) { $language = $languages[$form_state['values']['site_default_language']]; $language->default = TRUE; language_save($language); + drupal_rebuild_language_negotiation_settings(); } diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc index 43cd607..00840e8 100644 --- a/core/modules/language/language.negotiation.inc +++ b/core/modules/language/language.negotiation.inc @@ -50,338 +50,6 @@ 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) { - if (empty($_SERVER['HTTP_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($_SERVER['HTTP_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 occurence 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 occurence 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). - global $user; - - 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). - global $user; - - 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'); - - // Request parameter: we need to update the session parameter only if we have - // an authenticated user. - if (isset($_GET[$param]) && isset($languages[$langcode = $_GET[$param]])) { - global $user; - 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= $_SERVER['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. diff --git a/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php b/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php index ccc833c..4cabb9b 100644 --- a/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php +++ b/core/modules/language/lib/Drupal/language/Form/LanguageAddForm.php @@ -91,6 +91,10 @@ public function submitForm(array &$form, array &$form_state) { } // Save the language and inform the user that it happened. $language = language_save($language); + + // Rebuild the container to update the submitted settings. + drupal_rebuild_language_negotiation_settings(); + 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 9d8b6aa..318f54c 100644 --- a/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php +++ b/core/modules/language/lib/Drupal/language/Form/LanguageEditForm.php @@ -54,6 +54,8 @@ public function submitForm(array &$form, array &$form_state) { $language->name = $form_state['values']['name']; $language->direction = $form_state['values']['direction']; language_save($language); + // Rebuild the container to update the submitted settings. + drupal_rebuild_language_negotiation_settings(); $form_state['redirect'] = 'admin/config/regional/language'; } diff --git a/core/modules/language/lib/Drupal/language/Form/NegotiationBrowserDeleteForm.php b/core/modules/language/lib/Drupal/language/Form/NegotiationBrowserDeleteForm.php index 29de4ce..9419ba7 100644 --- a/core/modules/language/lib/Drupal/language/Form/NegotiationBrowserDeleteForm.php +++ b/core/modules/language/lib/Drupal/language/Form/NegotiationBrowserDeleteForm.php @@ -66,6 +66,8 @@ public function submitForm(array &$form, array &$form_state) { language_set_browser_drupal_langcode_mappings($mappings); } + // Rebuild the container to update the submitted settings. + drupal_rebuild_language_negotiation_settings(); $form_state['redirect'] = 'admin/config/regional/language/detection/browser'; } diff --git a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php index aa3cc2b..c9593f0 100644 --- a/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php +++ b/core/modules/language/lib/Drupal/language/HttpKernel/PathProcessorLanguage.php @@ -42,51 +42,43 @@ class PathProcessorLanguage implements InboundPathProcessorInterface, OutboundPa */ protected $languageManager; - /** - * An array of enabled languages. - * - * @var array - */ - protected $languages; - /** * 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 LanguageManager $language_manager + * A LanguageManager object. */ - public function __construct(ConfigFactory $config, Settings $settings, LanguageManager $language_manager, array $languages = array()) { + public function __construct(ConfigFactory $config, Settings $settings, LanguageManager $language_manager) { $this->config = $config; $this->mixedModeSessions = $settings->get('mixed_mode_sessions', FALSE); $this->languageManager = $language_manager; - if (empty($languages)) { - $languages = language_list(); - } - $this->languages = $languages; } /** * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processInbound(). */ public function processInbound($path, Request $request) { - if (!empty($path)) { - $args = explode('/', $path); - $prefix = array_shift($args); + if (empty($path)) { + return $path; + } - // 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); - } - } + $languages = $this->languageManager->getLanguageList(); + $prefixes = $this->config->get('language.negotiation')->get('url.prefixes'); + $parts = explode('/', $path); + $prefix = array_shift($parts); + + // Search prefix within enabled languages. + foreach ($languages as $language) { + if (isset($prefixes[$language->id]) && $prefixes[$language->id] == $prefix) { + // Rebuild $path with the language removed. + $path = implode('/', $parts); + break; + } } + return $path; } @@ -103,7 +95,7 @@ public function processOutbound($path, &$options = array(), Request $request = N $url_scheme = $request->getScheme(); $port = $request->getPort(); } - $languages = array_flip(array_keys($this->languages)); + $languages = array_flip(array_keys($this->languageManager->getLanguageList())); // 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); diff --git a/core/modules/language/lib/Drupal/language/LanguageListController.php b/core/modules/language/lib/Drupal/language/LanguageListController.php index d33b9f4..b1d05c9 100644 --- a/core/modules/language/lib/Drupal/language/LanguageListController.php +++ b/core/modules/language/lib/Drupal/language/LanguageListController.php @@ -92,8 +92,7 @@ public function buildForm(array $form, array &$form_state) { 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'); + drupal_rebuild_language_negotiation_settings(); // Update weight of locked system languages. language_update_locked_weights(); diff --git a/core/modules/language/lib/Drupal/language/LanguageManager.php b/core/modules/language/lib/Drupal/language/LanguageManager.php new file mode 100644 index 0000000..6c744a2 --- /dev/null +++ b/core/modules/language/lib/Drupal/language/LanguageManager.php @@ -0,0 +1,77 @@ +configStorage = $config_storage; + } + + /** + * {@inheritdoc} + */ + public function getLanguageList($flags = Language::STATE_CONFIGURABLE) { + if (!isset($this->languageList)) { + // Fill in master language list based on current configuration. + $default = $this->getLanguageDefault(); + + // Use language module configuration if available. + $language_ids = $this->configStorage->listAll('language.entity'); + foreach (\Drupal::service('config.factory')->loadMultiple($language_ids) as $language_config) { + $langcode = $language_config->get('id'); + $info = $language_config->get(); + $info['default'] = ($langcode == $default->id); + $this->languageList[$langcode] = new Language($info); + } + } + + return parent::getLanguageList($flags); + } + +} 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 0000000..40e7670 --- /dev/null +++ b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php @@ -0,0 +1,34 @@ +getDefinition('language_manager'); + $definition->setClass('Drupal\language\LanguageManager') + ->addArgument(new Reference('config.storage')); + } + +} diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php index a369484..4fc8b42 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php @@ -9,6 +9,8 @@ use Drupal\simpletest\WebTestBase; use Drupal\Core\Language\Language; +use Drupal\Core\Language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser; +use Symfony\Component\HttpFoundation\Request; /** * Test browser language detection. @@ -153,9 +155,11 @@ function testLanguageFromBrowser() { 'zh-cht' => 'zh-hant', ); + $mappings = $this->container->get('config.factory')->get('language.mappings')->get(); + $language_neg = new LanguageNegotiationBrowser(array('browser' => array('mappings' => $mappings))); foreach ($test_cases as $accept_language => $expected_result) { - $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $accept_language; - $result = language_from_browser($languages); + $request = Request::create('', 'GET', array(), array(), array(), array('HTTP_ACCEPT_LANGUAGE' => $accept_language)); + $result = $language_neg->negotiateLanguage($languages, $request); $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/LanguageConfigurationElementTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php index d5a3c02..878f497 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php @@ -85,6 +85,7 @@ public function testDefaultLangcode() { $langcode = language_get_default_langcode('custom_type', 'custom_bundle'); $language_interface = language(Language::TYPE_INTERFACE); $this->assertEqual($langcode, $language_interface->id); + drupal_rebuild_language_negotiation_settings(); // Site's default. $old_default = language_default(); diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php index 1fb8c85..fa384d5 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php @@ -156,7 +156,7 @@ function testLanguageConfigurationWeight() { */ protected function checkConfigurableLanguageWeight($state = 'by default') { // Reset language list. - drupal_static_reset('language_list'); + $this->container->get('language_manager')->reset(); $max_configurable_language_weight = $this->getHighestConfigurableLanguageWeight(); $replacements = array('@event' => $state); foreach (language_list(Language::STATE_LOCKED) as $locked_language) { diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php index 8b2190d..29b75f0 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php @@ -117,14 +117,14 @@ function testLanguageList() { $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'); diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php index 6cff106..2c843dc 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php @@ -96,7 +96,7 @@ function testInfoAlterations() { // Check language negotiation results. $this->drupalGet(''); $last = \Drupal::state()->get('language_test.language_negotiation_last'); - foreach (language_types_get_all() as $type) { + foreach (Drupal::languageManager()->getLanguageTypes() 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 +107,7 @@ function testInfoAlterations() { $this->languageNegotiationUpdate('uninstall'); // Check that only the core language types are available. - foreach (language_types_get_all() as $type) { + foreach (Drupal::languageManager()->getLanguageTypes() as $type) { $this->assertTrue(strpos($type, 'test') === FALSE, format_string('The %type language is still available', array('%type' => $type))); } diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php index e87a550..414e4a7 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php @@ -106,7 +106,7 @@ function testUILanguageNegotiation() { // 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. @@ -235,7 +235,7 @@ function testUILanguageNegotiation() { } // Unknown language prefix should return 404. - variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_language_negotiation_info()); + variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_negotiation_info()); $this->drupalGet("$langcode_unknown/admin/config", array(), $http_header_browser_fallback); $this->assertResponse(404, "Unknown language path prefix should return 404"); diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php index 07ee9a9..c30f55b 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php @@ -46,8 +46,6 @@ function setUp() { $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'); } /** @@ -119,7 +117,7 @@ function testDomainNameNegotiationPort() { ->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/language_elements_test/language_elements_test.info.yml b/core/modules/language/tests/language_elements_test/language_elements_test.info.yml index 254c5f6..9fc44c1 100644 --- a/core/modules/language/tests/language_elements_test/language_elements_test.info.yml +++ b/core/modules/language/tests/language_elements_test/language_elements_test.info.yml @@ -4,4 +4,4 @@ description: 'Support module for the language form elements tests.' core: 8.x package: Testing version: VERSION -hidden: true +#hidden: true diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module index 33c2b36..3c0fa2e 100644 --- a/core/modules/language/tests/language_test/language_test.module +++ b/core/modules/language/tests/language_test/language_test.module @@ -56,33 +56,6 @@ function language_test_language_types_info_alter(array &$language_types) { } /** - * 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) { @@ -96,16 +69,9 @@ function language_test_language_negotiation_info_alter(array &$negotiation_info) */ function language_test_store_language_negotiation() { $last = array(); - print_r(language_types_get_all()); - foreach (language_types_get_all() as $type) { + print_r(Drupal::languageManager()->getLanguageTypes()); + foreach (Drupal::languageManager()->getLanguageTypes() as $type) { $last[$type] = language($type)->id; } \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 991755e..0000000 --- a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestManager.php +++ /dev/null @@ -1,28 +0,0 @@ -get('language_test.domain')) { - $_SERVER['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 c8b1633..0000000 --- a/core/modules/language/tests/language_test/lib/Drupal/language_test/LanguageTestServiceProvider.php +++ /dev/null @@ -1,36 +0,0 @@ -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 0000000..0f60de1 --- /dev/null +++ b/core/modules/language/tests/language_test/lib/Drupal/language_test/Plugin/LanguageNegotiation/LanguageNegotiationTest.php @@ -0,0 +1,41 @@ +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 c33da33..da63c72 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 @@ protected function translateFilters() { $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) { diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php index 2b53ff3..d5cdd7f 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 @@ function testMachineNameLTR() { $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', @@ -86,7 +85,6 @@ function testContentTypeLanguageConfiguration() { '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}"); @@ -97,7 +95,7 @@ function testContentTypeLanguageConfiguration() { $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); @@ -154,13 +152,12 @@ function testContentTypeDirLang() { $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}"); @@ -224,7 +221,6 @@ function testNodeAdminLanguageFilter() { // 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 06b6ed4..ee2f9a3 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php @@ -230,7 +230,7 @@ function testJavaScriptTranslation() { '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 875741b..9ef468c 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -97,10 +97,10 @@ function testUninstallProcess() { // 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()); + \Drupal::config('system.language.types')->set('configurable', $this->container->get('language_manager')->getTypeDefaults() + array('language_custom' => TRUE))->save(); + variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_negotiation_info()); + variable_set('language_negotiation_' . Language::TYPE_CONTENT, language_negotiation_info()); + variable_set('language_negotiation_' . Language::TYPE_URL, language_negotiation_info()); // Change language negotiation settings. \Drupal::config('language.negotiation') @@ -126,7 +126,7 @@ function testUninstallProcess() { // 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'); + $this->assertTrue(count($this->container->get('language_manager')->getLanguageTypes()) == count($this->container->get('language_manager')->getTypeDefaults()), '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; diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php index d61128d..95c202e 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateBase.php @@ -82,7 +82,7 @@ protected function setTranslationsDirectory($path) { 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 355ccb1..d8a7372 100644 --- a/core/modules/locale/locale.bulk.inc +++ b/core/modules/locale/locale.bulk.inc @@ -19,7 +19,7 @@ * @ingroup forms */ 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/path/lib/Drupal/path/Tests/PathLanguageTest.php b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php index 9e94728..48f7587 100644 --- a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php +++ b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php @@ -84,7 +84,7 @@ function testAliasTranslation() { $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(); @@ -96,7 +96,10 @@ function testAliasTranslation() { $this->drupalGet('fr/' . $edit['path[alias]']); $this->assertText($french_node->label(), '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[$french_node->language()->id])); $this->assertTrue(strpos($url, $edit['path[alias]']), 'URL contains the path alias.'); diff --git a/core/modules/system/language.api.php b/core/modules/system/language.api.php index cfa42ec..a7e6d13 100644 --- a/core/modules/system/language.api.php +++ b/core/modules/system/language.api.php @@ -88,55 +88,6 @@ function hook_language_types_info_alter(array &$language_types) { } /** - * Define language negotiation methods. - * - * @return - * An associative array of language negotiation method definitions. The keys - * are method identifiers, and the values are associative arrays definining - * 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 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 4aa6270..ee4f5c0 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 @@ public function setUp() { $custom_strings[$definition['label']] = $langcode . ' ' . $definition['label']; } variable_set('locale_custom_strings_' . $langcode, array('' => $custom_strings)); + $this->rebuildContainer(); } } 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 48d1e1f..8ce7d1a 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 @@ protected function setUp() { $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 @@ protected function installLanguages() { drupal_unlink($filename); } } + $this->container->get('language_manager')->reset(); } /** diff --git a/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php b/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php index fcae023..e8277c6 100644 --- a/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php +++ b/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php @@ -108,6 +108,7 @@ public function testTourFunctionality() { // Enable Italian language and navigate to it/tour-test1 and verify italian // version of tip is found. language_save(new Language(array('id' => 'it'))); + drupal_rebuild_language_negotiation_settings(); $this->drupalGet('it/tour-test-1'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( diff --git a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php index 8ef55a6..e1f6b7f 100644 --- a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php +++ b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php @@ -285,7 +285,6 @@ function testTranslateOwnContentRole() { * Resets static caches to make the test code match the client-side behavior. */ function resetCaches() { - drupal_static_reset('language_list'); $this->rebuildContainer(); } @@ -319,7 +318,7 @@ function addLanguage($langcode) { $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language')); // Make sure we are not using a stale list. - drupal_static_reset('language_list'); + $this->container->get('language_manager')->reset(); $languages = language_list(); $this->assertTrue(array_key_exists($langcode, $languages), 'Language was installed successfully.'); diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php index f49184f..b29aa18 100644 --- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php +++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorTest.php @@ -46,10 +46,15 @@ public function setUp() { $this->languages = $languages; // Create a language manager stub. - $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager'); + $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager') + ->disableOriginalConstructor() + ->getMock(); $language_manager->expects($this->any()) ->method('getLanguage') ->will($this->returnValue($languages['en'])); + $language_manager->expects($this->any()) + ->method('getLanguageList') + ->will($this->returnValue($this->languages)); $this->languageManager = $language_manager; } @@ -95,7 +100,7 @@ function testProcessInbound() { $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); // 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 3e86b66..0e60267 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php @@ -113,7 +113,9 @@ public function testDefaultPluginManagerWithEmptyCache() { ->with($cid . ':en', $this->expectedDefinitions); $language = new Language(array('id' => 'en')); - $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager'); + $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager') + ->disableOriginalConstructor() + ->getMock(); $language_manager->expects($this->once()) ->method('getLanguage') ->with(Language::TYPE_INTERFACE) @@ -144,7 +146,9 @@ public function testDefaultPluginManagerWithFilledCache() { ->method('set'); $language = new Language(array('id' => 'en')); - $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager'); + $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager') + ->disableOriginalConstructor() + ->getMock(); $language_manager->expects($this->once()) ->method('getLanguage') ->with(Language::TYPE_INTERFACE) @@ -173,7 +177,9 @@ public function testCacheClearWithTags() { ->method('deleteMultiple'); $language = new Language(array('id' => 'en')); - $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager'); + $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager') + ->disableOriginalConstructor() + ->getMock(); $language_manager->expects($this->once()) ->method('getLanguage') ->with(Language::TYPE_INTERFACE) diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php index 6b7334f..3e6c72f 100644 --- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php +++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php @@ -79,7 +79,10 @@ protected function setUp() { $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->getMockBuilder('Drupal\Core\Language\LanguageManager') + ->disableOriginalConstructor() + ->getMock(); + $this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler, $this->languageManager); }