Issue #1899994 by katbailey, plach, YesCT: Disentangle language initialization from path resolution.

8.0.x
Dries 2013-02-01 15:29:29 -05:00
parent cf8827418e
commit 3e478b0362
21 changed files with 342 additions and 192 deletions

View File

@ -2744,73 +2744,29 @@ function get_t() {
* @see language() * @see language()
*/ */
function drupal_language_initialize() { function drupal_language_initialize() {
if (language_multilingual()) { drupal_container()->get('language_manager')->init();
$types = language_types_get_all();
foreach ($types as $type) {
language($type);
}
// Allow modules to react on language system initialization in multilingual
// environments.
bootstrap_invoke_all('language_init');
// @todo D8: Remove after http://drupal.org/node/1859110.
drupal_container()->get('config.factory')->reset();
}
} }
/** /**
* Returns the language object for a given language type. * Returns the language object for a given language type.
* *
* The 'language_manager' service is only available within the scope of a kernel
* request. When it's not available, we return a default language object,
* regardless of the type passed in.
*
* @see Drupal\Core\Language\LanguageManager * @see Drupal\Core\Language\LanguageManager
* *
* @param string $type * @param string $type
* The type of language object needed, e.g. LANGUAGE_TYPE_INTERFACE. * The type of language object needed, e.g. LANGUAGE_TYPE_INTERFACE.
* @param bool $reset
* TRUE to reset the statically cached language object for the type, or for
* all types if $type is NULL.
*/ */
function language($type, $reset = FALSE) { function language($type) {
// We don't use drupal_static() here because resetting is not a simple case of $container = drupal_container();
// drupal_static_reset(). if (!$container) {
static $languages = array(); return language_default();
// Reset the language manager's cache and our own.
if ($reset) {
if (drupal_container()->isScopeActive('request')) {
drupal_container()->get('language_manager')->reset($type);
}
if (!isset($type)) {
$languages = array();
}
elseif (isset($languages[$type])) {
unset($languages[$type]);
}
} }
if (!$container->has('language_manager')) {
// If no type is passed (most likely when resetting all types), return. // This happens in rare situations when the container has not been built by
if (!isset($type)) { // a kernel and has no services, e.g., when t() is called during unit tests
return; // for assertions.
} $container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
// When the language_manager service exists (is both defined and the 'request'
// scope is active in the container), use it to get the language. Otherwise
// return the default language.
if (drupal_container()->isScopeActive('request')) {
$language_manager = drupal_container()->get('language_manager', Container::NULL_ON_INVALID_REFERENCE);
}
if (isset($language_manager)) {
return $language_manager->getLanguage($type);
}
else {
if (!isset($languages[$type])) {
$languages[$type] = language_default();
}
return $languages[$type];
} }
return $container->get('language_manager')->getLanguage($type);
} }
/** /**
@ -3015,6 +2971,24 @@ function language_default() {
return new Language($info); return new Language($info);
} }
/**
* Stores or retrieves the path derived during language negotiation.
*
* @param string $new_path
* The altered path.
*
* @todo Replace this with a path processor in language module. See
* http://drupal.org/node/1888424.
*/
function _language_resolved_path($new_path = NULL) {
$path = &drupal_static(__FUNCTION__, NULL);
if ($new_path === NULL) {
return $path;
}
$path = $new_path;
return $path;
}
/** /**
* Returns the requested URL path of the page being viewed. * Returns the requested URL path of the page being viewed.
* *

View File

@ -339,6 +339,9 @@ function install_begin_request(&$install_state) {
->addArgument(new Reference('config.storage')) ->addArgument(new Reference('config.storage'))
->addArgument(new Reference('event_dispatcher')); ->addArgument(new Reference('event_dispatcher'));
// Register the 'language_manager' service.
$container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
// The install process cannot use the database lock backend since the database // The install process cannot use the database lock backend since the database
// is not fully up, so we use a null backend implementation during the // is not fully up, so we use a null backend implementation during the
// installation process. This will also speed up the installation process. // installation process. This will also speed up the installation process.

View File

@ -98,7 +98,8 @@ class CoreBundle extends Bundle {
$container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager') $container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager')
->addArgument(new Reference('database')) ->addArgument(new Reference('database'))
->addArgument(new Reference('keyvalue')); ->addArgument(new Reference('state'))
->addArgument(new Reference('language_manager'));
$container->register('http_client_simpletest_subscriber', 'Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber'); $container->register('http_client_simpletest_subscriber', 'Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber');
$container->register('http_default_client', 'Guzzle\Http\Client') $container->register('http_default_client', 'Guzzle\Http\Client')
@ -142,9 +143,10 @@ class CoreBundle extends Bundle {
->addArgument(new Reference('event_dispatcher')) ->addArgument(new Reference('event_dispatcher'))
->addArgument(new Reference('service_container')) ->addArgument(new Reference('service_container'))
->addArgument(new Reference('controller_resolver')); ->addArgument(new Reference('controller_resolver'));
$container->register('language_manager', 'Drupal\Core\Language\LanguageManager')
->addArgument(new Reference('request')) // Register the 'language_manager' service.
->setScope('request'); $container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
$container->register('database.slave', 'Drupal\Core\Database\Connection') $container->register('database.slave', 'Drupal\Core\Database\Connection')
->setFactoryClass('Drupal\Core\Database\Database') ->setFactoryClass('Drupal\Core\Database\Database')
->setFactoryMethod('getConnection') ->setFactoryMethod('getConnection')
@ -245,6 +247,9 @@ class CoreBundle extends Bundle {
->addTag('event_subscriber'); ->addTag('event_subscriber');
$container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber') $container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber')
->addTag('event_subscriber'); ->addTag('event_subscriber');
$container->register('language_request_subscriber', 'Drupal\Core\EventSubscriber\LanguageRequestSubscriber')
->addArgument(new Reference('language_manager'))
->addTag('event_subscriber');
$container->register('exception_controller', 'Drupal\Core\ExceptionController') $container->register('exception_controller', 'Drupal\Core\ExceptionController')
->addArgument(new Reference('content_negotiation')) ->addArgument(new Reference('content_negotiation'))

View File

@ -0,0 +1,63 @@
<?php
/**
* @file
* Contains \Drupal\Core\EventSubscriber\LanguageRequestSubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Language\LanguageManager;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Sets the $request property on the language manager.
*/
class LanguageRequestSubscriber implements EventSubscriberInterface {
/**
* The language manager service.
*
* @var \Drupal\Core\Language\LanguageManager
*/
protected $languageManager;
/**
* Constructs a LanguageRequestSubscriber object.
*
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager service.
*
*/
public function __construct(LanguageManager $language_manager) {
$this->languageManager = $language_manager;
}
/**
* Sets the request on the language manager.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
public function onKernelRequestLanguage(GetResponseEvent $event) {
if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
$this->languageManager->setRequest($event->getRequest());
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onKernelRequestLanguage', 300);
return $events;
}
}

View File

@ -77,22 +77,15 @@ class PathSubscriber extends PathListenerBase implements EventSubscriberInterfac
/** /**
* Decode language information embedded in the request path. * Decode language information embedded in the request path.
* *
* @todo Refactor this entire method to inline the relevant portions of
* drupal_language_initialize(). See the inline comment for more details.
*
* @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process. * The Event to process.
*/ */
public function onKernelRequestLanguageResolve(GetResponseEvent $event) { public function onKernelRequestLanguageResolve(GetResponseEvent $event) {
// drupal_language_initialize() combines: $request = $event->getRequest();
// - Determination of language from $request information (e.g., path). $path = _language_resolved_path();
// - Determination of language from other information (e.g., site default). if ($path !== NULL) {
// - Population of determined language into drupal_container(). $this->setPath($request, $path);
// - Removal of language code from _current_path(). }
// @todo Decouple the above, but for now, invoke it and update the path
// prior to front page and alias resolution. When above is decoupled, also
// add 'langcode' (determined from $request only) to $request->attributes.
drupal_language_initialize();
} }
/** /**

View File

@ -2,7 +2,7 @@
/** /**
* @file * @file
* Definition of Drupal\Core\Language\LanguageManager. * Contains \Drupal\Core\Language\LanguageManager.
*/ */
namespace Drupal\Core\Language; namespace Drupal\Core\Language;
@ -11,43 +11,158 @@ use Symfony\Component\HttpFoundation\Request;
/** /**
* Class responsible for initializing each language type. * Class responsible for initializing each language type.
*
* This service is dependent on the 'request' service and can therefore pass the
* Request object to the code that deals with each particular language type.
* This means the Request can be used directly for things like URL-based
* language negotiation.
*/ */
class LanguageManager { class LanguageManager {
private $request; /**
private $languages; * A request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
public function __construct(Request $request = NULL) { /**
$this->request = $request; * An array of language objects keyed by language type.
*
* @var array
*/
protected $languages;
/**
* Whether or not the language manager has been initialized.
*
* @var bool
*/
protected $initialized = FALSE;
/**
* 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;
/**
* Initializes each language type to a language object.
*/
public function init() {
if ($this->initialized) {
return;
}
if ($this->isMultilingual()) {
foreach ($this->getLanguageTypes() as $type) {
$this->getLanguage($type);
}
}
$this->initialized = TRUE;
} }
/**
* Sets the $request property and resets all language types.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HttpRequest object representing the current request.
*/
public function setRequest(Request $request) {
$this->request = $request;
$this->reset();
$this->init();
}
/**
* Returns a language object for the given type.
*
* @param string $type
* The language type, e.g. LANGUAGE_TYPE_INTERFACE.
*
* @return \Drupal\Core\Language\Language
* A language object for the given type.
*/
public function getLanguage($type) { public function getLanguage($type) {
if (isset($this->languages[$type])) { if (isset($this->languages[$type])) {
return $this->languages[$type]; return $this->languages[$type];
} }
// @todo Objectify the language system so that we don't have to do this. if ($this->isMultilingual() && $this->request) {
if (language_multilingual()) { if (!$this->initializing) {
include_once DRUPAL_ROOT . '/core/includes/language.inc'; $this->initializing = TRUE;
$this->languages[$type] = language_types_initialize($type, $this->request); // @todo Objectify the language system so that we don't have to load an
// include file and call out to procedural code. See
// http://drupal.org/node/1862202
include_once DRUPAL_ROOT . '/core/includes/language.inc';
$this->languages[$type] = language_types_initialize($type, $this->request);
$this->initializing = FALSE;
}
else {
// Config has called getLanguage() during initialization of a language
// type. Simply return the default language without setting it on the
// $this->languages property. See the TODO in the docblock for the
// $initializing property.
return $this->getLanguageDefault();
}
} }
else { else {
$this->languages[$type] = language_default(); $this->languages[$type] = $this->getLanguageDefault();
} }
return $this->languages[$type]; return $this->languages[$type];
} }
/**
* Resets the given language type or all types if none specified.
*
* @param string|null $type
* (optional) The language type to reset as a string, e.g.,
* LANGUAGE_TYPE_INTERFACE, or NULL to reset all language types. Defaults to
* NULL.
*/
public function reset($type = NULL) { public function reset($type = NULL) {
if (!isset($type)) { if (!isset($type)) {
$this->languages = array(); $this->languages = array();
$this->initialized = FALSE;
} }
elseif (isset($this->languages[$type])) { elseif (isset($this->languages[$type])) {
unset($this->languages[$type]); unset($this->languages[$type]);
} }
} }
/**
* Returns whether or not the site has more than one language enabled.
*
* @return bool
* TRUE if more than one language is enabled, FALSE otherwise.
*/
protected function isMultilingual() {
return variable_get('language_count', 1) > 1;
}
/**
* Returns an array of the available language types.
*
* @return array()
* An array of all language types.
*/
protected function getLanguageTypes() {
return array_keys(variable_get('language_types', language_types_get_default()));
}
/**
* Returns a language object representing the site's default language.
*
* @return Drupal\Core\Language\Language
* A language object.
*/
protected function getLanguageDefault() {
$default_info = variable_get('language_default', array(
'langcode' => 'en',
'name' => 'English',
'direction' => 0,
'weight' => 0,
'locked' => 0,
));
return new Language($default_info + array('default' => TRUE));
}
} }

View File

@ -8,7 +8,8 @@
namespace Drupal\Core\Path; namespace Drupal\Core\Path;
use Drupal\Core\Database\Connection; use Drupal\Core\Database\Connection;
use Drupal\Core\KeyValueStore\KeyValueFactory; use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\Core\Language\LanguageManager;
class AliasManager implements AliasManagerInterface { class AliasManager implements AliasManagerInterface {
@ -27,11 +28,11 @@ class AliasManager implements AliasManagerInterface {
protected $state; protected $state;
/** /**
* The default langcode to use when none is specified for path lookups. * Language manager for retrieving the default langcode when none is specified.
* *
* @var string * @var \Drupal\Core\Language\LanguageManager
*/ */
protected $langcode; protected $languageManager;
/** /**
* Holds the map of path lookups per language. * Holds the map of path lookups per language.
@ -78,11 +79,12 @@ class AliasManager implements AliasManagerInterface {
*/ */
protected $preloadedPathLookups = array(); protected $preloadedPathLookups = array();
public function __construct(Connection $connection, KeyValueFactory $keyvalue) { public function __construct(Connection $connection, KeyValueStoreInterface $state, LanguageManager $language_manager) {
$this->connection = $connection; $this->connection = $connection;
$this->state = $keyvalue->get('state'); $this->state = $state;
$this->langcode = language(LANGUAGE_TYPE_URL)->langcode; $this->languageManager = $language_manager;
$this->whitelist = $this->state->get('system.path_alias_whitelist', NULL); $this->whitelist = $this->state->get('system.path_alias_whitelist', NULL);
if (!isset($this->whitelist)) { if (!isset($this->whitelist)) {
$this->whitelist = $this->pathAliasWhitelistRebuild(); $this->whitelist = $this->pathAliasWhitelistRebuild();
} }
@ -96,7 +98,7 @@ class AliasManager implements AliasManagerInterface {
// language. If we used a language different from the one conveyed by the // language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path // requested URL, we might end up being unable to check if there is a path
// alias matching the URL path. // alias matching the URL path.
$path_language = $path_language ?: $this->langcode; $path_language = $path_language ?: $this->languageManager->getLanguage(LANGUAGE_TYPE_URL)->langcode;
$original_path = $path; $original_path = $path;
// Lookup the path alias first. // Lookup the path alias first.
if (!empty($path) && $source = $this->lookupPathSource($path, $path_language)) { if (!empty($path) && $source = $this->lookupPathSource($path, $path_language)) {
@ -114,7 +116,7 @@ class AliasManager implements AliasManagerInterface {
// language. If we used a language different from the one conveyed by the // language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path // requested URL, we might end up being unable to check if there is a path
// alias matching the URL path. // alias matching the URL path.
$path_language = $path_language ?: $this->langcode; $path_language = $path_language ?: $this->languageManager->getLanguage(LANGUAGE_TYPE_URL)->langcode;
$result = $path; $result = $path;
if (!empty($path) && $alias = $this->lookupPathAlias($path, $path_language)) { if (!empty($path) && $alias = $this->lookupPathAlias($path, $path_language)) {
$result = $alias; $result = $alias;

View File

@ -33,10 +33,6 @@ class LocaleConfigOverride extends WebTestBase {
$name = 'config_test.system'; $name = 'config_test.system';
// Verify the default configuration values exist. // Verify the default configuration values exist.
$config = config($name); $config = config($name);
$this->assertIdentical($config->get('foo'), 'bar');
// Spoof multilingual.
$GLOBALS['conf']['language_count'] = 2;
drupal_language_initialize();
$this->assertIdentical($config->get('foo'), 'en bar'); $this->assertIdentical($config->get('foo'), 'en bar');
} }
} }

View File

@ -507,7 +507,6 @@ function language_save($language) {
if (!empty($language->default)) { if (!empty($language->default)) {
// Set the new version of this language as default in a variable. // Set the new version of this language as default in a variable.
$default_language = language_default();
variable_set('language_default', (array) $language); variable_set('language_default', (array) $language);
} }

View File

@ -1,5 +1,7 @@
<?php <?php
use \Symfony\Component\HttpFoundation\Request;
/** /**
* @file * @file
* Language negotiation functions. * Language negotiation functions.
@ -206,14 +208,19 @@ function language_from_user($languages) {
* @param $languages * @param $languages
* An array of valid language objects. * 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 * @return
* A valid language code on success, FALSE otherwise. * A valid language code on success, FALSE otherwise.
*/ */
function language_from_user_admin($languages) { function language_from_user_admin(array $languages, Request $request = NULL) {
// User preference (only for authenticated users). // User preference (only for authenticated users).
global $user; global $user;
if ($user->uid && !empty($user->preferred_admin_langcode) && isset($languages[$user->preferred_admin_langcode]) && path_is_admin(current_path())) { $request_path = $request ? urldecode(trim($request->getPathInfo(), '/')) : _current_path();
if ($user->uid && !empty($user->preferred_admin_langcode) && isset($languages[$user->preferred_admin_langcode]) && path_is_admin($request_path)) {
return $user->preferred_admin_langcode; return $user->preferred_admin_langcode;
} }
@ -257,31 +264,29 @@ function language_from_session($languages) {
* @param $languages * @param $languages
* An array of valid language objects. * An array of valid language objects.
* *
* @param $request * @param \Symfony\Component\HttpFoundation\Request|null $request
* The HttpRequest object representing the current request. * (optional) The HttpRequest object representing the current request.
* Defaults to NULL.
* *
* @return * @return
* A valid language code on success, FALSE otherwise. * A valid language code on success, FALSE otherwise.
*/ */
function language_from_url($languages, $request) { function language_from_url($languages, Request $request = NULL) {
$language_url = FALSE; $language_url = FALSE;
if (!language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_URL)) { if (!language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_URL) || !$request) {
return $language_url; return $language_url;
} }
switch (config('language.negotiation')->get('url.source')) { switch (config('language.negotiation')->get('url.source')) {
case LANGUAGE_NEGOTIATION_URL_PREFIX: case LANGUAGE_NEGOTIATION_URL_PREFIX:
$current_path = $request->attributes->get('system_path'); $request_path = urldecode(trim($request->getPathInfo(), '/'));
if (!isset($current_path)) {
$current_path = trim($request->getPathInfo(), '/');
}
list($language, $path) = language_url_split_prefix($current_path, $languages); list($language, $path) = language_url_split_prefix($request_path, $languages);
// Store the correct system path, i.e. minus the path prefix, in the // Store the correct system path, i.e., the request path without the
// request. // language prefix.
$request->attributes->set('system_path', $path); _language_resolved_path($path);
if ($language !== FALSE) { if ($language !== FALSE) {
$language_url = $language->langcode; $language_url = $language->langcode;

View File

@ -35,7 +35,7 @@ class LanguageDependencyInjectionTest extends WebTestBase {
parent::setUp(); parent::setUp();
// Ensure we are building a new Language object for each test. // Ensure we are building a new Language object for each test.
language(NULL, TRUE); $this->container->get('language_manager')->reset();
} }

View File

@ -369,6 +369,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
if (!empty($test['language_test_domain'])) { if (!empty($test['language_test_domain'])) {
state()->set('language_test.domain', $test['language_test_domain']); state()->set('language_test.domain', $test['language_test_domain']);
} }
$this->container->get('language_manager')->reset();
$this->drupalGet($test['path'], array(), $test['http_header']); $this->drupalGet($test['path'], array(), $test['http_header']);
$this->assertText($test['expect'], $test['message']); $this->assertText($test['expect'], $test['message']);
$this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id']))); $this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id'])));

View File

@ -0,0 +1,28 @@
<?php
/**
* @file
* Contains \Drupal\locale\LocaleBundle.
*/
namespace Drupal\locale;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Registers locale module's services to the container.
*/
class LocaleBundle extends Bundle {
/**
* Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
*/
public function build(ContainerBuilder $container) {
$container->register('locale_config_subscriber', 'Drupal\locale\LocaleConfigSubscriber')
->addArgument(new Reference('language_manager'))
->addTag('event_subscriber');
}
}

View File

@ -9,6 +9,7 @@ namespace Drupal\locale;
use Drupal\Core\Config\Config; use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigEvent; use Drupal\Core\Config\ConfigEvent;
use Drupal\Core\Config\StorageDispatcher; use Drupal\Core\Config\StorageDispatcher;
use Drupal\Core\Language\LanguageManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -18,6 +19,24 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
* $config is always a DrupalConfig object. * $config is always a DrupalConfig object.
*/ */
class LocaleConfigSubscriber implements EventSubscriberInterface { class LocaleConfigSubscriber implements EventSubscriberInterface {
/**
* The language manager for retrieving the interface language.
*
* @var \Drupal\Core\Language\LanguageManager
*/
protected $languageManager;
/**
* Constructs a LocaleConfigSubscriber object.
*
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager service.
*/
public function __construct(LanguageManager $language_manager) {
$this->languageManager = $language_manager;
}
/** /**
* Override configuration values with localized data. * Override configuration values with localized data.
* *
@ -26,7 +45,7 @@ class LocaleConfigSubscriber implements EventSubscriberInterface {
*/ */
public function configLoad(ConfigEvent $event) { public function configLoad(ConfigEvent $event) {
$config = $event->getConfig(); $config = $event->getConfig();
$language = language(LANGUAGE_TYPE_INTERFACE); $language = $this->languageManager->getLanguage(LANGUAGE_TYPE_INTERFACE);
$locale_name = $this->getLocaleConfigName($config->getName(), $language); $locale_name = $this->getLocaleConfigName($config->getName(), $language);
if ($override = $config->getStorage()->read($locale_name)) { if ($override = $config->getStorage()->read($locale_name)) {
$config->setOverride($override); $config->setOverride($override);

View File

@ -56,10 +56,12 @@ class LocaleUninstallTest extends WebTestBase {
'default' => $this->langcode == 'fr', 'default' => $this->langcode == 'fr',
)); ));
language_save($language); language_save($language);
// Reset statically cached language objects. // Reset the language manager.
language(NULL, TRUE); $language_manager = $this->container->get('language_manager');
$language_manager->reset();
$language_manager->init();
// Check the UI language. // Check the UI language.
drupal_language_initialize();
$this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode))); $this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode)));
// Enable multilingual workflow option for articles. // Enable multilingual workflow option for articles.
@ -101,13 +103,11 @@ class LocaleUninstallTest extends WebTestBase {
// Uninstall Locale. // Uninstall Locale.
module_disable($locale_module); module_disable($locale_module);
module_uninstall($locale_module); module_uninstall($locale_module);
$this->rebuildContainer();
// Visit the front page. // Visit the front page.
$this->drupalGet(''); $this->drupalGet('');
// Reset statically cached language objects.
language(NULL, TRUE);
// Check the init language logic. // Check the init language logic.
drupal_language_initialize();
$this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, 'en', t('Language after uninstall: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode))); $this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, 'en', t('Language after uninstall: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode)));
// Check JavaScript files deletion. // Check JavaScript files deletion.

View File

@ -1303,11 +1303,3 @@ function _locale_rebuild_js($langcode = NULL) {
return TRUE; return TRUE;
} }
} }
/**
* Implements hook_language_init().
*/
function locale_language_init() {
// Add locale helper to configuration subscribers.
drupal_container()->get('event_dispatcher')->addSubscriber(new LocaleConfigSubscriber());
}

View File

@ -1025,13 +1025,6 @@ abstract class TestBase {
// this second reset is guranteed to reset everything to nothing. // this second reset is guranteed to reset everything to nothing.
drupal_static_reset(); drupal_static_reset();
// Reset static in language().
// Restoring drupal_container() makes language() return the proper languages
// already, but it contains an additional static that needs to be reset. The
// reset can happen before the container is restored, as it is unnecessary
// to reset the language_manager service.
language(NULL, TRUE);
// Restore original in-memory configuration. // Restore original in-memory configuration.
$conf = $this->originalConf; $conf = $this->originalConf;
new Settings($this->originalSettings); new Settings($this->originalSettings);

View File

@ -10,33 +10,6 @@
* @{ * @{
*/ */
/**
* Allows modules to act after language initialization has been performed.
*
* This is primarily needed to provide translation for configuration variables
* in the proper bootstrap phase. Variables are user-defined strings and
* therefore should not be translated via t(), since the source string can
* change without notice and any previous translation would be lost. Moreover,
* since variables can be used in the bootstrap phase, we need a bootstrap hook
* to provide a translation early enough to avoid misalignments between code
* using the original values and code using the translated values. However
* modules implementing hook_boot() should be aware that language initialization
* did not happen yet and thus they cannot rely on translated variables.
*/
function hook_language_init() {
global $conf;
switch (language(LANGUAGE_TYPE_INTERFACE)->langcode) {
case 'it':
$conf['system.site']['name'] = 'Il mio sito Drupal';
break;
case 'fr':
$conf['system.site']['name'] = 'Mon site Drupal';
break;
}
}
/** /**
* Perform alterations on language switcher links. * Perform alterations on language switcher links.
* *

View File

@ -43,7 +43,7 @@ class AliasTest extends DrupalUnitTestBase {
$this->fixtures->createTables($connection); $this->fixtures->createTables($connection);
//Create AliasManager and Path object. //Create AliasManager and Path object.
$aliasManager = new AliasManager($connection, $this->container->get('keyvalue')); $aliasManager = new AliasManager($connection, $this->container->get('state'), $this->container->get('language_manager'));
$path = new Path($connection, $aliasManager); $path = new Path($connection, $aliasManager);
$aliases = $this->fixtures->sampleUrlAliases(); $aliases = $this->fixtures->sampleUrlAliases();
@ -96,7 +96,7 @@ class AliasTest extends DrupalUnitTestBase {
$this->fixtures->createTables($connection); $this->fixtures->createTables($connection);
//Create AliasManager and Path object. //Create AliasManager and Path object.
$aliasManager = new AliasManager($connection, $this->container->get('keyvalue')); $aliasManager = new AliasManager($connection, $this->container->get('state'), $this->container->get('language_manager'));
$pathObject = new Path($connection, $aliasManager); $pathObject = new Path($connection, $aliasManager);
// Test the situation where the source is the same for multiple aliases. // Test the situation where the source is the same for multiple aliases.

View File

@ -37,21 +37,21 @@ class DateUpgradePathTest extends UpgradePathTestBase {
$expected_formats['short'] = array( $expected_formats['short'] = array(
'name' => 'Short', 'name' => 'Short',
'pattern' => array( 'pattern' => array(
'php' => 'Y/m/d - H:i', 'php' => 'm/d/Y - H:i',
), ),
'locked' => '1', 'locked' => '1',
); );
$expected_formats['medium'] = array( $expected_formats['medium'] = array(
'name' => 'Medium', 'name' => 'Medium',
'pattern' => array( 'pattern' => array(
'php' => 'D, d/m/Y - H:i', 'php' => 'D, m/d/Y - H:i',
), ),
'locked' => '1', 'locked' => '1',
); );
$expected_formats['long'] = array( $expected_formats['long'] = array(
'name' => 'Long', 'name' => 'Long',
'pattern' => array( 'pattern' => array(
'php' => 'l, Y, F j - H:i', 'php' => 'l, j F, Y - H:i',
), ),
'locked' => '1', 'locked' => '1',
); );
@ -76,43 +76,24 @@ class DateUpgradePathTest extends UpgradePathTestBase {
$this->assertNull(update_variable_get('date_format_' . $type), format_string('Date format variable for @type was deleted.', array('@type' => $type))); $this->assertNull(update_variable_get('date_format_' . $type), format_string('Date format variable for @type was deleted.', array('@type' => $type)));
} }
$expected_locale_formats = array( $expected_de_formats = array(
array( array(
'langcode' => 'en',
'type' => 'long',
'format' => 'l, j F, Y - H:i',
),
array(
'langcode' => 'en',
'type' => 'medium',
'format' => 'D, m/d/Y - H:i',
),
array(
'langcode' => 'en',
'type' => 'short',
'format' => 'm/d/Y - H:i',
),
array(
'langcode' => 'de',
'type' => 'long', 'type' => 'long',
'format' => 'l, j. F, Y - H:i', 'format' => 'l, j. F, Y - H:i',
), ),
array( array(
'langcode' => 'de',
'type' => 'medium', 'type' => 'medium',
'format' => 'D, d/m/Y - H:i', 'format' => 'D, d/m/Y - H:i',
), ),
array( array(
'langcode' => 'de',
'type' => 'short', 'type' => 'short',
'format' => 'd/m/Y - H:i', 'format' => 'd/m/Y - H:i',
), ),
); );
$config['en'] = config('locale.config.en.system.date'); $config = config('locale.config.de.system.date');
$config['de'] = config('locale.config.de.system.date'); foreach ($expected_de_formats as $locale_format) {
foreach ($expected_locale_formats as $locale_format) { $format = $config->get('formats.' . $locale_format['type'] . '.pattern.php');
$format = $config[$locale_format['langcode']]->get('formats.' . $locale_format['type'] . '.pattern.php');
$this->assertEqual($locale_format['format'], $format); $this->assertEqual($locale_format['format'], $format);
} }
} }

View File

@ -126,6 +126,13 @@ abstract class UpgradePathTestBase extends WebTestBase {
drupal_save_session(FALSE); drupal_save_session(FALSE);
// Login as uid 1. // Login as uid 1.
$user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject(); $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject();
// Load roles for the user object.
$roles = array(DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID);
$result = db_query('SELECT rid, uid FROM {users_roles} WHERE uid = :uid', array(':uid' => 1));
foreach ($result as $record) {
$roles[$record->rid] = $record->rid;
}
$user->roles = $roles;
// Generate and set a D8-compatible session cookie. // Generate and set a D8-compatible session cookie.
$this->prepareD8Session(); $this->prepareD8Session();
@ -288,6 +295,7 @@ abstract class UpgradePathTestBase extends WebTestBase {
* @see WebTestBase::drupalGet() * @see WebTestBase::drupalGet()
*/ */
protected function getUpdatePhp() { protected function getUpdatePhp() {
$this->rebuildContainer();
$path = $GLOBALS['base_url'] . '/core/update.php'; $path = $GLOBALS['base_url'] . '/core/update.php';
$out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $path, CURLOPT_NOBODY => FALSE)); $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $path, CURLOPT_NOBODY => FALSE));
// Ensure that any changes to variables in the other thread are picked up. // Ensure that any changes to variables in the other thread are picked up.