diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index fb076b6..a7fdfcb 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -107,8 +107,6 @@ function hook_entity_view_mode_info_alter(&$view_modes) {
* - access callback: As in hook_menu(). 'user_access' will be assumed if
* no value is provided.
* - access arguments: As in hook_menu().
- * - translatable: (optional) A boolean value specifying whether this bundle
- * has translation support enabled. Defaults to FALSE.
*
* @see entity_get_bundles()
* @see hook_entity_bundle_info_alter()
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 5bde077..b4e8fce 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -729,6 +729,12 @@ function install_tasks($install_state) {
'type' => 'batch',
'run' => $needs_translations ? INSTALL_TASK_RUN_IF_NOT_COMPLETED : INSTALL_TASK_SKIP,
),
+ 'install_update_configuration_translations' => array(
+ 'display_name' => st('Translate configuration'),
+ 'display' => $needs_translations,
+ 'type' => 'batch',
+ 'run' => $needs_translations ? INSTALL_TASK_RUN_IF_NOT_COMPLETED : INSTALL_TASK_SKIP,
+ ),
'install_finished' => array(
'display_name' => st('Finished'),
),
@@ -1830,6 +1836,22 @@ function install_import_translations_remaining(&$install_state) {
}
/**
+ * Creates configuration translations.
+ *
+ * @param array $install_state
+ * An array of information about the current installation state.
+ *
+ * @return array
+ * The batch definition, if there are configuration objects to update.
+ *
+ * @see install_tasks()
+ */
+function install_update_configuration_translations(&$install_state) {
+ module_load_include('bulk.inc', 'locale');
+ return locale_config_batch_update_components(array(), array($install_state['parameters']['langcode']));
+}
+
+/**
* Performs final installation steps and displays a 'finished' page.
*
* @param $install_state
diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
index 5d39934..457f6ec 100644
--- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
+++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
@@ -36,13 +36,13 @@
* initialize the defined contexts by setting it to an array of context
* values keyed by context names.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
$context = array();
if (isset($configuration['context'])) {
$context = $configuration['context'];
unset($configuration['context']);
}
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ parent::__construct($configuration, $plugin_id, $discovery);
foreach ($context as $key => $value) {
$context_definition = $this->getContextDefinition($key);
$this->context[$key] = new Context($context_definition);
diff --git a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
index d049814..168d5d7 100644
--- a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
+++ b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
@@ -41,23 +41,23 @@ public function __construct(DiscoveryInterface $discovery) {
* Implements Drupal\Component\Plugin\Factory\FactoryInterface::createInstance().
*/
public function createInstance($plugin_id, array $configuration) {
- $plugin_definition = $this->discovery->getDefinition($plugin_id);
- $plugin_class = static::getPluginClass($plugin_id, $plugin_definition);
- return new $plugin_class($configuration, $plugin_id, $plugin_definition);
+ $plugin_class = static::getPluginClass($plugin_id, $this->discovery);
+ return new $plugin_class($configuration, $plugin_id, $this->discovery);
}
/**
* Finds the class relevant for a given plugin.
*
- * @param string $plugin_id
- * The id of a plugin.
- * @param array $plugin_definition
- * The plugin definition associated to the plugin_id.
+ * @param array $plugin_id
+ * The id of a plugin.
+ * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+ * The discovery object.
*
- * @return string
- * The appropriate class name.
+ * @return string
+ * The appropriate class name.
*/
- public static function getPluginClass($plugin_id, array $plugin_definition = NULL) {
+ public static function getPluginClass($plugin_id, DiscoveryInterface $discovery) {
+ $plugin_definition = $discovery->getDefinition($plugin_id);
if (empty($plugin_definition['class'])) {
throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
}
diff --git a/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php b/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php
index d0f11ff..7954745 100644
--- a/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php
@@ -6,6 +6,8 @@
namespace Drupal\Component\Plugin\Factory;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
/**
* Factory interface implemented by all plugin factories.
*/
diff --git a/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php b/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php
index 01f300e..50b3868 100644
--- a/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php
+++ b/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php
@@ -20,14 +20,13 @@ class ReflectionFactory extends DefaultFactory {
* Implements Drupal\Component\Plugin\Factory\FactoryInterface::createInstance().
*/
public function createInstance($plugin_id, array $configuration) {
- $plugin_definition = $this->discovery->getDefinition($plugin_id);
- $plugin_class = static::getPluginClass($plugin_id, $plugin_definition);
+ $plugin_class = static::getPluginClass($plugin_id, $this->discovery);
// Lets figure out of there's a constructor for this class and pull
// arguments from the $options array if so to populate it.
$reflector = new ReflectionClass($plugin_class);
if ($reflector->hasMethod('__construct')) {
- $arguments = $this->getInstanceArguments($reflector, $plugin_id, $plugin_definition, $configuration);
+ $arguments = $this->getInstanceArguments($reflector, $plugin_id, $configuration);
$instance = $reflector->newInstanceArgs($arguments);
}
else {
@@ -47,29 +46,28 @@ public function createInstance($plugin_id, array $configuration) {
* The reflector object being used to inspect the plugin class.
* @param string $plugin_id
* The identifier of the plugin implementation.
- * @param array $plugin_definition
- * The definition associated to the plugin_id.
* @param array $configuration
* An array of configuration that may be passed to the instance.
*
* @return array
* An array of arguments to be passed to the constructor.
*/
- protected function getInstanceArguments(ReflectionClass $reflector, $plugin_id, array $plugin_definition, array $configuration) {
+ protected function getInstanceArguments(ReflectionClass $reflector, $plugin_id, array $configuration) {
$arguments = array();
foreach ($reflector->getMethod('__construct')->getParameters() as $param) {
$param_name = $param->getName();
+ $param_class = $param->getClass();
if ($param_name == 'plugin_id') {
$arguments[] = $plugin_id;
}
- elseif ($param_name == 'plugin_definition') {
- $arguments[] = $plugin_definition;
- }
elseif ($param_name == 'configuration') {
$arguments[] = $configuration;
}
+ elseif ($param_class && $param_class->isInstance($this->discovery)) {
+ $arguments[] = $this->discovery;
+ }
elseif (isset($configuration[$param_name]) || array_key_exists($param_name, $configuration)) {
$arguments[] = $configuration[$param_name];
}
diff --git a/core/lib/Drupal/Component/Plugin/PluginBase.php b/core/lib/Drupal/Component/Plugin/PluginBase.php
index f2cc78b..58c5a3b 100644
--- a/core/lib/Drupal/Component/Plugin/PluginBase.php
+++ b/core/lib/Drupal/Component/Plugin/PluginBase.php
@@ -6,24 +6,26 @@
namespace Drupal\Component\Plugin;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
/**
* Base class for plugins wishing to support metadata inspection.
*/
abstract class PluginBase implements PluginInspectionInterface {
/**
- * The plugin_id.
+ * The discovery object.
*
- * @var string
+ * @var Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
- protected $pluginId;
+ protected $discovery;
/**
- * The plugin implementation definition.
+ * The plugin_id.
*
- * @var array
+ * @var string
*/
- protected $pluginDefinition;
+ protected $plugin_id;
/**
* Configuration information passed into the plugin.
@@ -39,27 +41,28 @@
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
- * @param array $plugin_definition
- * The plugin implementation definition.
+ * @param DiscoveryInterface $discovery
+ * The Discovery class that holds access to the plugin implementation
+ * definition.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
$this->configuration = $configuration;
- $this->pluginId = $plugin_id;
- $this->pluginDefinition = $plugin_definition;
+ $this->plugin_id = $plugin_id;
+ $this->discovery = $discovery;
}
/**
* Implements Drupal\Component\Plugin\PluginInterface::getPluginId().
*/
public function getPluginId() {
- return $this->pluginId;
+ return $this->plugin_id;
}
/**
* Implements Drupal\Component\Plugin\PluginInterface::getDefinition().
*/
public function getDefinition() {
- return $this->pluginDefinition;
+ return $this->discovery->getDefinition($this->plugin_id);
}
// Note: Plugin configuration is optional so its left to the plugin type to
diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php
index 41db679..de60da8 100644
--- a/core/lib/Drupal/Core/Config/InstallStorage.php
+++ b/core/lib/Drupal/Core/Config/InstallStorage.php
@@ -128,7 +128,7 @@ protected function getAllFolders() {
* @return array
* Folders indexed by configuration name.
*/
- protected function getComponentNames($type, array $list) {
+ public function getComponentNames($type, array $list) {
$extension = '.' . $this->getFileExtension();
$folders = array();
foreach ($list as $name) {
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 91bba3c..d4d16f3 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -88,6 +88,10 @@ public function build(ContainerBuilder $container) {
$container
->register('config.storage.schema', 'Drupal\Core\Config\Schema\SchemaStorage');
+ // Register installer configuration storage.
+ $container
+ ->register('config.storage.installer', 'Drupal\Core\Config\InstallStorage');
+
// Register the typed configuration data manager.
$container->register('config.typed', 'Drupal\Core\Config\TypedConfigManager')
->addArgument(new Reference('config.storage'))
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 785c81c..fe00ef3 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -440,14 +440,4 @@ public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
// As entities are always the root of the tree of typed data, we do not need
// to set any parent or name.
}
-
- /**
- * Implements \Drupal\Core\Entity\EntityInterface::isTranslatable().
- */
- public function isTranslatable() {
- // @todo Inject the entity manager and retrieve bundle info from it.
- $bundles = entity_get_bundles($this->entityType);
- return !empty($bundles[$this->bundle()]['translatable']);
- }
-
}
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 08be87c..a23f7e4 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -460,12 +460,4 @@ public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
public function getExportProperties() {
$this->decorated->getExportProperties();
}
-
- /**
- * Forwards the call to the decorated entity.
- */
- public function isTranslatable() {
- return $this->decorated->isTranslatable();
- }
-
}
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index b900490..34038e9 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -219,13 +219,4 @@ public function getBCEntity();
* @see \Drupal\Core\Entity\EntityInterface::getBCEntity()
*/
public function getOriginalEntity();
-
- /**
- * Returns the translation support status.
- *
- * @return bool
- * TRUE if the entity bundle has translation support enabled.
- */
- public function isTranslatable();
-
}
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index be46ac9..a0d7c03 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -75,8 +75,11 @@
* - static_cache: (optional) Boolean indicating whether entities should be
* statically cached during a page request. Used by
* Drupal\Core\Entity\DatabaseStorageController. Defaults to TRUE.
- * - translatable: (optional) Boolean indicating whether entities of this type
- * have mutlilingual support. Defaults to FALSE.
+ * - translation: (optional) An associative array of modules registered as
+ * field translation handlers. Array keys are the module names, and array
+ * values can be any data structure the module uses to provide field
+ * translation. If the value is empty, the module will not be used as a
+ * translation handler.
* - entity_keys: An array describing how the Field API can extract certain
* information from objects of this entity type. Elements:
* - id: The name of the property that contains the primary ID of the
diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
index 86f7529..45648d4 100644
--- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
+++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
@@ -24,13 +24,13 @@
/**
* Override of \Drupal\Component\Plugin\ContextAwarePluginBase::__construct().
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
$context = array();
if (isset($configuration['context'])) {
$context = $configuration['context'];
unset($configuration['context']);
}
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ parent::__construct($configuration, $plugin_id, $discovery);
foreach ($context as $key => $value) {
$context_definition = $this->getContextDefinition($key);
$this->context[$key] = new Context($context_definition);
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index f066b72..744e780 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -52,5 +52,4 @@ public function getTranslationLanguages($include_default = TRUE);
* A typed data object for the translated data.
*/
public function getTranslation($langcode, $strict = TRUE);
-
}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
index d0ea6ee..c84a761 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
@@ -31,7 +31,6 @@
* revision_table = "custom_block_revision",
* menu_base_path = "block/%custom_block",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "revision" = "revision_id",
diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php
index d32444f..9c90a5a 100644
--- a/core/modules/block/lib/Drupal/block/BlockBase.php
+++ b/core/modules/block/lib/Drupal/block/BlockBase.php
@@ -30,8 +30,8 @@
/**
* Overrides \Drupal\Component\Plugin\PluginBase::__construct().
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition, Block $entity) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery, Block $entity) {
+ parent::__construct($configuration, $plugin_id, $discovery);
$this->entity = $entity;
}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 7acbeb9..d5dedb9 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -41,9 +41,8 @@ public function __construct(array $namespaces) {
* Overrides \Drupal\Component\Plugin\PluginManagerBase::createInstance().
*/
public function createInstance($plugin_id, array $configuration = array(), Block $entity = NULL) {
- $plugin_definition = $this->discovery->getDefinition($plugin_id);
- $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition);
- return new $plugin_class($configuration, $plugin_id, $plugin_definition, $entity);
+ $plugin_class = DefaultFactory::getPluginClass($plugin_id, $this->discovery);
+ return new $plugin_class($configuration, $plugin_id, $this->discovery, $entity);
}
}
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
index f6e9091..d80a844 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
@@ -29,7 +29,6 @@
* base_table = "comment",
* uri_callback = "comment_uri",
* fieldable = TRUE,
- * translatable = TRUE,
* static_cache = FALSE,
* entity_keys = {
* "id" = "cid",
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverrideWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverrideWebTest.php
index 9f9579d..0833653 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverrideWebTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverrideWebTest.php
@@ -35,14 +35,22 @@ function testSiteNameTranslation() {
$adminUser = $this->drupalCreateUser(array('administer site configuration', 'administer languages'));
$this->drupalLogin($adminUser);
- // Add French and make it the site default language.
- $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'fr'), t('Add language'));
+ // Add a custom lanugage.
+ $langcode = 'xx';
+ $name = $this->randomName(16);
+ $edit = array(
+ 'predefined_langcode' => 'custom',
+ 'langcode' => $langcode,
+ 'name' => $name,
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
$this->drupalLogout();
// The home page in English should not have the override.
$this->drupalGet('');
- $this->assertNoText('French site name');
+ $this->assertNoText('XX site name');
// During path resolution the system.site configuration object is used to
// determine the front page. This occurs before language negotiation causing
@@ -53,8 +61,8 @@ function testSiteNameTranslation() {
// language negotiation. Ensure that it applies when we access the French
// front page.
// @see \Drupal\Core\PathProcessor::processInbound()
- $this->drupalGet('fr');
- $this->assertText('French site name');
+ $this->drupalGet('xx');
+ $this->assertText('XX site name');
}
}
diff --git a/core/modules/config/tests/config_test/config/locale.config.fr.system.site.yml b/core/modules/config/tests/config_test/config/locale.config.fr.system.site.yml
deleted file mode 100644
index 0e4081b..0000000
--- a/core/modules/config/tests/config_test/config/locale.config.fr.system.site.yml
+++ /dev/null
@@ -1 +0,0 @@
-name: 'French site name'
diff --git a/core/modules/config/tests/config_test/config/locale.config.xx.system.site.yml b/core/modules/config/tests/config_test/config/locale.config.xx.system.site.yml
new file mode 100644
index 0000000..4e3fc87
--- /dev/null
+++ b/core/modules/config/tests/config_test/config/locale.config.xx.system.site.yml
@@ -0,0 +1 @@
+name: 'XX site name'
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 40b636c..d0d59fd 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -184,13 +184,3 @@ function config_test_entity_disable(ConfigTest $config_test) {
$config_test->disable()->save();
return new RedirectResponse(url('admin/structure/config_test', array('absolute' => TRUE)));
}
-
-/**
- * Implements hook_entity_info_alter().
- */
-function config_test_entity_info_alter(&$entity_info) {
- // The 'translatable' entity key is not supposed to change over time. In this
- // case we can safely do it because we set it once and we do not change it for
- // all the duration of the test session.
- $entity_info['config_test']['translatable'] = Drupal::service('state')->get('config_test.translatable');
-}
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDatelistWidget.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDatelistWidget.php
index 2be0e27..c508911 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDatelistWidget.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDatelistWidget.php
@@ -40,8 +40,9 @@ class DateTimeDatelistWidget extends WidgetBase {
*
* @param array $plugin_id
* The plugin_id for the widget.
- * @param array $plugin_definition
- * The plugin implementation definition.
+ * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+ * The Discovery class that holds access to the widget implementation
+ * definition.
* @param \Drupal\field\FieldInstance $instance
* The field instance to which the widget is associated.
* @param array $settings
@@ -49,10 +50,10 @@ class DateTimeDatelistWidget extends WidgetBase {
* @param int $weight
* The widget weight.
*/
- public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings, $weight) {
+ public function __construct($plugin_id, DiscoveryInterface $discovery, FieldInstance $instance, array $settings, $weight) {
// Identify the function used to set the default value.
$instance['default_value_function'] = $this->defaultValueFunction();
- parent::__construct($plugin_id, $plugin_definition, $instance, $settings, $weight);
+ parent::__construct($plugin_id, $discovery, $instance, $settings, $weight);
}
/**
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDefaultWidget.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDefaultWidget.php
index 75ccad3..cd130d3 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDefaultWidget.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/widget/DatetimeDefaultWidget.php
@@ -34,8 +34,9 @@ class DateTimeDefaultWidget extends WidgetBase {
*
* @param array $plugin_id
* The plugin_id for the widget.
- * @param array $plugin_definition
- * The plugin implementation definition.
+ * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+ * The Discovery class that holds access to the widget implementation
+ * definition.
* @param \Drupal\field\FieldInstance $instance
* The field instance to which the widget is associated.
* @param array $settings
@@ -43,10 +44,10 @@ class DateTimeDefaultWidget extends WidgetBase {
* @param int $weight
* The widget weight.
*/
- public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings, $weight) {
+ public function __construct($plugin_id, DiscoveryInterface $discovery, FieldInstance $instance, array $settings, $weight) {
// Identify the function used to set the default value.
$instance['default_value_function'] = $this->defaultValueFunction();
- parent::__construct($plugin_id, $plugin_definition, $instance, $settings, $weight);
+ parent::__construct($plugin_id, $discovery, $instance, $settings, $weight);
}
/**
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index 8e5ee39..a9b33ac 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -29,9 +29,17 @@
* The available language codes for a particular field are returned by
* field_available_languages(). Whether a field is translatable is determined by
* calling field_is_translatable(), which checks the $field['translatable']
- * property returned by field_info_field() and whether the entity type the field
- * is attached to supports translation.
+ * property returned by field_info_field(), and whether there is at least one
+ * translation handler available for the field. A translation handler is a
+ * module registering itself via hook_entity_info_alter() to handle field
+ * translations.
*
+
+ * By default, _field_invoke() and _field_invoke_multiple() are processing a
+ * field in all available languages, unless they are given a language code
+ * suggestion. Based on that suggestion, _field_language_suggestion() determines
+ * the languages to act on.
+
* By default, _field_invoke() and _field_invoke_multiple() process a field in
* all available languages, unless they are given a language code suggestion.
* Based on that suggestion, _field_language_suggestion() determines the
@@ -218,12 +226,23 @@ function field_is_translatable($entity_type, $field) {
* TRUE, if the given handler is allowed to manage field translations. If no
* handler is passed, TRUE means there is at least one registered translation
* handler.
- *
- * @todo Remove this once the migration to the Entity Field API is complete.
*/
function field_has_translation_handler($entity_type, $handler = NULL) {
- $info = entity_get_info($entity_type);
- return !empty($info['translatable']);
+ $entity_info = entity_get_info($entity_type);
+
+ if (isset($handler)) {
+ return !empty($entity_info['translation'][$handler]);
+ }
+ elseif (isset($entity_info['translation'])) {
+ foreach ($entity_info['translation'] as $handler_info) {
+ // The translation handler must use a non-empty data structure.
+ if (!empty($handler_info)) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
}
/**
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
index 92d6fba..04a038d 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php
@@ -7,6 +7,7 @@
namespace Drupal\field\Plugin\Type\Formatter;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Plugin\PluginSettingsBase;
use Drupal\field\FieldInstance;
@@ -56,8 +57,9 @@
*
* @param string $plugin_id
* The plugin_id for the formatter.
- * @param array $plugin_definition
- * The plugin implementation definition.
+ * @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+ * The Discovery class that holds access to the formatter implementation
+ * definition.
* @param Drupal\field\FieldInstance $instance
* The field instance to which the formatter is associated.
* @param array $settings
@@ -67,8 +69,8 @@
* @param string $view_mode
* The view mode.
*/
- public function __construct($plugin_id, array $plugin_definition, $instance, array $settings, $label, $view_mode) {
- parent::__construct(array(), $plugin_id, $plugin_definition);
+ public function __construct($plugin_id, DiscoveryInterface $discovery, $instance, array $settings, $label, $view_mode) {
+ parent::__construct(array(), $plugin_id, $discovery);
$this->instance = $instance;
$this->field = field_info_field($instance['field_name']);
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterFactory.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterFactory.php
index 0df5b97..a0bf0c2 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterFactory.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterFactory.php
@@ -18,8 +18,7 @@ class FormatterFactory extends DefaultFactory {
* Overrides Drupal\Component\Plugin\Factory\DefaultFactory::createInstance().
*/
public function createInstance($plugin_id, array $configuration) {
- $plugin_definition = $this->discovery->getDefinition($plugin_id);
- $plugin_class = static::getPluginClass($plugin_id, $plugin_definition);
- return new $plugin_class($plugin_id, $plugin_definition, $configuration['instance'], $configuration['settings'], $configuration['label'], $configuration['view_mode']);
+ $plugin_class = static::getPluginClass($plugin_id, $this->discovery);
+ return new $plugin_class($plugin_id, $this->discovery, $configuration['instance'], $configuration['settings'], $configuration['label'], $configuration['view_mode']);
}
}
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
index b60552e..12118f8 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php
@@ -7,6 +7,7 @@
namespace Drupal\field\Plugin\Type\Widget;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Plugin\PluginSettingsBase;
@@ -50,8 +51,9 @@
*
* @param array $plugin_id
* The plugin_id for the widget.
- * @param array $plugin_definition
- * The plugin implementation definition.
+ * @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
+ * The Discovery class that holds access to the widget implementation
+ * definition.
* @param Drupal\field\FieldInstance $instance
* The field instance to which the widget is associated.
* @param array $settings
@@ -59,8 +61,8 @@
* @param int $weight
* The widget weight.
*/
- public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings, $weight) {
- parent::__construct(array(), $plugin_id, $plugin_definition);
+ public function __construct($plugin_id, DiscoveryInterface $discovery, FieldInstance $instance, array $settings, $weight) {
+ parent::__construct(array(), $plugin_id, $discovery);
$this->instance = $instance;
$this->field = field_info_field($instance['field_name']);
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetFactory.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetFactory.php
index 392ef5e..4b6e7dc 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetFactory.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetFactory.php
@@ -18,8 +18,7 @@ class WidgetFactory extends DefaultFactory {
* Overrides Drupal\Component\Plugin\Factory\DefaultFactory::createInstance().
*/
public function createInstance($plugin_id, array $configuration) {
- $plugin_definition = $this->discovery->getDefinition($plugin_id);
- $plugin_class = static::getPluginClass($plugin_id, $plugin_definition);
- return new $plugin_class($plugin_id, $plugin_definition, $configuration['instance'], $configuration['settings'], $configuration['weight']);
+ $plugin_class = static::getPluginClass($plugin_id, $this->discovery);
+ return new $plugin_class($plugin_id, $this->discovery, $configuration['instance'], $configuration['settings'], $configuration['weight']);
}
}
diff --git a/core/modules/field/tests/modules/field_test/field_test.entity.inc b/core/modules/field/tests/modules/field_test/field_test.entity.inc
index 565ed08..81c116d 100644
--- a/core/modules/field/tests/modules/field_test/field_test.entity.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.entity.inc
@@ -12,8 +12,13 @@
* Implements hook_entity_info_alter().
*/
function field_test_entity_info_alter(&$entity_info) {
+ // Enable/disable field_test as a translation handler.
foreach (field_test_entity_info_translatable() as $entity_type => $translatable) {
- $entity_info[$entity_type]['translatable'] = $translatable;
+ $entity_info[$entity_type]['translation']['field_test'] = $translatable;
+ }
+ // Disable the entity type translation handler.
+ foreach ($entity_info as $entity_type => $info) {
+ $entity_info[$entity_type]['translation'][$entity_type] = FALSE;
}
}
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 1c20695..81b9715 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -210,7 +210,11 @@ function language_theme() {
function language_entity_supported() {
$supported = array();
foreach (entity_get_info() as $entity_type => $info) {
- if (!empty($info['fieldable']) && !empty($info['translatable'])) {
+ // @todo Revisit this once all core entities are migrated to the Entity
+ // Field API and language support for configuration entities has been
+ // sorted out.
+ $entity_class = new ReflectionClass($info['class']);
+ if ($info['fieldable'] && !$entity_class->implementsInterface('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$supported[$entity_type] = $entity_type;
}
}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
index 726b40e..06aa112 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
@@ -7,6 +7,7 @@
namespace Drupal\layout\Plugin\layout\layout;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\layout\Plugin\LayoutInterface;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Annotation\Plugin;
@@ -22,13 +23,15 @@ class StaticLayout extends PluginBase implements LayoutInterface {
/**
* Overrides Drupal\Component\Plugin\PluginBase::__construct().
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- foreach ($plugin_definition['regions'] as $region => $title) {
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ // Get definition by discovering the declarative information.
+ $definition = $discovery->getDefinition($plugin_id);
+ foreach ($definition['regions'] as $region => $title) {
if (!isset($configuration['regions'][$region])) {
$configuration['regions'][$region] = array();
}
}
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ parent::__construct($configuration, $plugin_id, $discovery);
}
/**
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleBundle.php b/core/modules/locale/lib/Drupal/locale/LocaleBundle.php
index 7c2ca6e..61eae0a 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleBundle.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleBundle.php
@@ -24,6 +24,11 @@ public function build(ContainerBuilder $container) {
->addArgument(new Reference('language_manager'))
->addArgument(new Reference('config.context'))
->addTag('event_subscriber');
+ // Register the locale configuration data manager.
+ $container->register('locale.config.typed', 'Drupal\locale\LocaleConfigManager')
+ ->addArgument(new Reference('config.storage'))
+ ->addArgument(new Reference('config.storage.schema'))
+ ->addArgument(new Reference('config.storage.installer'));
}
}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
new file mode 100644
index 0000000..87cace7
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
@@ -0,0 +1,282 @@
+installStorage = $installStorage;
+ $this->localeStorage = $localeStorage ?: locale_storage();
+ }
+
+ /**
+ * Gets locale wrapper with typed configuration data.
+ *
+ * @param string $name
+ * Configuration object name.
+ *
+ * @return \Drupal\locale\LocaleTypedConfig
+ * Locale-wrapped configuration element.
+ */
+ public function get($name) {
+ // Read default and current configuration data.
+ $default = $this->installStorage->read($name);
+ $updated = $this->configStorage->read($name);
+ // We get only the data that didn't change from default.
+ $data = $this->compareConfigData($default, $updated);
+ $definition = $this->getDefinition($name);
+ // Unless the configuration has a explicit language code we assume English.
+ $langcode = isset($default['langcode']) ? $default['langcode'] : 'en';
+ $wrapper = new LocaleTypedConfig($definition, $name, $langcode, $this);
+ $wrapper->setValue($data);
+ return $wrapper;
+ }
+
+ /**
+ * Compares default configuration with updated data.
+ *
+ * @param array $default
+ * Default configuration data.
+ * @param array|false $updated
+ * Current configuration data, or FALSE if no configuration data existed.
+ *
+ * @return array
+ * The elements of default configuration that haven't changed.
+ */
+ protected function compareConfigData(array $default, $updated) {
+ // Speed up comparison, specially for install operations.
+ if ($default === $updated) {
+ return $default;
+ }
+ $result = array();
+ foreach ($default as $key => $value) {
+ if (isset($updated[$key])) {
+ if (is_array($value)) {
+ $result[$key] = $this->compareConfigData($value, $updated[$key]);
+ }
+ elseif ($value === $updated[$key]) {
+ $result[$key] = $value;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Saves translated configuration data.
+ *
+ * @param string $name
+ * Configuration object name.
+ * @param string $langcode
+ * Language code.
+ * @param array $data
+ * Configuration data to be saved, that will be only the translated values.
+ */
+ public function saveTranslationData($name, $langcode, array $data) {
+ $locale_name = 'locale.config.' . $langcode . '.' . $name;
+ $this->configStorage->write($locale_name, $data);
+ }
+
+ /**
+ * Deletes translated configuration data.
+ *
+ * @param string $name
+ * Configuration object name.
+ * @param string $langcode
+ * Language code.
+ */
+ public function deleteTranslationData($name, $langcode) {
+ $locale_name = 'locale.config.' . $langcode . '.' . $name;
+ $this->configStorage->delete($locale_name);
+ }
+
+ /**
+ * Gets configuration names associated with components.
+ *
+ * @param array $components
+ * (optional) Array of component lists indexed by type. If not present or it
+ * is an empty array, it will update all components.
+ *
+ * @return array
+ * Array of configuration object names.
+ */
+ public function getComponentNames(array $components) {
+ $components = array_filter($components);
+ if ($components) {
+ $names = array();
+ foreach ($components as $type => $list) {
+ // InstallStorage::getComponentNames returns a list of folders keyed by
+ // config name.
+ $names = array_merge($names, array_keys($this->installStorage->getComponentNames($type, $list)));
+ }
+ return $names;
+ }
+ else {
+ return $this->installStorage->listAll();
+ }
+ }
+
+ /**
+ * Deletes configuration translations for uninstalled components.
+ *
+ * @param array $components
+ * Array with string identifiers.
+ * @param array $langcodes
+ * Array of language codes.
+ */
+ public function deleteComponentTranslations(array $components, array $langcodes) {
+ $names = $this->getComponentNames($components);
+ if ($names && $langcodes) {
+ foreach ($names as $name) {
+ foreach ($langcodes as $langcode) {
+ $this->deleteTranslationData($name, $langcode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets configuration names associated with strings.
+ *
+ * @param array $lids
+ * Array with string identifiers.
+ *
+ * @return array
+ * Array of configuration object names.
+ */
+ public function getStringNames(array $lids) {
+ $names = array();
+ $locations = $this->localeStorage->getLocations(array('sid' => $lids, 'type' => 'configuration'));
+ foreach ($locations as $location) {
+ $names[$location->name] = $location->name;
+ }
+ return $names;
+ }
+
+ /**
+ * Deletes configuration for language.
+ *
+ * @param string $langcode
+ * Language code to delete.
+ */
+ public function deleteLanguageTranslations($langcode) {
+ $locale_name = 'locale.config.' . $langcode;
+ foreach ($this->configStorage->listAll($locale_name) as $name) {
+ $this->configStorage->delete($name);
+ }
+ }
+
+ /**
+ * Translates string using the localization system.
+ *
+ * So far we only know how to translate strings from English so the source
+ * string should be in English.
+ * Unlike regular t() translations, strings will be added to the source
+ * tables only if this is marked as default data.
+ *
+ * @param string $name
+ * Name of the configuration location.
+ * @param string $langcode
+ * Language code to translate to.
+ * @param string $source
+ * The source string, should be English.
+ * @param string $context
+ * The string context.
+ *
+ * @return string|false
+ * Translated string if there is a translation, FALSE if not.
+ */
+ public function translateString($name, $langcode, $source, $context) {
+ if ($source) {
+ // If translations for a language have not been loaded yet.
+ if (!isset($this->translations[$name][$langcode])) {
+ // Preload all translations for this configuration name and language.
+ $this->translations[$name][$langcode] = array();
+ foreach ($this->localeStorage->getTranslations(array('language' => $langcode, 'type' => 'configuration', 'name' => $name)) as $string){
+ $this->translations[$name][$langcode][$string->context][$string->source] = $string;
+ }
+ }
+ if (!isset($this->translations[$name][$langcode][$context][$source])) {
+ // There is no translation of the source string in this config location
+ // to this language for this context.
+ if ($translation = $this->localeStorage->findTranslation(array('source' => $source, 'context' => $context, 'language' => $langcode))) {
+ // Look for a translation of the string. It might have one, but not
+ // be saved in this configuration location yet.
+ // If the string has a translation for this context to this language,
+ // save it in the configuration location so it can be looked up faster
+ // next time.
+ $string = $this->localeStorage->createString((array) $translation)
+ ->addLocation('configuration', $name)
+ ->save();
+ }
+ else {
+ // No translation was found. Add the source to the configuration
+ // location so it can be translated, and the string is faster to look
+ // for next time.
+ $translation = $this->localeStorage
+ ->createString(array('source' => $source, 'context' => $context))
+ ->addLocation('configuration', $name)
+ ->save();
+ }
+
+ // Add an entry, either the translation found, or a blank string object
+ // to track the source string, to this configuration location, language,
+ // and context.
+ $this->translations[$name][$langcode][$context][$source] = $translation;
+ }
+
+ $translation = $this->translations[$name][$langcode][$context][$source];
+ // Return the string only when the string object had a translation.
+ return $translation->isTranslation() ? $translation->getString() : FALSE;
+ }
+ return FALSE;
+ }
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
new file mode 100644
index 0000000..1784bae
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php
@@ -0,0 +1,209 @@
+langcode = $langcode;
+ $this->localeConfig = $localeConfig;
+ }
+
+ /**
+ * Gets wrapped typed config object.
+ */
+ public function getTypedConfig() {
+ return $this->localeConfig->create($this->definition, $this->value);
+ }
+
+ /**
+ * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslationLanguages().
+ */
+ public function getTranslationLanguages($include_default = TRUE) {
+ $languages = locale_translatable_language_list();
+ if ($include_default) {
+ $default = $this->language();
+ $languages[$default->langcode] = $default;
+ }
+ else {
+ unset($languages[$this->langcode]);
+ }
+ return $languages;
+ }
+
+ /**
+ * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslation().
+ */
+ public function getTranslation($langcode, $strict = TRUE) {
+ $options = array(
+ 'source' => $this->langcode,
+ 'target' => $langcode,
+ 'strict' => $strict,
+ );
+ $data = $this->getElementTranslation($this->getTypedConfig(), $options);
+ return $this->localeConfig->create($this->definition, isset($data) ? $data : array());
+ }
+
+ /**
+ * Implements \Drupal\Core\TypedData\TranslatableInterface::language().
+ */
+ public function language() {
+ return new Language(array('langcode' => $this->langcode));
+ }
+
+ /**
+ * Checks whether we can translate these languages.
+ *
+ * @param string $from_langcode
+ * Source language code.
+ * @param string $to_langcode
+ * Destination language code.
+ *
+ * @return bool
+ * TRUE if this translator supports translations for these languages.
+ */
+ protected function canTranslate($from_langcode, $to_langcode) {
+ if ($from_langcode == 'en') {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /**
+ * Gets translated configuration data for a typed configuration element.
+ *
+ * @param mixed $element
+ * Typed configuration element, either \Drupal\Core\Config\Schema\Element or
+ * \Drupal\Core\Config\Schema\ArrayElement.
+ * @param array $options
+ * Array with translation options that must contain the keys defined in
+ * \Drupal\locale\LocaleTypedConfig::translateElement()
+ *
+ * @return array
+ * Configuration data translated to the requested language.
+ */
+ protected function getElementTranslation($element, array $options) {
+ $translation = NULL;
+ if ($element instanceof ArrayElement) {
+ $translation = $this->getArrayTranslation($element, $options);
+ }
+ elseif ($this->translateElement($element, $options) || empty($options['strict'])) {
+ $translation = $element->getValue();
+ }
+ if ($translation || empty($options['strict'])) {
+ return $translation;
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ /**
+ * Gets translated configuration data for an element of type ArrayElement.
+ *
+ * @param \Drupal\Core\Config\Schema\ArrayElement $element
+ * Typed configuration array element.
+ * @param array $options
+ * Array with translation options that must contain the keys defined in
+ * \Drupal\locale\LocaleTypedConfig::translateElement()
+ *
+ * @return array
+ * Configuration data translated to the requested language.
+ */
+ protected function getArrayTranslation(ArrayElement $element, array $options) {
+ $translation = array();
+ foreach ($element as $key => $property) {
+ $value = $this->getElementTranslation($property, $options);
+ if (isset($value)) {
+ $translation[$key] = $value;
+ }
+ }
+ return $translation;
+ }
+
+ /**
+ * Translates element's value if it fits our translation criteria.
+ *
+ * For an element to be translatable by locale module it needs to be of base
+ * type 'string' and have 'translatable = TRUE' in the element's definition.
+ * Translatable elements may use these additional keys in their data
+ * definition:
+ * - 'translatable', FALSE to opt out of translation.
+ * - 'locale context', to define the string context.
+ *
+ * @param \Drupal\Core\TypedData\TypedDataInterface $element
+ * Configuration element.
+ * @param array $options
+ * Array with translation options that must contain the following keys:
+ * - 'source', Source language code.
+ * - 'target', Target language code.
+ * - 'strict', True to return only elements that actually have translation.
+ *
+ * @return bool
+ * Whether the element fits the translation criteria.
+ */
+ protected function translateElement(\Drupal\Core\TypedData\TypedDataInterface $element, array $options) {
+ if ($this->canTranslate($options['source'], $options['target'])) {
+ $definition = $element->getDefinition();
+ $value = $element->getValue();
+ if ($value && !empty($definition['translatable'])) {
+ $context = isset($definition['locale context']) ? $definition['locale context'] : '';
+ if ($translation = $this->localeConfig->translateString($this->name, $options['target'], $value, $context)) {
+ $element->setValue($translation);
+ return TRUE;
+ }
+ }
+ }
+ // The element does not have a translation. If strict mode we drop it.
+ return empty($options['strict']);
+ }
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php b/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php
index 618b419..126ee04 100644
--- a/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php
+++ b/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php
@@ -102,6 +102,7 @@ function setReport($report = array()) {
'updates' => 0,
'deletes' => 0,
'skips' => 0,
+ 'strings' => array(),
);
$this->_report = $report;
}
@@ -259,6 +260,7 @@ private function importString(PoItem $item) {
$string->save();
$this->_report['updates']++;
}
+ $this->_report['strings'][] = $string->getId();
return $string->lid;
}
else {
@@ -273,6 +275,7 @@ private function importString(PoItem $item) {
))->save();
$this->_report['additions']++;
+ $this->_report['strings'][] = $string->getId();
return $string->lid;
}
}
@@ -280,6 +283,7 @@ private function importString(PoItem $item) {
// Empty translation, remove existing if instructed.
$string->delete();
$this->_report['deletes']++;
+ $this->_report['strings'][] = $string->lid;
return $string->lid;
}
}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
new file mode 100644
index 0000000..eb5a1f3
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
@@ -0,0 +1,155 @@
+ 'Configuration translation',
+ 'description' => 'Tests translation of configuration strings.',
+ 'group' => 'Locale',
+ );
+ }
+
+ public function setUp() {
+ parent::setUp();
+ // Add a default locale storage for all these tests.
+ $this->storage = locale_storage();
+ }
+
+ /**
+ * Tests basic configuration translation.
+ */
+ function testConfigTranslation() {
+ // Add custom language.
+ $langcode = 'xx';
+ $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'translate interface', 'administer modules'));
+ $this->drupalLogin($admin_user);
+ $name = $this->randomName(16);
+ $edit = array(
+ 'predefined_langcode' => 'custom',
+ 'langcode' => $langcode,
+ 'name' => $name,
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+ $language = new Language(array('langcode' => $langcode));
+ // Set path prefix.
+ $edit = array( "prefix[$langcode]" => $langcode );
+ $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
+
+ // Check site name string exists and create translation for it.
+ $string = $this->storage->findString(array('source' => 'Drupal', 'context' => '', 'type' => 'configuration'));
+ $this->assertTrue($string, 'Configuration strings have been created upon installation.');
+
+ // Translate using the UI so configuration is refreshed.
+ $site_name = $this->randomName(20);
+ $search = array(
+ 'string' => $string->source,
+ 'langcode' => $langcode,
+ 'translation' => 'all',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ $textareas = $this->xpath('//textarea');
+ $textarea = current($textareas);
+ $lid = (string) $textarea[0]['name'];
+ $edit = array(
+ $lid => $site_name,
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
+
+ $wrapper = locale_config()->get('system.site');
+
+ // Get strict translation and check we've got only the site name.
+ $translation = $wrapper->getTranslation($langcode, TRUE);
+ $properties = $translation->getProperties();
+ $this->assertEqual(count($properties), 1, 'Got the right number of properties with strict translation');
+ $this->assertEqual($properties['name']->getValue(), $site_name, 'Got the right translation for site name with strict translation');
+
+ // Get non strict translation and check we've got all properties.
+ $translation = $wrapper->getTranslation($langcode, FALSE);
+ $properties = $translation->getProperties();
+ $this->assertTrue(count($properties) == 5 && count($translation->get('page')) == 3, 'Got the right number of properties with non strict translation');
+ $this->assertEqual($properties['name']->getValue(), $site_name, 'Got the right translation for site name with non strict translation');
+
+ // Check the translated site name is displayed.
+ $this->drupalGet($langcode);
+ $this->assertText($site_name, 'The translated site name is displayed after translations refreshed.');
+
+ // Assert strings from image module config are not available.
+ $string = $this->storage->findString(array('source' => 'Medium (220x220)', 'context' => '', 'type' => 'configuration'));
+ $this->assertFalse($string, 'Configuration strings have been created upon installation.');
+
+ // Enable the image module.
+ $this->drupalPost('admin/modules', array('modules[Core][image][enable]' => "1"), t('Save configuration'));
+ $this->resetAll();
+
+ $string = $this->storage->findString(array('source' => 'Medium (220x220)', 'context' => '', 'type' => 'configuration'));
+ $this->assertTrue($string, 'Configuration strings have been created upon installation.');
+ $locations = $string->getLocations();
+ $this->assertTrue(isset($locations['configuration']) && isset($locations['configuration']['image.style.medium']), 'Configuration string has been created with the right location');
+
+ // Check the string is unique and has no translation yet.
+ $translations = $this->storage->getTranslations(array('language' => $langcode, 'type' => 'configuration', 'name' => 'image.style.medium'));
+ $translation = reset($translations);
+ $this->assertTrue(count($translations) == 1 && $translation->source == $string->source && empty($translation->translation), 'Got only one string for image configuration and has no translation.');
+
+ // Translate using the UI so configuration is refreshed.
+ $image_style_label = $this->randomName(20);
+ $search = array(
+ 'string' => $string->source,
+ 'langcode' => $langcode,
+ 'translation' => 'all',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
+ $edit = array(
+ $lid => $image_style_label,
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
+
+ // Check the right single translation has been created.
+ $translations = $this->storage->getTranslations(array('language' => $langcode, 'type' => 'configuration', 'name' => 'image.style.medium'));
+ $translation = reset($translations);
+ $this->assertTrue(count($translations) == 1 && $translation->source == $string->source && $translation->translation == $image_style_label, 'Got only one translation for image configuration.');
+
+ // Try more complex configuration data.
+ $wrapper = locale_config()->get('image.style.medium');
+ $translation = $wrapper->getTranslation($langcode, TRUE);
+ $property = $translation->get('label');
+ $this->assertEqual($property->getValue(), $image_style_label, 'Got the right translation for image style name with strict translation');
+
+ // Quick test to ensure translation file exists.
+ $this->assertEqual(config('locale.config.xx.image.style.medium')->get('label'), $image_style_label);
+
+ // Disable and uninstall the module.
+ $this->drupalPost('admin/modules', array('modules[Core][image][enable]' => FALSE), t('Save configuration'));
+ $this->drupalPost('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall'));
+ $this->drupalPost(NULL, array(), t('Uninstall'));
+
+ // Ensure that the translated configuration has been removed.
+ $this->assertFalse(config('locale.config.xx.image.style.medium')->get('label'), 'Translated configuration for image module removed.');
+ }
+
+}
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index 6a452d8..5690736 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -6,9 +6,12 @@
*/
use Drupal\Component\Gettext\PoStreamWriter;
+use Drupal\locale\LocaleTypedConfig;
use Drupal\locale\Gettext;
use Drupal\locale\PoDatabaseReader;
use Drupal\Core\Language\Language;
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\Config\StorageException;
/**
@@ -123,6 +126,7 @@ function locale_translate_import_form_submit($form, &$form_state) {
'langcode' => $form_state['values']['langcode'],
'overwrite_options' => $form_state['values']['overwrite_options'],
'customized' => $form_state['values']['customized'] ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED,
+ 'refresh_configuration' => TRUE,
);
$file = locale_translate_file_attach_properties($file, $options);
$batch = locale_translate_batch_build(array($file->uri => $file), $options);
@@ -277,6 +281,8 @@ function locale_translate_export_form_submit($form, &$form_state) {
* are customized translations or come from a community source. Use
* LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED. Optional, defaults to
* LOCALE_NOT_CUSTOMIZED.
+ * - 'refresh_configuration': Whether or not to refresh configuration strings
+ * after the import. Optional, defaults to FALSE.
* - 'finish_feedback': Whether or not to give feedback to the user when the
* batch is finished. Optional, defaults to TRUE.
*
@@ -389,6 +395,7 @@ function locale_translate_batch_build($files, $options) {
'overwrite_options' => array(),
'customized' => LOCALE_NOT_CUSTOMIZED,
'finish_feedback' => TRUE,
+ 'refresh_configuration' => FALSE,
);
$t = get_t();
if (count($files)) {
@@ -400,6 +407,9 @@ function locale_translate_batch_build($files, $options) {
// Save the translation status of all files.
$operations[] = array('locale_translate_batch_import_save', array());
+ // Add a final step to refresh JavaScript and configuration strings.
+ $operations[] = array('locale_translate_batch_refresh', array($options));
+
$batch = array(
'operations' => $operations,
'title' => $t('Importing interface translations'),
@@ -537,12 +547,72 @@ function locale_translate_batch_import_save($context) {
}
/**
+ * Refreshs translations after importing strings.
+ *
+ * @param array $options
+ * An array with options that can have the following elements:
+ * - 'refresh_configuration': (optional) Whether or not to refresh configuration
+ * strings after the import. Defaults to FALSE.
+ * @param array $context
+ * Contains a list of strings updated and information about the progress.
+ */
+function locale_translate_batch_refresh(array $options, array &$context) {
+ if (!isset($context['sandbox']['refresh'])) {
+ $strings = $langcodes = array();
+ if (isset($context['results']['stats'])) {
+ // Get list of unique string identifiers and language codes updated.
+ $langcodes = array_unique(array_values($context['results']['languages']));
+ foreach ($context['results']['stats'] as $filepath => $report) {
+ $strings = array_merge($strings, $report['strings']);
+ }
+ }
+ if ($strings) {
+ // Initialize multi-step string refresh.
+ $context['message'] = t('Updating translations for JavaScript and Configuration strings.');
+ $context['sandbox']['refresh']['strings'] = array_unique($strings);
+ $context['sandbox']['refresh']['languages'] = $langcodes;
+ if (!empty($options['refresh_configuration'])) {
+ $context['sandbox']['refresh']['names'] = array();
+ $context['results']['stats']['config'] = 0;
+ }
+ $context['sandbox']['refresh']['count'] = count($strings);
+
+ // We will update strings on later steps.
+ $context['finished'] = 1 - 1 / $context['sandbox']['refresh']['count'];
+ }
+ else {
+ $context['finished'] = 1;
+ }
+ }
+ elseif (!empty($options['refresh_configuration']) && $name = array_shift($context['sandbox']['refresh']['names'])) {
+ // Refresh all languages for one object at a time.
+ $count = locale_config_update_multiple(array($name), $context['sandbox']['refresh']['languages']);
+ $context['results']['stats']['config'] += $count;
+ }
+ elseif (!empty($context['sandbox']['refresh']['strings'])) {
+ // Not perfect but will give some indication of progress.
+ $context['finished'] = 1 - count($context['sandbox']['refresh']['strings']) / $context['sandbox']['refresh']['count'];
+ // Pending strings, refresh 100 at a time, get next pack.
+ $next = array_slice($context['sandbox']['refresh']['strings'], 0, 100);
+ array_splice($context['sandbox']['refresh']['strings'], 0, count($next));
+ // Clear cache and force refresh of JavaScript translations.
+ _locale_refresh_translations($context['sandbox']['refresh']['languages'], $next);
+ // Check whether we need to refresh configuration objects.
+ if (!empty($options['refresh_configuration']) && $names = locale_config()->getStringNames($next)) {
+ $context['sandbox']['refresh']['names'] = $names;
+ }
+ }
+ else {
+ $context['finished'] = 1;
+ }
+}
+
+/**
* Finished callback of system page locale import batch.
*/
function locale_translate_batch_finished($success, $results) {
if ($success) {
- $additions = $updates = $deletes = $skips = 0;
- $langcodes = array();
+ $additions = $updates = $deletes = $skips = $config = 0;
if (isset($results['failed_files'])) {
if (module_exists('dblog')) {
$message = format_plural(count($results['failed_files']), 'One translation file could not be imported. See the log for details.', '@count translation files could not be imported. See the log for details.', array('@url' => url('admin/reports/dblog')));
@@ -566,8 +636,6 @@ function locale_translate_batch_finished($success, $results) {
$skipped_files[] = $filepath;
}
}
- // Get list of unique language codes updated.
- $langcodes = array_unique(array_values($results['languages']));
}
drupal_set_message(format_plural(count($results['files']),
'One translation file imported. %number translations were added, %update translations were updated and %delete translations were removed.',
@@ -586,11 +654,12 @@ function locale_translate_batch_finished($success, $results) {
drupal_set_message($message, 'warning');
watchdog('locale', '@count disallowed HTML string(s) in files: @files.', array('@count' => $skips, '@files' => implode(',', $skipped_files)), WATCHDOG_WARNING);
}
-
- // Clear cache and force refresh of JavaScript translations.
- _locale_refresh_translations($langcodes);
}
}
+ // Add messages for configuration too.
+ if (isset($results['stats']['config'])) {
+ locale_config_batch_finished($success, $results);
+ }
}
/**
@@ -611,7 +680,7 @@ function locale_translate_file_create($filepath) {
}
/**
- * Generate file properties from filename and options.
+ * Generates file properties from filename and options.
*
* An attempt is made to determine the translation language, project name and
* project version from the file name. Supported file name patterns are:
@@ -685,3 +754,136 @@ function locale_translate_delete_translation_files($projects = array(), $langcod
}
return !$fail;
}
+
+/**
+ * Builds a locale batch to refresh configuration.
+ *
+ * @param array $options
+ * An array with options that can have the following elements:
+ * - 'finish_feedback': (optional) Whether or not to give feedback to the user
+ * when the batch is finished. Defaults to TRUE.
+ * @param array $langcodes
+ * (optional) Array of language codes. Defaults to all translatable languages.
+ * @param array $components
+ * (optional) Array of component lists indexed by type. If not present or it
+ * is an empty array, it will update all components.
+ *
+ * @return array
+ * The batch definition.
+ */
+function locale_config_batch_update_components(array $options, $langcodes = array(), $components = array()) {
+ $langcodes = $langcodes ? $langcodes : array_keys(locale_translatable_language_list());
+ if ($langcodes && $names = locale_config()->getComponentNames($components)) {
+ return locale_config_batch_build($names, $langcodes, $options);
+ }
+}
+
+/**
+ * Creates a locale batch to refresh specific configuration.
+ *
+ * @param array $names
+ * List of configuration object names (which are strings) to update.
+ * @param array $langcodes
+ * List of language codes to refresh.
+ * @param array $options
+ * (optional) An array with options that can have the following elements:
+ * - 'finish_feedback': Whether or not to give feedback to the user when the
+ * batch is finished. Defaults to TRUE.
+ *
+ * @return array
+ * The batch definition.
+ *
+ * @see locale_config_batch_refresh_name()
+ */
+function locale_config_batch_build(array $names, array $langcodes, $options = array()) {
+ $options += array('finish_feedback' => TRUE);
+ $t = get_t();
+ foreach ($names as $name) {
+ $operations[] = array('locale_config_batch_refresh_name', array($name, $langcodes));
+ }
+ $batch = array(
+ 'operations' => $operations,
+ 'title' => $t('Updating configuration translations'),
+ 'init_message' => $t('Starting configuration update'),
+ 'error_message' => $t('Error updating configuration translations'),
+ 'file' => drupal_get_path('module', 'locale') . '/locale.bulk.inc',
+ );
+ if (!empty($options['finish_feedback'])) {
+ $batch['completed'] = 'locale_config_batch_finished';
+ }
+ return $batch;
+}
+
+/**
+ * Performs configuration translation refresh as a batch step.
+ *
+ * @param string $name
+ * Name of configuration object to update.
+ * @param array $langcodes
+ * (optional) Array of language codes to update. Defaults to all languages.
+ * @param array $context
+ * Contains a list of files imported.
+ *
+ * @see locale_config_batch_build()
+ */
+function locale_config_batch_refresh_name($name, array $langcodes, array &$context) {
+ if (!isset($context['result']['stats']['config'])) {
+ $context['result']['stats']['config'] = 0;
+ }
+ $context['result']['stats']['config'] += locale_config_update_multiple(array($name), $langcodes);
+ $context['result']['names'][] = $name;
+ $context['result']['langcodes'] = $langcodes;
+ $context['finished'] = 1;
+}
+
+/**
+ * Finishes callback of system page locale import batch.
+ *
+ * @param bool $success
+ * Information about the success of the batch import.
+ * @param array $results
+ * Information about the results of the batch import.
+ */
+function locale_config_batch_finished($success, array $results) {
+ if ($success) {
+ $configuration = isset($results['stats']['config']) ? $results['stats']['config'] : 0;
+ if ($configuration) {
+ drupal_set_message(t('The configuration was successfully updated. There are %number configuration objects updated.', array('%number' => $configuration)));
+ watchdog('locale', 'The configuration was successfully updated. %number configuration objects updated.', array('%number' => $configuration));
+ }
+ else {
+ drupal_set_message(t('No configuration objects have been updated.'));
+ watchdog('locale', 'No configuration objects have been updated.', array(), WATCHDOG_WARNING);
+ }
+ }
+}
+
+/**
+ * Updates all configuration for names / languages.
+ *
+ * @param array $names
+ * Array of names of configuration objects to update.
+ * @param array $langcodes
+ * (optional) Array of language codes to update. Defaults to all languages.
+ *
+ * @return int
+ * Number of configuration objects retranslated.
+ */
+function locale_config_update_multiple(array $names, $langcodes = array()) {
+ $langcodes = $langcodes ? $langcodes : array_keys(locale_translatable_language_list());
+ $count = 0;
+ foreach ($names as $name) {
+ $wrapper = locale_config()->get($name);
+ foreach ($langcodes as $langcode) {
+ $translation = $wrapper->getValue() ? $wrapper->getTranslation($langcode, TRUE)->getValue() : NULL;
+ if ($translation) {
+ locale_config()->saveTranslationData($name, $langcode, $translation);
+ $count++;
+ }
+ else {
+ locale_config()->deleteTranslationData($name, $langcode);
+ }
+ }
+ }
+ return $count;
+}
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 880e335..9fd46d0 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -319,6 +319,9 @@ function locale_language_delete($language) {
module_load_include('inc', 'locale', 'locale.bulk');
locale_translate_delete_translation_files(array(), array($language->langcode));
+ // Remove translated configuration objects.
+ locale_config()->deleteLanguageTranslations($language->langcode);
+
// Changing the language settings impacts the interface:
_locale_invalidate_js($language->langcode);
cache('page')->deleteAll();
@@ -473,14 +476,16 @@ function locale_get_plural($count, $langcode = NULL) {
* Implements hook_modules_installed().
*/
function locale_modules_installed($modules) {
- locale_system_update($modules);
+ $components['module'] = $modules;
+ locale_system_update($components);
}
/**
* Implements hook_modules_uninstalled().
*/
function locale_modules_uninstalled($modules) {
- locale_system_remove($modules);
+ $components['module'] = $modules;
+ locale_system_remove($components);
}
/**
@@ -490,14 +495,16 @@ function locale_modules_uninstalled($modules) {
* initial installation. The theme system is missing an installation hook.
*/
function locale_themes_enabled($themes) {
- locale_system_update($themes);
+ $components['theme'] = $themes;
+ locale_system_update($components);
}
/**
* Implements hook_themes_disabled().
*/
function locale_themes_disabled($themes) {
- locale_system_remove($themes);
+ $components['theme'] = $themes;
+ locale_system_remove($components);
}
/**
@@ -507,10 +514,14 @@ function locale_themes_disabled($themes) {
* components.
*
* @param array $components
- * An array of component (theme and/or module) names to import
- * translations for.
+ * An array of arrays of component (theme and/or module) names to import
+ * translations for, indexed by type.
*/
-function locale_system_update($components) {
+function locale_system_update(array $components) {
+
+ $components += array('module' => array(), 'theme' => array());
+ $list = array_merge($components['module'], $components['theme']);
+
// Skip running the translation imports if in the installer,
// because it would break out of the installer flow. We have
// built-in support for translation imports in the installer.
@@ -521,11 +532,15 @@ function locale_system_update($components) {
// Only when new projects are added the update batch will be triggered. Not
// each enabled module will introduce a new project. E.g. sub modules.
$projects = array_keys(locale_translation_build_projects());
- if ($components = array_intersect($components, $projects)) {
+ if ($list = array_intersect($list, $projects)) {
module_load_include('fetch.inc', 'locale');
// Get translation status of the projects, download and update translations.
$options = _locale_translation_default_update_options();
- $batch = locale_translation_batch_update_build($components, array(), $options);
+ $batch = locale_translation_batch_update_build($list, array(), $options);
+ batch_set($batch);
+ }
+ module_load_include('bulk.inc', 'locale');
+ if ($batch = locale_config_batch_update_components(array(), array(), $components)) {
batch_set($batch);
}
}
@@ -539,37 +554,41 @@ function locale_system_update($components) {
* modules and we have no record of which string is used by which module.
*
* @param array $components
- * An array of component (theme and/or module) names to remove
- * translation history.
+ * An array of arrays of component (theme and/or module) names to import
+ * translations for, indexed by type.
*/
function locale_system_remove($components) {
- if (locale_translatable_language_list()) {
+ $components += array('module' => array(), 'theme' => array());
+ $list = array_merge($components['module'], $components['theme']);
+ if ($language_list = locale_translatable_language_list()) {
module_load_include('compare.inc', 'locale');
+ module_load_include('bulk.inc', 'locale');
+ // Delete configuration translations.
+ locale_config()->deleteComponentTranslations($components, array_keys($language_list));
// Only when projects are removed, the translation files and records will be
// deleted. Not each disabled module will remove a project. E.g. sub modules.
$projects = array_keys(locale_translation_get_projects());
- if ($components = array_intersect($components, $projects)) {
- locale_translation_file_history_delete($components);
+ if ($list = array_intersect($list, $projects)) {
+ locale_translation_file_history_delete($list);
// Remove translation files.
- module_load_include('inc', 'locale', 'locale.bulk');
- locale_translate_delete_translation_files($components, array());
+ locale_translate_delete_translation_files($list, array());
// Remove translatable projects.
// Followup issue http://drupal.org/node/1842362 to replace the
// {locale_project} table. Then change this to a function call.
db_delete('locale_project')
- ->condition('name', $components)
+ ->condition('name', $list)
->execute();
// Clear the translation status.
- locale_translation_status_delete_projects($components);
+ locale_translation_status_delete_projects($list);
}
+
}
}
-
/**
* Implements hook_js_alter().
*
@@ -772,6 +791,12 @@ function locale_form_language_admin_add_form_alter_submit($form, $form_state) {
$options = _locale_translation_default_update_options();
$batch = locale_translation_batch_update_build(array(), array($langcode), $options);
batch_set($batch);
+
+ // Create or update all configuration translations for this language.
+ module_load_include('bulk.inc', 'locale');
+ if ($batch = locale_config_batch_update_components($options, array($langcode))) {
+ batch_set($batch);
+ }
}
/**
@@ -1051,6 +1076,25 @@ function _locale_refresh_translations($langcodes, $lids = array()) {
}
/**
+ * Refreshes configuration after string translations have been updated.
+ *
+ * The information that will be refreshed includes:
+ * - JavaScript translations.
+ * - Locale cache.
+ *
+ * @param array $langcodes
+ * Language codes for updated translations.
+ * @param array $lids
+ * List of string identifiers that have been updated / created.
+ */
+function _locale_refresh_configuration(array $langcodes, array $lids) {
+ if ($lids && $langcodes && $names = locale_config()->getStringNames($lids)) {
+ module_load_include('bulk.inc', 'locale');
+ locale_config_update_multiple($names, $langcodes);
+ }
+}
+
+/**
* Parses a JavaScript file, extracts strings wrapped in Drupal.t() and
* Drupal.formatPlural() and inserts them into the database.
*
@@ -1310,3 +1354,17 @@ function _locale_rebuild_js($langcode = NULL) {
return TRUE;
}
}
+
+/**
+ * Returns the locale configuration manager service.
+ *
+ * Use the locale config manager service for creating locale-wrapped typed
+ * configuration objects.
+ *
+ * @see \Drupal\Core\TypedData\TypedDataManager::create()
+ *
+ * @return \Drupal\locale\LocaleConfigManager
+ */
+function locale_config() {
+ return drupal_container()->get('locale.config.typed');
+}
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index fc68a51..a109f5f 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -452,8 +452,9 @@ function locale_translate_edit_form_submit($form, &$form_state) {
}
if ($updated) {
- // Clear cache and force refresh of JavaScript translations.
+ // Clear cache and refresh configuration and JavaScript translations.
_locale_refresh_translations(array($langcode), $updated);
+ _locale_refresh_configuration(array($langcode), $updated);
}
}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index e367425..32c61ca 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -30,7 +30,6 @@
* revision_table = "node_revision",
* uri_callback = "node_uri",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "nid",
* "revision" = "vid",
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
index 347bfd0..747df45 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php
@@ -28,7 +28,7 @@ public function permissions() {
$definition = $this->getDefinition();
foreach ($this->availableMethods() as $method) {
$lowered_method = strtolower($method);
- $permissions["restful $lowered_method $this->pluginId"] = array(
+ $permissions["restful $lowered_method $this->plugin_id"] = array(
'title' => t('Access @method on %label resource', array('@method' => $method, '%label' => $definition['label'])),
);
}
@@ -40,8 +40,8 @@ public function permissions() {
*/
public function routes() {
$collection = new RouteCollection();
- $path_prefix = strtr($this->pluginId, ':', '/');
- $route_name = strtr($this->pluginId, ':', '.');
+ $path_prefix = strtr($this->plugin_id, ':', '/');
+ $route_name = strtr($this->plugin_id, ':', '.');
$methods = $this->availableMethods();
foreach ($methods as $method) {
@@ -49,11 +49,11 @@ public function routes() {
$route = new Route("/$path_prefix/{id}", array(
'_controller' => 'Drupal\rest\RequestHandler::handle',
// Pass the resource plugin ID along as default property.
- '_plugin' => $this->pluginId,
+ '_plugin' => $this->plugin_id,
), array(
// The HTTP method is a requirement for this route.
'_method' => $method,
- '_permission' => "restful $lower_method $this->pluginId",
+ '_permission' => "restful $lower_method $this->plugin_id",
));
switch ($method) {
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
index 03fb86b..b582a9f 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
@@ -78,7 +78,7 @@ public function post($id, EntityInterface $entity) {
$entity->save();
watchdog('rest', 'Created entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id()));
- $url = url(strtr($this->pluginId, ':', '/') . '/' . $entity->id(), array('absolute' => TRUE));
+ $url = url(strtr($this->plugin_id, ':', '/') . '/' . $entity->id(), array('absolute' => TRUE));
// 201 Created responses have an empty body.
return new ResourceResponse(NULL, 201, array('Location' => $url));
}
diff --git a/core/modules/system/config/schema/system.data_types.schema.yml b/core/modules/system/config/schema/system.data_types.schema.yml
index 422245b..a8bab2c 100644
--- a/core/modules/system/config/schema/system.data_types.schema.yml
+++ b/core/modules/system/config/schema/system.data_types.schema.yml
@@ -37,6 +37,7 @@ default:
label:
type: string
label: 'Label'
+ translatable: true
# Internal Drupal path
path:
@@ -47,6 +48,7 @@ path:
text:
type: string
label: 'Text'
+ translatable: true
# Complex extended data types:
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
index 4de550b..31844b6 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
@@ -27,7 +27,6 @@
* base_table = "entity_test_mul",
* data_table = "entity_test_mul_property_data",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
index 632ada7..a12fc58 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
@@ -28,7 +28,6 @@
* data_table = "entity_test_mulrev_property_data",
* revision_table = "entity_test_mulrev_property_revision",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockTestBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockTestBlock.php
index 04617da..63ea928 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockTestBlock.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockTestBlock.php
@@ -8,6 +8,7 @@
namespace Drupal\plugin_test\Plugin\plugin_test\mock_block;
use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Mock implementation of a test block plugin used by Plugin API unit tests.
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserLoginBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserLoginBlock.php
index 8fe8bad..e83e8cf 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserLoginBlock.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserLoginBlock.php
@@ -8,6 +8,7 @@
namespace Drupal\plugin_test\Plugin\plugin_test\mock_block;
use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Mock implementation of a login block plugin used by Plugin API unit tests.
@@ -23,8 +24,8 @@ class MockUserLoginBlock extends PluginBase {
*/
protected $title;
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
$this->title = isset($configuration['title']) ? $configuration['title'] : '';
}
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
index affe712..bbb4638 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
@@ -30,7 +30,6 @@
* base_table = "taxonomy_term_data",
* uri_callback = "taxonomy_term_uri",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "tid",
* "bundle" = "vid",
diff --git a/core/modules/tour/lib/Drupal/tour/TipPluginBase.php b/core/modules/tour/lib/Drupal/tour/TipPluginBase.php
index 3a07562..80e4115 100644
--- a/core/modules/tour/lib/Drupal/tour/TipPluginBase.php
+++ b/core/modules/tour/lib/Drupal/tour/TipPluginBase.php
@@ -8,6 +8,7 @@
namespace Drupal\tour;
use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\tour\TipPluginInterface;
/**
@@ -39,10 +40,10 @@
/**
* Overrides \Drupal\Component\Plugin\PluginBase::__construct().
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
- $this->definition = $plugin_definition;
+ $this->definition = $this->discovery->getDefinition($plugin_id);
$this->module = $this->definition['module'];
}
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
index aee3c67..a42a019 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
@@ -50,7 +50,9 @@
* Additionally some more entity info keys can be defined to further customize
* the translation UI. The entity translation info is an associative array that
* has to match the following structure. Two nested arrays keyed respectively
- * by the 'translation' key and the 'translation_entity' key. Elements:
+ * by the 'translation' key and the 'entity_translation' key: the first one is
+ * the key defined by the core entity system, while the second one registers
+ * Entity Tanslation as a field translation handler. Elements:
* - access callback: The access callback for the translation pages. Defaults to
* 'entity_translation_translate_access'.
* - access arguments: The access arguments for the translation pages. By
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/ConfigTestTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/ConfigTestTranslationUITest.php
index 9c51c46..2439c8b 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/ConfigTestTranslationUITest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/ConfigTestTranslationUITest.php
@@ -35,14 +35,6 @@ function setUp() {
}
/**
- * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::enableTranslation().
- */
- protected function enableTranslation() {
- $this->container->get('state')->set('config_test.translatable', TRUE);
- parent::enableTranslation();
- }
-
- /**
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
*/
protected function getNewEntityValues($langcode) {
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index 68eb96d..bb78d1e 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -72,12 +72,11 @@ function translation_entity_language_types_info_alter(array &$language_types) {
* Implements hook_entity_info_alter().
*/
function translation_entity_entity_info_alter(array &$entity_info) {
+ $edit_form_info = array();
+
+ $bundles_info = entity_get_bundles();
// Provide defaults for translation info.
foreach ($entity_info as $entity_type => &$info) {
- if (empty($info['translatable'])) {
- continue;
- }
-
if (!isset($info['translation']['translation_entity'])) {
$info['translation']['translation_entity'] = array();
}
@@ -88,37 +87,39 @@ function translation_entity_entity_info_alter(array &$entity_info) {
// shared accross different entities.
$info += array('translation_controller_class' => 'Drupal\translation_entity\EntityTranslationController');
- // If no menu base path is provided we default to the usual
- // "entity_type/%entity_type" pattern.
- if (!isset($info['menu_base_path'])) {
- $path = "$entity_type/%$entity_type";
- $info['menu_base_path'] = $path;
+ // Check whether translation is enabled at least for one bundle. We cannot
+ // use translation_entity_enabled() here since it would cause infinite
+ // recursion, as it relies on entity info.
+ $enabled = FALSE;
+ $bundles = isset($bundles_info[$entity_type]) ? array_keys($bundles_info[$entity_type]) : array($entity_type);
+ foreach ($bundles as $bundle) {
+ if (translation_entity_get_config($entity_type, $bundle, 'enabled')) {
+ $enabled = TRUE;
+ break;
+ }
}
- $path = $info['menu_base_path'];
+ if ($enabled) {
+ // If no menu base path is provided we default to the usual
+ // "entity_type/%entity_type" pattern.
+ if (!isset($info['menu_base_path'])) {
+ $path = "$entity_type/%$entity_type";
+ $info['menu_base_path'] = $path;
+ }
- $info += array(
- 'menu_view_path' => $path,
- 'menu_edit_path' => "$path/edit",
- 'menu_path_wildcard' => "%$entity_type",
- );
+ $path = $info['menu_base_path'];
- $entity_position = count(explode('/', $path)) - 1;
- $info['translation']['translation_entity'] += array(
- 'access_callback' => 'translation_entity_translate_access',
- 'access_arguments' => array($entity_position),
- );
- }
-}
+ $info += array(
+ 'menu_view_path' => $path,
+ 'menu_edit_path' => "$path/edit",
+ 'menu_path_wildcard' => "%$entity_type",
+ );
-/**
- * Implements hook_entity_bundle_info_alter().
- */
-function translation_entity_entity_bundle_info_alter(&$bundles) {
- foreach ($bundles as $entity_type => &$info) {
- foreach ($info as $bundle => &$bundle_info) {
- $enabled = translation_entity_get_config($entity_type, $bundle, 'enabled');
- $bundle_info['translatable'] = !empty($enabled);
+ $entity_position = count(explode('/', $path)) - 1;
+ $info['translation']['translation_entity'] += array(
+ 'access_callback' => 'translation_entity_translate_access',
+ 'access_arguments' => array($entity_position),
+ );
}
}
}
@@ -278,7 +279,9 @@ function _translation_entity_menu_strip_loaders($path) {
*/
function translation_entity_translate_access(EntityInterface $entity) {
$entity_type = $entity->entityType();
- return empty($entity->language()->locked) && language_multilingual() && $entity->isTranslatable() &&
+ return empty($entity->language()->locked) &&
+ language_multilingual() &&
+ translation_entity_enabled($entity_type, $entity->bundle()) &&
(user_access('create entity translations') || user_access('update entity translations') || user_access('delete entity translations'));
}
@@ -442,26 +445,26 @@ function translation_entity_set_config($entity_type, $bundle, $setting, $value)
* @param string $bundle
* (optional) The bundle of the entity. If no bundle is provided, all the
* available bundles are checked.
+ * @param boolean $skip_handler
+ * (optional) Specifies whether the availablity of a field translation handler
+ * should affect the returned value. By default the check is performed.
*
* @returns
* TRUE if the specified bundle is translatable. If no bundle is provided
* returns TRUE if at least one of the entity bundles is translatable.
*/
-function translation_entity_enabled($entity_type, $bundle = NULL) {
+function translation_entity_enabled($entity_type, $bundle = NULL, $skip_handler = FALSE) {
$enabled = FALSE;
- $info = entity_get_info($entity_type);
+ $bundles = !empty($bundle) ? array($bundle) : array_keys(entity_get_bundles($entity_type));
- if (!empty($info['translatable'])) {
- $bundles = !empty($bundle) ? array($bundle) : array_keys(entity_get_bundles($entity_type));
- foreach ($bundles as $bundle) {
- if (translation_entity_get_config($entity_type, $bundle, 'enabled')) {
- $enabled = TRUE;
- break;
- }
+ foreach ($bundles as $bundle) {
+ if (translation_entity_get_config($entity_type, $bundle, 'enabled')) {
+ $enabled = TRUE;
+ break;
}
}
- return $enabled;
+ return $enabled && ($skip_handler || field_has_translation_handler($entity_type, 'translation_entity'));
}
/**
@@ -599,7 +602,7 @@ function translation_entity_permission() {
* Implements hook_form_alter().
*/
function translation_entity_form_alter(array &$form, array &$form_state) {
- if (($form_controller = translation_entity_form_controller($form_state)) && ($entity = $form_controller->getEntity($form_state)) && !$entity->isNew() && $entity->isTranslatable()) {
+ if (($form_controller = translation_entity_form_controller($form_state)) && ($entity = $form_controller->getEntity($form_state)) && !$entity->isNew() && translation_entity_enabled($entity->entityType(), $entity->bundle())) {
$controller = translation_entity_controller($entity->entityType());
$controller->entityFormAlter($form, $form_state, $entity);
@@ -640,7 +643,7 @@ function translation_entity_field_language_alter(&$display_language, $context) {
$entity = $context['entity'];
$entity_type = $entity->entityType();
- if (isset($entity->translation[$context['langcode']]) && $entity->isTranslatable() && !translation_entity_view_access($entity, $context['langcode'])) {
+ if (isset($entity->translation[$context['langcode']]) && translation_entity_enabled($entity_type, $entity->bundle()) && !translation_entity_view_access($entity, $context['langcode'])) {
$instances = field_info_instances($entity_type, $entity->bundle());
// Avoid altering the real entity.
$entity = clone($entity);
@@ -676,7 +679,7 @@ function translation_entity_entity_load(array $entities, $entity_type) {
if (translation_entity_enabled($entity_type)) {
foreach ($entities as $entity) {
- if ($entity->isTranslatable()) {
+ if (translation_entity_enabled($entity_type, $entity->bundle())) {
$enabled_entities[$entity->id()] = $entity;
}
}
@@ -715,7 +718,7 @@ function translation_entity_load_translation_metadata(array $entities, $entity_t
*/
function translation_entity_entity_insert(EntityInterface $entity) {
// Only do something if translation support for the given entity is enabled.
- if (!$entity->isTranslatable()) {
+ if (!translation_entity_enabled($entity->entityType(), $entity->bundle())) {
return;
}
@@ -755,7 +758,7 @@ function translation_entity_entity_insert(EntityInterface $entity) {
*/
function translation_entity_entity_delete(EntityInterface $entity) {
// Only do something if translation support for the given entity is enabled.
- if (!$entity->isTranslatable()) {
+ if (!translation_entity_enabled($entity->entityType(), $entity->bundle())) {
return;
}
@@ -770,7 +773,7 @@ function translation_entity_entity_delete(EntityInterface $entity) {
*/
function translation_entity_entity_update(EntityInterface $entity) {
// Only do something if translation support for the given entity is enabled.
- if (!$entity->isTranslatable()) {
+ if (!translation_entity_enabled($entity->entityType(), $entity->bundle())) {
return;
}
@@ -864,7 +867,7 @@ function translation_entity_field_info_alter(&$info) {
* Implements hook_field_attach_presave().
*/
function translation_entity_field_attach_presave(EntityInterface $entity) {
- if ($entity->isTranslatable()) {
+ if (translation_entity_enabled($entity->entityType(), $entity->bundle())) {
$attributes = drupal_container()->get('request')->attributes;
Drupal::service('translation_entity.synchronizer')->synchronizeFields($entity, $attributes->get('working_langcode'), $attributes->get('source_langcode'));
}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
index fb7cbbb..64afbfc 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
@@ -31,7 +31,6 @@
* uri_callback = "user_uri",
* label_callback = "user_label",
* fieldable = TRUE,
- * translatable = TRUE,
* entity_keys = {
* "id" = "uid",
* "uuid" = "uuid"
diff --git a/core/modules/views/lib/Drupal/views/Plugin/block/block/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/block/block/ViewsBlock.php
index 8a77f18..4dbb64d 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/block/block/ViewsBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/block/block/ViewsBlock.php
@@ -11,6 +11,7 @@
use Drupal\block\Plugin\Core\Entity\Block;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Provides a generic Views block.
@@ -41,8 +42,8 @@ class ViewsBlock extends BlockBase {
/**
* Overrides \Drupal\Component\Plugin\PluginBase::__construct().
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition, Block $entity) {
- parent::__construct($configuration, $plugin_id, $plugin_definition, $entity);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery, Block $entity) {
+ parent::__construct($configuration, $plugin_id, $discovery, $entity);
list($plugin, $delta) = explode(':', $this->getPluginId());
list($name, $this->displayID) = explode('-', $delta, 2);
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
index a1d357a..731d212 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\PluginBase;
use Drupal\views\ViewExecutable;
@@ -75,8 +76,8 @@
/**
* Constructs a Handler object.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
$this->is_handler = TRUE;
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/PluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/PluginBase.php
index 82d14f9..8bf057b 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/PluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/PluginBase.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\Component\Plugin\PluginBase as ComponentPluginBase;
use Drupal\views\ViewExecutable;
@@ -56,10 +57,10 @@
/**
* Constructs a Plugin object.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
- $this->definition = $plugin_definition + $configuration;
+ $this->definition = $this->discovery->getDefinition($plugin_id) + $configuration;
}
/**
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/join/JoinPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/join/JoinPluginBase.php
index 75623b8..5c45450 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/join/JoinPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/join/JoinPluginBase.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views\join;
use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* @defgroup views_join_handlers Views join handlers
@@ -142,8 +143,8 @@ class JoinPluginBase extends PluginBase {
/**
* Constructs a Drupal\views\Plugin\views\join\JoinPluginBase object.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
// Merge in some default values.
$configuration += array(
'type' => 'LEFT',
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/join/Subquery.php b/core/modules/views/lib/Drupal/views/Plugin/views/join/Subquery.php
index 0cb03c9..6ce08cd 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/join/Subquery.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/join/Subquery.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Plugin\views\join;
use Drupal\Component\Annotation\Plugin;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Join handler for relationships that join with a subquery as the left field.
@@ -26,8 +27,8 @@ class Subquery extends JoinPluginBase {
/**
* Constructs a Subquery object.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
$this->left_query = $this->configuration['left_query'];
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
index a7f699f..aa5cd6b 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
@@ -14,6 +14,7 @@
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\PluginBase;
use Drupal\views\Plugin\views\wizard\WizardInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
/**
* Provides the interface and base class for Views Wizard plugins.
@@ -113,8 +114,8 @@
/**
* Constructs a WizardPluginBase object.
*/
- public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
+ public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+ parent::__construct($configuration, $plugin_id, $discovery);
$this->base_table = $this->definition['base_table'];
diff --git a/core/modules/views/lib/Drupal/views/Tests/PluginBaseUnitTest.php b/core/modules/views/lib/Drupal/views/Tests/PluginBaseUnitTest.php
index 07e2505..93702ab 100644
--- a/core/modules/views/lib/Drupal/views/Tests/PluginBaseUnitTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/PluginBaseUnitTest.php
@@ -249,7 +249,9 @@ public function testSetOptionDefault() {
* A test plugin instance.
*/
protected function getTestPlugin() {
- return new TestHelperPlugin(array(), 'default', array());
+ $discovery = new StaticDiscovery();
+ $discovery->setDefinition('default', array());
+ return new TestHelperPlugin(array(), 'default', $discovery);
}
}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
index eae95fc..8c44bb0 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -985,13 +985,6 @@ public function getOriginalEntity() {
}
/**
- * Implements \Drupal\Core\Entity\EntityInterface::isTranslatable().
- */
- public function isTranslatable() {
- return $this->__call(__FUNCTION__, func_get_args());
- }
-
- /**
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
*/
public function getName() {