class LanguageNegotiator
Same name in other branches
- 9 core/modules/language/src/LanguageNegotiator.php \Drupal\language\LanguageNegotiator
- 8.9.x core/modules/language/src/LanguageNegotiator.php \Drupal\language\LanguageNegotiator
- 11.x core/modules/language/src/LanguageNegotiator.php \Drupal\language\LanguageNegotiator
Class responsible for performing language negotiation.
Hierarchy
- class \Drupal\language\LanguageNegotiator implements \Drupal\language\LanguageNegotiatorInterface uses \Drupal\Core\Logger\LoggerChannelTrait
Expanded class hierarchy of LanguageNegotiator
1 string reference to 'LanguageNegotiator'
- language.services.yml in core/
modules/ language/ language.services.yml - core/modules/language/language.services.yml
1 service uses LanguageNegotiator
- language_negotiator in core/
modules/ language/ language.services.yml - Drupal\language\LanguageNegotiator
File
-
core/
modules/ language/ src/ LanguageNegotiator.php, line 17
Namespace
Drupal\languageView source
class LanguageNegotiator implements LanguageNegotiatorInterface {
use LoggerChannelTrait;
/**
* The language negotiation method plugin manager.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
*/
protected $negotiatorManager;
/**
* The language manager.
*
* @var \Drupal\language\ConfigurableLanguageManagerInterface
*/
protected $languageManager;
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The settings instance.
*
* @var \Drupal\Core\Site\Settings
*/
protected $settings;
/**
* The request stack object.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The current active user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Local cache for language negotiation method instances.
*
* @var array
*/
protected $methods;
/**
* An array of language objects keyed by method id.
*
* @var \Drupal\Core\Language\LanguageInterface[]
*/
protected $negotiatedLanguages = [];
/**
* Constructs a new LanguageNegotiator object.
*
* @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager
* The language negotiation methods plugin manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Site\Settings $settings
* The settings instance.
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
* The request stack service.
*/
public function __construct(ConfigurableLanguageManagerInterface $language_manager, PluginManagerInterface $negotiator_manager, ConfigFactoryInterface $config_factory, Settings $settings, RequestStack $requestStack) {
$this->languageManager = $language_manager;
$this->negotiatorManager = $negotiator_manager;
$this->configFactory = $config_factory;
$this->settings = $settings;
$this->requestStack = $requestStack;
}
/**
* Initializes the injected language manager with the negotiator.
*
* This should be called right after instantiating the negotiator to make it
* available to the language manager without introducing a circular
* dependency.
*/
public function initLanguageManager() {
$this->languageManager
->setNegotiator($this);
}
/**
* {@inheritdoc}
*/
public function reset() {
$this->negotiatedLanguages = [];
$this->methods = [];
}
/**
* {@inheritdoc}
*/
public function setCurrentUser(AccountInterface $current_user) {
$this->currentUser = $current_user;
$this->reset();
}
/**
* {@inheritdoc}
*/
public function initializeType($type) {
$language = NULL;
if ($this->currentUser) {
// Execute the language negotiation methods in the order they were set up
// and return the first valid language found.
foreach ($this->getEnabledNegotiators($type) as $method_id => $info) {
if (!isset($this->negotiatedLanguages[$method_id])) {
try {
$this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id);
} catch (PluginNotFoundException $e) {
// If a plugin is not found, log the error so user can handle it.
$this->getLogger('language')
->error($e->getMessage());
}
}
// Since objects are references, we need to return a clone to prevent
// the language negotiation method cache from being unintentionally
// altered. The same methods might be used with different language types
// based on configuration.
$language = !empty($this->negotiatedLanguages[$method_id]) ? clone $this->negotiatedLanguages[$method_id] : NULL;
if ($language) {
$this->getNegotiationMethodInstance($method_id)
->persist($language);
break;
}
}
}
if (!$language) {
// If no other language was found use the default one.
$language = $this->languageManager
->getDefaultLanguage();
$method_id = static::METHOD_ID;
}
return [
$method_id => $language,
];
}
/**
* Gets enabled detection methods for the provided language type.
*
* @param string $type
* The language type.
*
* @return array
* An array of enabled detection methods for the provided language type.
*/
protected function getEnabledNegotiators($type) {
return $this->configFactory
->get('language.types')
->get('negotiation.' . $type . '.enabled') ?: [];
}
/**
* 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\LanguageInterface|null
* Negotiated language object for given type and method, FALSE otherwise.
*/
protected function negotiateLanguage($type, $method_id) {
$langcode = NULL;
$method = $this->negotiatorManager
->getDefinition($method_id);
if (!isset($method['types']) || in_array($type, $method['types'])) {
$langcode = $this->getNegotiationMethodInstance($method_id)
->getLangcode($this->requestStack
->getCurrentRequest());
}
$languages = $this->languageManager
->getLanguages();
return $languages[$langcode] ?? NULL;
}
/**
* {@inheritdoc}
*/
public function getNegotiationMethods($type = NULL) {
$definitions = $this->negotiatorManager
->getDefinitions();
if (isset($type)) {
$enabled_methods = $this->getEnabledNegotiators($type);
$definitions = array_intersect_key($definitions, $enabled_methods);
}
return $definitions;
}
/**
* {@inheritdoc}
*/
public function getNegotiationMethodInstance($method_id) {
if (!isset($this->methods[$method_id])) {
$instance = $this->negotiatorManager
->createInstance($method_id, []);
$instance->setLanguageManager($this->languageManager);
$instance->setConfig($this->configFactory);
$instance->setCurrentUser($this->currentUser);
$this->methods[$method_id] = $instance;
}
return $this->methods[$method_id];
}
/**
* {@inheritdoc}
*/
public function getPrimaryNegotiationMethod($type) {
$enabled_methods = $this->getEnabledNegotiators($type);
return empty($enabled_methods) ? LanguageNegotiatorInterface::METHOD_ID : key($enabled_methods);
}
/**
* {@inheritdoc}
*/
public function isNegotiationMethodEnabled($method_id, $type = NULL) {
$enabled = FALSE;
$language_types = !empty($type) ? [
$type,
] : $this->languageManager
->getLanguageTypes();
foreach ($language_types as $type) {
$enabled_methods = $this->getEnabledNegotiators($type);
if (isset($enabled_methods[$method_id])) {
$enabled = TRUE;
break;
}
}
return $enabled;
}
/**
* {@inheritdoc}
*/
public function saveConfiguration($type, $enabled_methods) {
// As configurable language types might have changed, we reset the cache.
$this->languageManager
->reset();
$definitions = $this->getNegotiationMethods();
$default_types = $this->languageManager
->getLanguageTypes();
// Ensure that the weights are integers.
$enabled_methods = array_map('intval', $enabled_methods);
// Order the language negotiation method list by weight.
asort($enabled_methods);
foreach ($enabled_methods as $method_id => $weight) {
if (isset($definitions[$method_id])) {
$method = $definitions[$method_id];
// If the language negotiation method does not express any preference
// about types, make it available for any configurable type.
$types = array_flip(!empty($method['types']) ? $method['types'] : $default_types);
// Check whether the method is defined and has the right type.
if (!isset($types[$type])) {
unset($enabled_methods[$method_id]);
}
}
else {
unset($enabled_methods[$method_id]);
}
}
$this->configFactory
->getEditable('language.types')
->set('negotiation.' . $type . '.enabled', $enabled_methods)
->save(TRUE);
}
/**
* {@inheritdoc}
*/
public function purgeConfiguration() {
// Ensure that we are getting the defined language negotiation information.
// An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or
// \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the
// cached information.
$this->negotiatorManager
->clearCachedDefinitions();
$this->languageManager
->reset();
foreach ($this->languageManager
->getDefinedLanguageTypesInfo() as $type => $info) {
$this->saveConfiguration($type, $this->getEnabledNegotiators($type));
}
}
/**
* {@inheritdoc}
*/
public function updateConfiguration(array $types) {
// Ensure that we are getting the defined language negotiation information.
// An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or
// \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the
// cached information.
$this->negotiatorManager
->clearCachedDefinitions();
$this->languageManager
->reset();
$language_types = [];
$language_types_info = $this->languageManager
->getDefinedLanguageTypesInfo();
$method_definitions = $this->getNegotiationMethods();
foreach ($language_types_info as $type => $info) {
$configurable = in_array($type, $types);
// The default language negotiation settings, if available, are stored in
// $info['fixed'].
$has_default_settings = !empty($info['fixed']);
// Check whether the language type is unlocked. Only the status of
// unlocked language types can be toggled between configurable and
// non-configurable.
if (empty($info['locked'])) {
if (!$configurable && !$has_default_settings) {
// If we have an unlocked non-configurable language type without
// default language negotiation settings, we use the values
// negotiated for the interface language which, should always be
// available.
$method_weights = [
LanguageNegotiationUI::METHOD_ID,
];
$method_weights = array_flip($method_weights);
$this->saveConfiguration($type, $method_weights);
}
}
else {
// The language type is locked. Locked language types with default
// settings are always considered non-configurable. In turn if default
// settings are missing, the language type is always considered
// configurable.
// If the language type is locked we can just store its default language
// negotiation settings if it has some, since it is not configurable.
if ($has_default_settings) {
$method_weights = [];
// Default settings are in $info['fixed'].
foreach ($info['fixed'] as $weight => $method_id) {
if (isset($method_definitions[$method_id])) {
$method_weights[$method_id] = $weight;
}
}
$this->saveConfiguration($type, $method_weights);
}
else {
// It was missing default settings, so force it to be configurable.
$configurable = TRUE;
}
}
// Accumulate information for each language type so it can be saved later.
$language_types[$type] = $configurable;
}
// Store the language type configuration.
$config = [
'configurable' => array_keys(array_filter($language_types)),
'all' => array_keys($language_types),
];
$this->languageManager
->saveLanguageTypesConfiguration($config);
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
LanguageNegotiator::$configFactory | protected | property | The configuration factory. |
LanguageNegotiator::$currentUser | protected | property | The current active user. |
LanguageNegotiator::$languageManager | protected | property | The language manager. |
LanguageNegotiator::$methods | protected | property | Local cache for language negotiation method instances. |
LanguageNegotiator::$negotiatedLanguages | protected | property | An array of language objects keyed by method id. |
LanguageNegotiator::$negotiatorManager | protected | property | The language negotiation method plugin manager. |
LanguageNegotiator::$requestStack | protected | property | The request stack object. |
LanguageNegotiator::$settings | protected | property | The settings instance. |
LanguageNegotiator::getEnabledNegotiators | protected | function | Gets enabled detection methods for the provided language type. |
LanguageNegotiator::getNegotiationMethodInstance | public | function | |
LanguageNegotiator::getNegotiationMethods | public | function | |
LanguageNegotiator::getPrimaryNegotiationMethod | public | function | |
LanguageNegotiator::initializeType | public | function | |
LanguageNegotiator::initLanguageManager | public | function | Initializes the injected language manager with the negotiator. |
LanguageNegotiator::isNegotiationMethodEnabled | public | function | |
LanguageNegotiator::negotiateLanguage | protected | function | Performs language negotiation using the specified negotiation method. |
LanguageNegotiator::purgeConfiguration | public | function | |
LanguageNegotiator::reset | public | function | |
LanguageNegotiator::saveConfiguration | public | function | |
LanguageNegotiator::setCurrentUser | public | function | |
LanguageNegotiator::updateConfiguration | public | function | |
LanguageNegotiator::__construct | public | function | Constructs a new LanguageNegotiator object. |
LoggerChannelTrait::$loggerFactory | protected | property | The logger channel factory service. |
LoggerChannelTrait::getLogger | protected | function | Gets the logger for a specific channel. |
LoggerChannelTrait::setLoggerFactory | public | function | Injects the logger channel factory. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.