Initial Drupal 11 with DDEV setup

This commit is contained in:
gluebox
2025-10-08 11:39:17 -04:00
commit 89ef74b305
25344 changed files with 2599172 additions and 0 deletions

View File

@ -0,0 +1,128 @@
<?php
namespace Drupal\language\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\Attribute\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\language\Plugin\Derivative\LanguageBlock as LanguageBlockDeriver;
/**
* Provides a 'Language switcher' block.
*/
#[Block(
id: "language_block",
admin_label: new TranslatableMarkup("Language switcher"),
category: new TranslatableMarkup("System"),
deriver: LanguageBlockDeriver::class
)]
class LanguageBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The path matcher.
*
* @var \Drupal\Core\Path\PathMatcherInterface
*/
protected $pathMatcher;
/**
* Constructs a LanguageBlock object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
* The path matcher.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager, PathMatcherInterface $path_matcher) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->languageManager = $language_manager;
$this->pathMatcher = $path_matcher;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('language_manager'),
$container->get('path.matcher')
);
}
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account) {
$access = $this->languageManager->isMultilingual() ? AccessResult::allowed() : AccessResult::forbidden();
return $access->addCacheTags(['config:configurable_language_list']);
}
/**
* {@inheritdoc}
*/
public function build() {
$build = [];
$type = $this->getDerivativeId();
$route_match = \Drupal::routeMatch();
// If there is no route match, for example when creating blocks on 404 pages
// for logged-in users with big_pipe enabled using the front page instead.
if ($this->pathMatcher->isFrontPage() || !$route_match->getRouteObject()) {
// We are skipping the route match on both 404 and front page.
// Example: If on front page, there is no route match like when creating
// blocks on 404 pages for logged-in users with big_pipe enabled, use the
// front page.
$url = Url::fromRoute('<front>');
}
else {
$url = Url::fromRouteMatch($route_match);
}
$links = $this->languageManager->getLanguageSwitchLinks($type, $url);
if (isset($links->links)) {
$build = [
'#theme' => 'links__language_block',
'#links' => $links->links,
'#attributes' => [
'class' => [
"language-switcher-{$links->method_id}",
],
],
'#set_active_class' => TRUE,
];
}
return $build;
}
/**
* {@inheritdoc}
*
* @todo Make cacheable in https://www.drupal.org/node/2232375.
*/
public function getCacheMaxAge() {
return 0;
}
}

View File

@ -0,0 +1,155 @@
<?php
namespace Drupal\language\Plugin\Condition;
use Drupal\Core\Condition\Attribute\Condition;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a 'Language' condition.
*/
#[Condition(
id: "language",
label: new TranslatableMarkup("Language"),
context_definitions: [
"language" => new ContextDefinition(
data_type: "language",
label: new TranslatableMarkup("Language"),
),
]
)]
class Language extends ConditionPluginBase implements ContainerFactoryPluginInterface {
/**
* The Language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Creates a new Language instance.
*
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param array $configuration
* The plugin configuration, i.e. an array with configuration values keyed
* by configuration option name. The special key 'context' may be used to
* initialize the defined contexts by setting it to an array of context
* values keyed by context names.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
*/
public function __construct(LanguageManagerInterface $language_manager, array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('language_manager'),
$configuration,
$plugin_id,
$plugin_definition
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
if ($this->languageManager->isMultilingual()) {
// Fetch languages.
$languages = $this->languageManager->getLanguages();
$langcodes_options = [];
foreach ($languages as $language) {
$langcodes_options[$language->getId()] = $language->getName();
}
$form['langcodes'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Language selection'),
'#default_value' => $this->configuration['langcodes'],
'#options' => $langcodes_options,
'#description' => $this->t('Select languages to enforce. If none are selected, all languages will be allowed.'),
];
}
else {
$form['langcodes'] = [
'#type' => 'value',
'#default_value' => $this->configuration['langcodes'],
];
}
return parent::buildConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['langcodes'] = array_filter($form_state->getValue('langcodes'));
parent::submitConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function summary() {
$language_list = $this->languageManager->getLanguages(LanguageInterface::STATE_ALL);
$selected = $this->configuration['langcodes'];
// Reduce the language list to an array of language names.
$language_names = array_reduce($language_list, function ($result, $item) use ($selected) {
// If the current item of the $language_list array is one of the selected
// languages, add it to the $results array.
if (!empty($selected[$item->getId()])) {
$result[$item->getId()] = $item->getName();
}
return $result;
}, []);
// If we have more than one language selected, separate them by commas.
if (count($this->configuration['langcodes']) > 1) {
$languages = implode(', ', $language_names);
}
else {
// If we have just one language just grab the only present value.
$languages = array_pop($language_names);
}
if (!empty($this->configuration['negate'])) {
return $this->t('The language is not @languages.', ['@languages' => $languages]);
}
return $this->t('The language is @languages.', ['@languages' => $languages]);
}
/**
* {@inheritdoc}
*/
public function evaluate() {
if (empty($this->configuration['langcodes']) && !$this->isNegated()) {
return TRUE;
}
$language = $this->getContextValue('language');
// Language visibility settings.
return !empty($this->configuration['langcodes'][$language->getId()]);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return ['langcodes' => []] + parent::defaultConfiguration();
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Drupal\language\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\language\ConfigurableLanguageManagerInterface;
/**
* Provides language switcher block plugin definitions for all languages.
*/
class LanguageBlock extends DeriverBase {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$language_manager = \Drupal::languageManager();
if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
$info = $language_manager->getDefinedLanguageTypesInfo();
$configurable_types = $language_manager->getLanguageTypes();
foreach ($configurable_types as $type) {
$this->derivatives[$type] = $base_plugin_definition;
$this->derivatives[$type]['admin_label'] = $this->t('Language switcher (@type)', ['@type' => $info[$type]['name']]);
}
// If there is just one configurable type then change the title of the
// block.
if (count($configurable_types) == 1) {
$this->derivatives[reset($configurable_types)]['admin_label'] = $this->t('Language switcher');
}
}
return parent::getDerivativeDefinitions($base_plugin_definition);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Component\Utility\UserAgent;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class for identifying language from the browser Accept-language HTTP header.
*/
#[LanguageNegotiation(
id: LanguageNegotiationBrowser::METHOD_ID,
name: new TranslatableMarkup('Browser'),
weight: -2,
description: new TranslatableMarkup("Language from the browser's language settings."),
config_route_name: 'language.negotiation_browser'
)]
class LanguageNegotiationBrowser extends LanguageNegotiationMethodBase implements ContainerFactoryPluginInterface {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-browser';
/**
* The page cache disabling policy.
*
* @var \Drupal\Core\PageCache\ResponsePolicy\KillSwitch
*/
protected $pageCacheKillSwitch;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = new static();
$instance->pageCacheKillSwitch = $container->get('page_cache_kill_switch');
return $instance;
}
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
$langcode = NULL;
if ($this->languageManager && $request && $request->server->get('HTTP_ACCEPT_LANGUAGE')) {
$http_accept_language = $request->server->get('HTTP_ACCEPT_LANGUAGE');
$langcodes = array_keys($this->languageManager->getLanguages());
$mappings = $this->config->get('language.mappings')->get('map');
$langcode = UserAgent::getBestMatchingLangcode($http_accept_language, $langcodes, $mappings);
}
// Internal page cache with multiple languages and browser negotiation
// could lead to wrong cached sites. Therefore disabling the internal page
// cache.
// @todo Solve more elegantly in https://www.drupal.org/node/2430335.
$this->pageCacheKillSwitch->trigger();
return $langcode;
}
}

View File

@ -0,0 +1,282 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Drupal\language\LanguageSwitcherInterface;
use Drupal\Core\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Class for identifying the content translation language.
*/
#[LanguageNegotiation(
id: LanguageNegotiationContentEntity::METHOD_ID,
name: new TranslatableMarkup('Content language'),
types: [LanguageInterface::TYPE_CONTENT],
weight: -9,
description: new TranslatableMarkup("Determines the content language from the request parameter named 'language_content_entity'.")
)]
class LanguageNegotiationContentEntity extends LanguageNegotiationMethodBase implements OutboundPathProcessorInterface, LanguageSwitcherInterface, ContainerFactoryPluginInterface {
/**
* The language negotiation method ID.
*/
const METHOD_ID = 'language-content-entity';
/**
* The query string parameter.
*/
const QUERY_PARAMETER = 'language_content_entity';
/**
* A list of all the link paths of enabled content entities.
*
* @var array
*/
protected $contentEntityPaths;
/**
* Static cache for the language negotiation order check.
*
* @var bool
*
* @see \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity::hasLowerLanguageNegotiationWeight()
*/
protected $hasLowerLanguageNegotiationWeightResult;
/**
* Static cache of outbound route paths per request.
*
* @var \SplObjectStorage
*/
protected $paths;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a new LanguageNegotiationContentEntity instance.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->paths = new \SplObjectStorage();
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($container->get('entity_type.manager'));
}
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
if ($request === NULL || $this->languageManager === NULL) {
return NULL;
}
$langcode = $request->query->get(static::QUERY_PARAMETER);
$language_enabled = array_key_exists($langcode, $this->languageManager->getLanguages());
return $language_enabled ? $langcode : NULL;
}
/**
* {@inheritdoc}
*/
public function processOutbound($path, &$options = [], ?Request $request = NULL, ?BubbleableMetadata $bubbleable_metadata = NULL) {
// If appropriate, process outbound to add a query parameter to the URL and
// remove the language option, so that URL negotiator does not rewrite the
// URL.
// First, check if processing conditions are met.
if (!($request && !empty($options['route']) && $this->hasLowerLanguageNegotiationWeight() && $this->meetsContentEntityRoutesCondition($options['route'], $request))) {
return $path;
}
if (isset($options['language']) || $langcode = $this->getLangcode($request)) {
// If the language option is set, unset it, so that the URL language
// negotiator does not rewrite the URL.
if (isset($options['language'])) {
$langcode = $options['language']->getId();
unset($options['language']);
}
if (!isset($options['query'][static::QUERY_PARAMETER])) {
$options['query'][static::QUERY_PARAMETER] = $langcode;
}
if ($bubbleable_metadata) {
// Cached URLs that have been processed by this outbound path
// processor must be:
$bubbleable_metadata
// - varied by the content language query parameter.
->addCacheContexts(['url.query_args:' . static::QUERY_PARAMETER]);
}
}
return $path;
}
/**
* {@inheritdoc}
*/
public function getLanguageSwitchLinks(Request $request, $type, Url $url) {
$links = [];
$query = [];
parse_str($request->getQueryString() ?? '', $query);
foreach ($this->languageManager->getNativeLanguages() as $language) {
$langcode = $language->getId();
$query[static::QUERY_PARAMETER] = $langcode;
$links[$langcode] = [
'url' => $url,
'title' => $language->getName(),
'attributes' => ['class' => ['language-link']],
'query' => $query,
];
}
return $links;
}
/**
* Determines if content entity language negotiator has higher priority.
*
* The content entity language negotiator having higher priority than the URL
* language negotiator, is a criteria in
* \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity::processOutbound().
*
* @return bool
* TRUE if the content entity language negotiator has higher priority than
* the URL language negotiator, FALSE otherwise.
*/
protected function hasLowerLanguageNegotiationWeight() {
if (!isset($this->hasLowerLanguageNegotiationWeightResult)) {
// Only run if the LanguageNegotiationContentEntity outbound function is
// being executed before the outbound function of LanguageNegotiationUrl.
$content_method_weights = $this->config->get('language.types')->get('negotiation.language_content.enabled') ?: [];
// Check if the content language is configured to be dependent on the
// URL negotiator directly or indirectly over the interface negotiator.
if (isset($content_method_weights[LanguageNegotiationUrl::METHOD_ID]) && ($content_method_weights[static::METHOD_ID] > $content_method_weights[LanguageNegotiationUrl::METHOD_ID])) {
$this->hasLowerLanguageNegotiationWeightResult = FALSE;
}
else {
$check_interface_method = FALSE;
if (isset($content_method_weights[LanguageNegotiationUI::METHOD_ID])) {
$interface_method_weights = $this->config->get('language.types')->get('negotiation.language_interface.enabled') ?: [];
$check_interface_method = isset($interface_method_weights[LanguageNegotiationUrl::METHOD_ID]);
}
if ($check_interface_method) {
$max_weight = $content_method_weights[LanguageNegotiationUI::METHOD_ID];
$max_weight = isset($content_method_weights[LanguageNegotiationUrl::METHOD_ID]) ? max($max_weight, $content_method_weights[LanguageNegotiationUrl::METHOD_ID]) : $max_weight;
}
else {
$max_weight = $content_method_weights[LanguageNegotiationUrl::METHOD_ID] ?? PHP_INT_MAX;
}
$this->hasLowerLanguageNegotiationWeightResult = $content_method_weights[static::METHOD_ID] < $max_weight;
}
}
return $this->hasLowerLanguageNegotiationWeightResult;
}
/**
* Determines if content entity route condition is met.
*
* Requirements: currently being on a content entity route and processing
* outbound URL pointing to the same content entity.
*
* @param \Symfony\Component\Routing\Route $outbound_route
* The route object for the current outbound URL being processed.
* @param \Symfony\Component\HttpFoundation\Request $request
* The HttpRequest object representing the current request.
*
* @return bool
* TRUE if the content entity route condition is met, FALSE otherwise.
*/
protected function meetsContentEntityRoutesCondition(Route $outbound_route, Request $request) {
$outbound_path_pattern = $outbound_route->getPath();
$storage = $this->paths[$request] ?? [];
if (!isset($storage[$outbound_path_pattern])) {
$storage[$outbound_path_pattern] = FALSE;
// Check if the outbound route points to the current entity.
if ($content_entity_type_id_for_current_route = $this->getContentEntityTypeIdForCurrentRequest($request)) {
if (!empty($this->getContentEntityPaths()[$outbound_path_pattern]) && $content_entity_type_id_for_current_route == $this->getContentEntityPaths()[$outbound_path_pattern]) {
$storage[$outbound_path_pattern] = TRUE;
}
}
$this->paths[$request] = $storage;
}
return $storage[$outbound_path_pattern];
}
/**
* Returns the content entity type ID from the current request for the route.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HttpRequest object representing the current request.
*
* @return string
* The entity type ID for the route from the request.
*/
protected function getContentEntityTypeIdForCurrentRequest(Request $request) {
$content_entity_type_id_for_current_route = '';
if ($current_route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) {
$current_route_path = $current_route->getPath();
$content_entity_type_id_for_current_route = $this->getContentEntityPaths()[$current_route_path] ?? '';
}
return $content_entity_type_id_for_current_route;
}
/**
* Returns the paths for the link templates of all content entities.
*
* @return array
* An array of all content entity type IDs, keyed by the corresponding link
* template paths.
*/
protected function getContentEntityPaths() {
if (!isset($this->contentEntityPaths)) {
$this->contentEntityPaths = [];
$entity_types = $this->entityTypeManager->getDefinitions();
foreach ($entity_types as $entity_type_id => $entity_type) {
if ($entity_type->entityClassImplements(ContentEntityInterface::class)) {
$entity_paths = array_fill_keys($entity_type->getLinkTemplates(), $entity_type_id);
$this->contentEntityPaths = array_merge($this->contentEntityPaths, $entity_paths);
}
}
}
return $this->contentEntityPaths;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Class for identifying language from a selected language.
*/
#[LanguageNegotiation(
id: LanguageNegotiationSelected::METHOD_ID,
name: new TranslatableMarkup('Selected language'),
weight: 12,
description: new TranslatableMarkup("Language based on a selected language."),
config_route_name: 'language.negotiation_selected'
)]
class LanguageNegotiationSelected extends LanguageNegotiationMethodBase {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-selected';
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
$langcode = NULL;
if ($this->languageManager) {
$langcode = $this->config->get('language.negotiation')->get('selected_langcode');
}
return $langcode;
}
}

View File

@ -0,0 +1,189 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Drupal\language\LanguageSwitcherInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Identify language from a request/session parameter.
*/
#[LanguageNegotiation(
id: LanguageNegotiationSession::METHOD_ID,
name: new TranslatableMarkup('Session'),
weight: -6,
description: new TranslatableMarkup("Language from a request/session parameter."),
config_route_name: 'language.negotiation_session'
)]
class LanguageNegotiationSession extends LanguageNegotiationMethodBase implements OutboundPathProcessorInterface, LanguageSwitcherInterface, ContainerFactoryPluginInterface {
/**
* Flag used to determine whether query rewriting is active.
*
* @var bool
*/
protected $queryRewrite;
/**
* The query parameter name to rewrite.
*
* @var string
*/
protected $queryParam;
/**
* The query parameter value to be set.
*
* @var string
*/
protected $queryValue;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-session';
/**
* Constructs a LanguageNegotiationSession object.
*
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(RequestStack $request_stack) {
$this->requestStack = $request_stack;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('request_stack')
);
}
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
$config = $this->config->get('language.negotiation')->get('session');
if (($param = $config['parameter']) && $request) {
if ($request->query->has($param)) {
return $request->query->get($param);
}
if ($request->getSession()->has($param)) {
return $request->getSession()->get($param);
}
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function persist(LanguageInterface $language) {
// We need to update the session parameter with the request value only if we
// have an authenticated user.
$langcode = $language->getId();
if ($langcode && $this->languageManager) {
$languages = $this->languageManager->getLanguages();
if ($this->currentUser->isAuthenticated() && isset($languages[$langcode])) {
$config = $this->config->get('language.negotiation')->get('session');
$this->requestStack->getCurrentRequest()->getSession()->set($config['parameter'], $langcode);
}
}
}
/**
* {@inheritdoc}
*/
public function processOutbound($path, &$options = [], ?Request $request = NULL, ?BubbleableMetadata $bubbleable_metadata = NULL) {
if ($request) {
// The following values are not supposed to change during a single page
// request processing.
if (!isset($this->queryRewrite)) {
if ($this->currentUser->isAnonymous()) {
$languages = $this->languageManager->getLanguages();
$config = $this->config->get('language.negotiation')->get('session');
$this->queryParam = $config['parameter'];
$this->queryValue = $request->query->has($this->queryParam) ? $request->query->get($this->queryParam) : NULL;
$this->queryRewrite = isset($languages[$this->queryValue]);
}
else {
$this->queryRewrite = FALSE;
}
}
// If the user is anonymous, the user language negotiation method is
// enabled, and the corresponding option has been set, we must preserve
// any explicit user language preference even with cookies disabled.
if ($this->queryRewrite) {
if (!isset($options['query'][$this->queryParam])) {
$options['query'][$this->queryParam] = $this->queryValue;
}
if ($bubbleable_metadata) {
// Cached URLs that have been processed by this outbound path
// processor must be:
$bubbleable_metadata
// - invalidated when the language negotiation config changes, since
// another query parameter may be used to determine the language.
->addCacheTags($this->config->get('language.negotiation')->getCacheTags())
// - varied by the configured query parameter.
->addCacheContexts(['url.query_args:' . $this->queryParam]);
}
}
}
return $path;
}
/**
* {@inheritdoc}
*/
public function getLanguageSwitchLinks(Request $request, $type, Url $url) {
$links = [];
$query = [];
parse_str($request->getQueryString() ?? '', $query);
$config = $this->config->get('language.negotiation')->get('session');
$param = $config['parameter'];
$language_query = $request->getSession()->has($param) ? $request->getSession()->get($param) : $this->languageManager->getCurrentLanguage($type)->getId();
foreach ($this->languageManager->getNativeLanguages() as $language) {
$langcode = $language->getId();
$links[$langcode] = [
// 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(),
'attributes' => ['class' => ['language-link']],
'query' => $query,
];
if ($language_query != $langcode) {
$links[$langcode]['query'][$param] = $langcode;
}
else {
$links[$langcode]['attributes']['class'][] = 'session-active';
}
}
return $links;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Identifies the language from the interface text language selected for page.
*/
#[LanguageNegotiation(
id: LanguageNegotiationUI::METHOD_ID,
name: new TranslatableMarkup('Interface'),
types: [LanguageInterface::TYPE_CONTENT],
weight: 9,
description: new TranslatableMarkup("Use the detected interface language.")
)]
class LanguageNegotiationUI extends LanguageNegotiationMethodBase {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-interface';
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
return $this->languageManager ? $this->languageManager->getCurrentLanguage()->getId() : NULL;
}
}

View File

@ -0,0 +1,227 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Drupal\language\LanguageSwitcherInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class for identifying language via URL prefix or domain.
*/
#[LanguageNegotiation(
id: LanguageNegotiationUrl::METHOD_ID,
name: new TranslatableMarkup('URL'),
types: [LanguageInterface::TYPE_INTERFACE,
LanguageInterface::TYPE_CONTENT,
LanguageInterface::TYPE_URL,
],
weight: -8,
description: new TranslatableMarkup("Language from the URL (Path prefix or domain)."),
config_route_name: 'language.negotiation_url'
)]
class LanguageNegotiationUrl extends LanguageNegotiationMethodBase implements InboundPathProcessorInterface, OutboundPathProcessorInterface, LanguageSwitcherInterface {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-url';
/**
* URL language negotiation: use the path prefix as URL language indicator.
*/
const CONFIG_PATH_PREFIX = 'path_prefix';
/**
* URL language negotiation: use the domain as URL language indicator.
*/
const CONFIG_DOMAIN = 'domain';
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
$langcode = NULL;
if ($request && $this->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']) || ($options['language'] instanceof LanguageInterface && $options['language']->getId() == LanguageInterface::LANGCODE_NOT_SPECIFIED)) {
$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()])) {
// Check if the base URLs match, return early if they do.
if (isset($options['base_url']) && $request && $request->getHost() === parse_url($options['base_url'], PHP_URL_HOST)) {
return $path;
}
// 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 only if the domain
// is different from the current request domain.
if ($request && $request->getHost() !== $config['domains'][$options['language']->getId()]) {
$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) && str_contains($normalized_base_url, ':')) {
[, $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 = [];
parse_str($request->getQueryString() ?? '', $query);
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;
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\HttpFoundation\Request;
/**
* 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.
*/
#[LanguageNegotiation(
id: LanguageNegotiationUrlFallback::METHOD_ID,
name: new TranslatableMarkup('URL fallback'),
types: [LanguageInterface::TYPE_URL],
weight: 8,
description: new TranslatableMarkup('Use an already detected language for URLs if none is found.'),
)]
class LanguageNegotiationUrlFallback extends LanguageNegotiationMethodBase {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-url-fallback';
/**
* {@inheritdoc}
*/
public function getLangcode(?Request $request = NULL) {
$langcode = NULL;
if ($this->languageManager) {
$default = $this->languageManager->getDefaultLanguage();
$config = $this->config->get('language.negotiation')->get('url');
$prefix = ($config['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.
if (($prefix && empty($config['prefixes'][$default->getId()])) || (!$prefix && empty($config['domains'][$default->getId()]))) {
$langcode = $default->getId();
}
else {
$langcode = $this->languageManager->getCurrentLanguage()->getId();
}
}
return $langcode;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Drupal\language\Plugin\migrate\destination;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\migrate\Attribute\MigrateDestination;
use Drupal\migrate\MigrateException;
use Drupal\migrate\Plugin\migrate\destination\Config;
use Drupal\migrate\Row;
/**
* Provides a destination plugin for the default langcode config.
*/
#[MigrateDestination('default_langcode')]
class DefaultLangcode extends Config {
/**
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = []) {
$destination = $row->getDestination();
$langcode = $destination['default_langcode'];
// Check if the language exists.
if (ConfigurableLanguage::load($langcode) === NULL) {
throw new MigrateException("The language '$langcode' does not exist on this site.");
}
$this->config->set('default_langcode', $destination['default_langcode']);
$this->config->save();
return [$this->config->getName()];
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace Drupal\language\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Determines the content translation setting.
*
* The source value is an indexed array of three values:
* - The language content type, e.g. '1'
* - The entity_translation_entity_types, an array of entity types.
* - An entity type used with entity translation, e.g. comment.
*/
#[MigrateProcess('content_translation_enabled_setting')]
class ContentTranslationEnabledSetting extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (!is_array($value)) {
throw new MigrateException('Input should be an array');
}
[$language_content_type, $entity_translation_entity_types, $entity_type] = $value;
switch ($language_content_type) {
// In the case of being 0, it will be skipped. We are not actually setting
// a null value.
case 0:
$setting = NULL;
break;
case 1:
$setting = FALSE;
break;
case 2:
$setting = FALSE;
break;
case 4:
// If entity translation is enabled return the status of comment
// translations.
$setting = FALSE;
if (!empty($entity_translation_entity_types[$entity_type])) {
$setting = TRUE;
}
break;
default:
$setting = NULL;
break;
}
return $setting;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Drupal\language\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\migrate\process\ArrayBuild;
use Drupal\migrate\Row;
/**
* This plugin makes sure that no domain is empty if domain negotiation is used.
*/
#[MigrateProcess(
id: "language_domains",
handle_multiples: TRUE,
)]
class LanguageDomains extends ArrayBuild {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if ($row->getSourceProperty('domain_negotiation_used')) {
global $base_url;
foreach ($value as $old_key => $old_value) {
if (empty($old_value['domain'])) {
// The default language domain might be empty.
// If it is, use the current domain.
$value[$old_key]['domain'] = parse_url($base_url, PHP_URL_HOST);
}
else {
// Ensure we have a protocol when checking for the hostname.
$domain = 'http://' . str_replace(['http://', 'https://'], '', $old_value['domain']);
// Only keep the host part of the domain.
$value[$old_key]['domain'] = parse_url($domain, PHP_URL_HOST);
}
}
}
return parent::transform($value, $migrate_executable, $row, $destination_property);
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Drupal\language\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Processes the arrays for the language types' negotiation methods and weights.
*/
#[MigrateProcess(
id: "language_negotiation",
handle_multiples: TRUE,
)]
class LanguageNegotiation extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$new_value = [
'enabled' => [],
'method_weights' => [],
];
if (!is_array($value)) {
throw new MigrateException('The input should be an array');
}
// If no weights are provided, use the keys by flipping the array.
if (empty($value[1])) {
$new_value['enabled'] = array_flip(array_map([$this, 'mapNewMethods'], array_keys($value[0])));
unset($new_value['method_weights']);
}
else {
foreach ($value[1] as $method => $weight) {
$new_method = $this->mapNewMethods($method);
$new_value['method_weights'][$new_method] = $weight;
if (in_array($method, array_keys($value[0]))) {
$new_value['enabled'][$new_method] = $weight;
}
}
}
return $new_value;
}
/**
* Maps old negotiation method names to the new ones.
*
* @param string $value
* The old negotiation method name.
*
* @return string
* The new negotiation method name.
*/
protected function mapNewMethods($value) {
switch ($value) {
case 'language-default':
return 'language-selected';
case 'locale-browser':
return 'language-browser';
case 'locale-interface':
return 'language-interface';
case 'locale-session':
return 'language-session';
case 'locale-url':
return 'language-url';
case 'locale-url-fallback':
return 'language-url-fallback';
case 'locale-user':
return 'language-user';
default:
return $value;
}
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Drupal\language\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Processes the array for the language types.
*/
#[MigrateProcess(
id: "language_types",
handle_multiples: TRUE,
)]
class LanguageTypes extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (!is_array($value)) {
throw new MigrateException('The input should be an array');
}
if (array_key_exists('language', $value)) {
$value['language_interface'] = $value['language'];
unset($value['language']);
}
if (!empty($this->configuration['filter_configurable'])) {
$value = array_filter($value);
}
return array_keys($value);
}
}

View File

@ -0,0 +1,103 @@
<?php
namespace Drupal\language\Plugin\migrate\source;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 6/7 language source from database.
*
* Available configuration keys:
* - fetch_all: (optional) If not empty, all source languages are retrieved and
* available as "languages" source property. Each language is an array with
* the same structure as a source row.
* - domain_negotiation: (optional) If not empty and domain negotiation is
* enabled in the source database, the "domain_negotiation_used" source
* property is set to TRUE.
*
* Example:
*
* @code
* plugin: language
* fetch_all: true
* domain_negotiation: true
* @endcode
*
* In this example, available languages are retrieved from the source database.
* Given that fetch_all and domain_negotiation are specified, each row also
* contains all languages and the domain negotiation status, if enabled.
*
* For additional configuration keys, refer to the parent classes.
*
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
*
* @MigrateSource(
* id = "language",
* source_module = "locale"
* )
*/
class Language extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function fields() {
return [
'language' => $this->t('The language code.'),
'name' => $this->t('The English name of the language.'),
'native' => $this->t('The native name of the language.'),
'direction' => $this->t('The language direction. (0 = LTR, 1 = RTL)'),
'enabled' => $this->t('Whether the language is enabled.'),
'plurals' => $this->t('Number of plural indexes in this language.'),
'formula' => $this->t('PHP formula to get plural indexes.'),
'domain' => $this->t('Domain to use for this language.'),
'prefix' => $this->t('Path prefix used for this language.'),
'weight' => $this->t('The language weight when listed.'),
'javascript' => $this->t('Location of the JavaScript translation file.'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
return [
'language' => [
'type' => 'string',
],
];
}
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('languages')->fields('languages');
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
if (!empty($this->configuration['fetch_all'])) {
// Get an array of all languages.
$languages = $this->query()->execute()->fetchAll();
$row->setSourceProperty('languages', $languages);
}
if (!empty($this->configuration['domain_negotiation'])) {
// Check if domain negotiation is used to be able to fill in the default
// language domain, which may be empty. In D6, domain negotiation is used
// when the 'language_negotiation' variable is set to '3', and in D7, when
// the 'locale_language_negotiation_url_part' variable is set to '1'.
if ($this->variableGet('language_negotiation', 0) == 3 || $this->variableGet('locale_language_negotiation_url_part', 0) == 1) {
$row->setSourceProperty('domain_negotiation_used', TRUE);
}
}
return parent::prepareRow($row);
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d6;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 6 i18n node settings from database.
*
* For available configuration keys, refer to the parent classes.
*
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBas
*
* @MigrateSource(
* id = "d6_language_content_settings",
* source_module = "locale"
* )
*/
class LanguageContentSettings extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('node_type', 't')
->fields('t', [
'type',
]);
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = [
'type' => $this->t('Type'),
'language_content_type' => $this->t('Multilingual support.'),
'i18n_lock_node' => $this->t('Lock language.'),
];
return $fields;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$type = $row->getSourceProperty('type');
$row->setSourceProperty('language_content_type', $this->variableGet('language_content_type_' . $type, NULL));
$row->setSourceProperty('i18n_lock_node', $this->variableGet('i18n_lock_node_' . $type, 0));
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['type']['type'] = 'string';
return $ids;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d6;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
// cspell:ignore localizable
/**
* Drupal 6 i18n vocabularies source from database.
*
* For available configuration keys, refer to the parent classes.
*
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBas
*
* @MigrateSource(
* id = "d6_language_content_settings_taxonomy_vocabulary",
* source_module = "taxonomy"
* )
*/
class LanguageContentSettingsTaxonomyVocabulary extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('vocabulary', 'v')
->fields('v', ['vid']);
if ($this->getDatabase()
->schema()
->fieldExists('vocabulary', 'language')) {
$query->addField('v', 'language');
}
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'vid' => $this->t('The vocabulary ID.'),
'language' => $this->t('The default language for new terms.'),
'state' => $this->t('The i18n taxonomy translation setting.'),
];
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
// Get the i18n taxonomy translation setting for this vocabulary.
// 0 - No multilingual options
// 1 - Localizable terms. Run through the localization system.
// 2 - Predefined language for a vocabulary and its terms.
// 3 - Per-language terms, translatable (referencing terms with different
// languages) but not localizable.
$i18ntaxonomy_vocabulary = $this->variableGet('i18ntaxonomy_vocabulary', []);
$vid = $row->getSourceProperty('vid');
$state = 0;
if (array_key_exists($vid, $i18ntaxonomy_vocabulary)) {
$state = $i18ntaxonomy_vocabulary[$vid];
}
$row->setSourceProperty('state', $state);
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['vid']['type'] = 'integer';
return $ids;
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d7;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 7 i18n node settings from database.
*
* For available configuration keys, refer to the parent classes.
*
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBas
*
* @MigrateSource(
* id = "d7_language_content_settings",
* source_module = "locale"
* )
*/
class LanguageContentSettings extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('node_type', 't')
->fields('t', [
'type',
]);
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = [
'type' => $this->t('Type'),
'language_content_type' => $this->t('Multilingual support.'),
'i18n_lock_node' => $this->t('Lock language.'),
];
return $fields;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$type = $row->getSourceProperty('type');
$row->setSourceProperty('language_content_type', $this->variableGet('language_content_type_' . $type, NULL));
$i18n_node_options = $this->variableGet('i18n_node_options_' . $type, NULL);
if ($i18n_node_options && in_array('lock', $i18n_node_options)) {
$row->setSourceProperty('i18n_lock_node', 1);
}
else {
$row->setSourceProperty('i18n_lock_node', 0);
}
// Get the entity translation entity settings.
$entity_translation_entity_types = $this->variableGet('entity_translation_entity_types', NULL);
$row->setSourceProperty('entity_translation_entity_types', $entity_translation_entity_types);
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['type']['type'] = 'string';
return $ids;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Drupal\language\Plugin\migrate\source\d7;
use Drupal\taxonomy\Plugin\migrate\source\d7\Vocabulary;
/**
* Drupal 7 i18n vocabularies source from database.
*
* For available configuration keys, refer to the parent classes.
*
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBas
*
* @MigrateSource(
* id = "d7_language_content_settings_taxonomy_vocabulary",
* source_module = "i18n_taxonomy"
* )
*/
class LanguageContentSettingsTaxonomyVocabulary extends Vocabulary {
/**
* {@inheritdoc}
*/
public function query() {
$query = parent::query();
if ($this->getDatabase()
->schema()
->fieldExists('taxonomy_vocabulary', 'i18n_mode')) {
$query->addField('v', 'language');
$query->addField('v', 'i18n_mode');
}
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = parent::fields();
$fields['language'] = $this->t('i18n language');
$fields['i18n_mode'] = $this->t('i18n mode');
return $fields;
}
}