languageManager) { $languages = $this->languageManager->getLanguages(); $config = $this->config->get('language.negotiation')->get('url'); switch ($config['source']) { case LanguageNegotiationUrl::CONFIG_PATH_PREFIX: $request_path = urldecode(trim($request->getPathInfo(), '/')); $path_args = explode('/', $request_path); $prefix = array_shift($path_args); // Search prefix within added languages. $negotiated_language = FALSE; foreach ($languages as $language) { if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) { $negotiated_language = $language; break; } } if ($negotiated_language) { $langcode = $negotiated_language->getId(); } break; case LanguageNegotiationUrl::CONFIG_DOMAIN: // Get only the host, not the port. $http_host = $request->getHost(); foreach ($languages as $language) { // Skip the check if the language doesn't have a domain. if (!empty($config['domains'][$language->getId()])) { // Ensure that there is exactly one protocol in the URL when // checking the hostname. $host = 'http://' . str_replace(['http://', 'https://'], '', $config['domains'][$language->getId()]); $host = parse_url($host, PHP_URL_HOST); if ($http_host == $host) { $langcode = $language->getId(); break; } } } break; } } return $langcode; } /** * {@inheritdoc} */ public function processInbound($path, Request $request) { $config = $this->config->get('language.negotiation')->get('url'); if ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) { $parts = explode('/', trim($path, '/')); $prefix = array_shift($parts); // Search prefix within added languages. foreach ($this->languageManager->getLanguages() as $language) { if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) { // Rebuild $path with the language removed. $path = '/' . implode('/', $parts); break; } } } return $path; } /** * {@inheritdoc} */ public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) { $url_scheme = 'http'; $port = 80; if ($request) { $url_scheme = $request->getScheme(); $port = $request->getPort(); } $languages = array_flip(array_keys($this->languageManager->getLanguages())); // Language can be passed as an option, or we go for current URL language. if (!isset($options['language'])) { $language_url = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL); $options['language'] = $language_url; } // We allow only added languages here. elseif (!is_object($options['language']) || !isset($languages[$options['language']->getId()])) { return $path; } $config = $this->config->get('language.negotiation')->get('url'); if ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) { if (is_object($options['language']) && !empty($config['prefixes'][$options['language']->getId()])) { $options['prefix'] = $config['prefixes'][$options['language']->getId()] . '/'; if ($bubbleable_metadata) { $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL]); } } } elseif ($config['source'] == LanguageNegotiationUrl::CONFIG_DOMAIN) { if (is_object($options['language']) && !empty($config['domains'][$options['language']->getId()])) { // Save the original base URL. If it contains a port, we need to // retain it below. if (!empty($options['base_url'])) { // The colon in the URL scheme messes up the port checking below. $normalized_base_url = str_replace(['https://', 'http://'], '', $options['base_url']); } // Ask for an absolute URL with our modified base URL. $options['absolute'] = TRUE; $options['base_url'] = $url_scheme . '://' . $config['domains'][$options['language']->getId()]; // In case either the original base URL or the HTTP host contains a // port, retain it. if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) { list(, $port) = explode(':', $normalized_base_url); $options['base_url'] .= ':' . $port; } elseif (($url_scheme == 'http' && $port != 80) || ($url_scheme == 'https' && $port != 443)) { $options['base_url'] .= ':' . $port; } if (isset($options['https'])) { if ($options['https'] === TRUE) { $options['base_url'] = str_replace('http://', 'https://', $options['base_url']); } elseif ($options['https'] === FALSE) { $options['base_url'] = str_replace('https://', 'http://', $options['base_url']); } } // Add Drupal's subfolder from the base_path if there is one. $options['base_url'] .= rtrim(base_path(), '/'); if ($bubbleable_metadata) { $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']); } } } return $path; } /** * {@inheritdoc} */ public function getLanguageSwitchLinks(Request $request, $type, Url $url) { $links = []; $query = $request->query->all(); foreach ($this->languageManager->getNativeLanguages() as $language) { $links[$language->getId()] = [ // We need to clone the $url object to avoid using the same one for all // links. When the links are rendered, options are set on the $url // object, so if we use the same one, they would be set for all links. 'url' => clone $url, 'title' => $language->getName(), 'language' => $language, 'attributes' => ['class' => ['language-link']], 'query' => $query, ]; } return $links; } }