Chris@0: languageManager = $language_manager; Chris@0: $this->negotiatorManager = $negotiator_manager; Chris@0: $this->configFactory = $config_factory; Chris@0: $this->settings = $settings; Chris@0: $this->requestStack = $requestStack; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Initializes the injected language manager with the negotiator. Chris@0: * Chris@0: * This should be called right after instantiating the negotiator to make it Chris@0: * available to the language manager without introducing a circular Chris@0: * dependency. Chris@0: */ Chris@0: public function initLanguageManager() { Chris@0: $this->languageManager->setNegotiator($this); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function reset() { Chris@0: $this->negotiatedLanguages = []; Chris@0: $this->methods = []; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setCurrentUser(AccountInterface $current_user) { Chris@0: $this->currentUser = $current_user; Chris@0: $this->reset(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function initializeType($type) { Chris@0: $language = NULL; Chris@0: Chris@0: if ($this->currentUser) { Chris@0: // Execute the language negotiation methods in the order they were set up Chris@0: // and return the first valid language found. Chris@0: foreach ($this->getEnabledNegotiators($type) as $method_id => $info) { Chris@0: if (!isset($this->negotiatedLanguages[$method_id])) { Chris@0: $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id); Chris@0: } Chris@0: Chris@0: // Since objects are references, we need to return a clone to prevent Chris@0: // the language negotiation method cache from being unintentionally Chris@0: // altered. The same methods might be used with different language types Chris@0: // based on configuration. Chris@0: $language = !empty($this->negotiatedLanguages[$method_id]) ? clone($this->negotiatedLanguages[$method_id]) : NULL; Chris@0: Chris@0: if ($language) { Chris@0: $this->getNegotiationMethodInstance($method_id)->persist($language); Chris@0: break; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: if (!$language) { Chris@0: // If no other language was found use the default one. Chris@0: $language = $this->languageManager->getDefaultLanguage(); Chris@0: $method_id = static::METHOD_ID; Chris@0: } Chris@0: Chris@0: return [$method_id => $language]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets enabled detection methods for the provided language type. Chris@0: * Chris@0: * @param string $type Chris@0: * The language type. Chris@0: * Chris@0: * @return array Chris@0: * An array of enabled detection methods for the provided language type. Chris@0: */ Chris@0: protected function getEnabledNegotiators($type) { Chris@0: return $this->configFactory->get('language.types')->get('negotiation.' . $type . '.enabled') ?: []; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Performs language negotiation using the specified negotiation method. Chris@0: * Chris@0: * @param string $type Chris@0: * The language type to be initialized. Chris@0: * @param string $method_id Chris@0: * The string identifier of the language negotiation method to use to detect Chris@0: * language. Chris@0: * Chris@0: * @return \Drupal\Core\Language\LanguageInterface|null Chris@0: * Negotiated language object for given type and method, FALSE otherwise. Chris@0: */ Chris@0: protected function negotiateLanguage($type, $method_id) { Chris@0: $langcode = NULL; Chris@0: $method = $this->negotiatorManager->getDefinition($method_id); Chris@0: Chris@0: if (!isset($method['types']) || in_array($type, $method['types'])) { Chris@0: $langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->requestStack->getCurrentRequest()); Chris@0: } Chris@0: Chris@0: $languages = $this->languageManager->getLanguages(); Chris@0: return isset($languages[$langcode]) ? $languages[$langcode] : NULL; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getNegotiationMethods($type = NULL) { Chris@0: $definitions = $this->negotiatorManager->getDefinitions(); Chris@0: if (isset($type)) { Chris@0: $enabled_methods = $this->getEnabledNegotiators($type); Chris@0: $definitions = array_intersect_key($definitions, $enabled_methods); Chris@0: } Chris@0: return $definitions; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getNegotiationMethodInstance($method_id) { Chris@0: if (!isset($this->methods[$method_id])) { Chris@0: $instance = $this->negotiatorManager->createInstance($method_id, []); Chris@0: $instance->setLanguageManager($this->languageManager); Chris@0: $instance->setConfig($this->configFactory); Chris@0: $instance->setCurrentUser($this->currentUser); Chris@0: $this->methods[$method_id] = $instance; Chris@0: } Chris@0: return $this->methods[$method_id]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getPrimaryNegotiationMethod($type) { Chris@0: $enabled_methods = $this->getEnabledNegotiators($type); Chris@0: return empty($enabled_methods) ? LanguageNegotiatorInterface::METHOD_ID : key($enabled_methods); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isNegotiationMethodEnabled($method_id, $type = NULL) { Chris@0: $enabled = FALSE; Chris@0: $language_types = !empty($type) ? [$type] : $this->languageManager->getLanguageTypes(); Chris@0: Chris@0: foreach ($language_types as $type) { Chris@0: $enabled_methods = $this->getEnabledNegotiators($type); Chris@0: if (isset($enabled_methods[$method_id])) { Chris@0: $enabled = TRUE; Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: return $enabled; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function saveConfiguration($type, $enabled_methods) { Chris@0: // As configurable language types might have changed, we reset the cache. Chris@0: $this->languageManager->reset(); Chris@0: $definitions = $this->getNegotiationMethods(); Chris@0: $default_types = $this->languageManager->getLanguageTypes(); Chris@0: Chris@18: // Ensure that the weights are integers. Chris@18: $enabled_methods = array_map('intval', $enabled_methods); Chris@18: Chris@0: // Order the language negotiation method list by weight. Chris@0: asort($enabled_methods); Chris@0: foreach ($enabled_methods as $method_id => $weight) { Chris@0: if (isset($definitions[$method_id])) { Chris@0: $method = $definitions[$method_id]; Chris@0: // If the language negotiation method does not express any preference Chris@0: // about types, make it available for any configurable type. Chris@0: $types = array_flip(!empty($method['types']) ? $method['types'] : $default_types); Chris@0: // Check whether the method is defined and has the right type. Chris@0: if (!isset($types[$type])) { Chris@0: unset($enabled_methods[$method_id]); Chris@0: } Chris@0: } Chris@0: else { Chris@0: unset($enabled_methods[$method_id]); Chris@0: } Chris@0: } Chris@18: $this->configFactory->getEditable('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save(TRUE); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function purgeConfiguration() { Chris@0: // Ensure that we are getting the defined language negotiation information. Chris@0: // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or Chris@0: // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the Chris@0: // cached information. Chris@0: $this->negotiatorManager->clearCachedDefinitions(); Chris@0: $this->languageManager->reset(); Chris@0: foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) { Chris@0: $this->saveConfiguration($type, $this->getEnabledNegotiators($type)); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function updateConfiguration(array $types) { Chris@0: // Ensure that we are getting the defined language negotiation information. Chris@0: // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or Chris@0: // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the Chris@0: // cached information. Chris@0: $this->negotiatorManager->clearCachedDefinitions(); Chris@0: $this->languageManager->reset(); Chris@0: Chris@0: $language_types = []; Chris@0: $language_types_info = $this->languageManager->getDefinedLanguageTypesInfo(); Chris@0: $method_definitions = $this->getNegotiationMethods(); Chris@0: Chris@0: foreach ($language_types_info as $type => $info) { Chris@0: $configurable = in_array($type, $types); Chris@0: Chris@0: // The default language negotiation settings, if available, are stored in Chris@0: // $info['fixed']. Chris@0: $has_default_settings = !empty($info['fixed']); Chris@0: // Check whether the language type is unlocked. Only the status of Chris@0: // unlocked language types can be toggled between configurable and Chris@0: // non-configurable. Chris@0: if (empty($info['locked'])) { Chris@0: if (!$configurable && !$has_default_settings) { Chris@0: // If we have an unlocked non-configurable language type without Chris@0: // default language negotiation settings, we use the values Chris@0: // negotiated for the interface language which, should always be Chris@0: // available. Chris@0: $method_weights = [LanguageNegotiationUI::METHOD_ID]; Chris@0: $method_weights = array_flip($method_weights); Chris@0: $this->saveConfiguration($type, $method_weights); Chris@0: } Chris@0: } Chris@0: else { Chris@0: // The language type is locked. Locked language types with default Chris@0: // settings are always considered non-configurable. In turn if default Chris@0: // settings are missing, the language type is always considered Chris@0: // configurable. Chris@0: Chris@0: // If the language type is locked we can just store its default language Chris@0: // negotiation settings if it has some, since it is not configurable. Chris@0: if ($has_default_settings) { Chris@0: $method_weights = []; Chris@0: // Default settings are in $info['fixed']. Chris@0: Chris@0: foreach ($info['fixed'] as $weight => $method_id) { Chris@0: if (isset($method_definitions[$method_id])) { Chris@0: $method_weights[$method_id] = $weight; Chris@0: } Chris@0: } Chris@0: $this->saveConfiguration($type, $method_weights); Chris@0: } Chris@0: else { Chris@0: // It was missing default settings, so force it to be configurable. Chris@0: $configurable = TRUE; Chris@0: } Chris@0: } Chris@0: Chris@0: // Accumulate information for each language type so it can be saved later. Chris@0: $language_types[$type] = $configurable; Chris@0: } Chris@0: Chris@0: // Store the language type configuration. Chris@0: $config = [ Chris@0: 'configurable' => array_keys(array_filter($language_types)), Chris@0: 'all' => array_keys($language_types), Chris@0: ]; Chris@0: $this->languageManager->saveLanguageTypesConfiguration($config); Chris@0: } Chris@0: Chris@0: }