contrib modules updates
This commit is contained in:
@@ -3,7 +3,7 @@ Translation Views
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
Provides fields and filter for views to display information about the current row, the **source** translation, in another **target** language. You can also add translation operation links to decide if you want to add/edit the content in the target language.
|
||||
Provides fields and filter for views to display information about each row, the **source** translation, in another **target** language. You can also add translation operation links to decide if you want to add/edit the content in the target language.
|
||||
|
||||
Configurations for a demo view is imported on installation, named `Content translation jobs` which can be found at path `/translate/content`. If you want to get view for other translatable entities, you should build it yourself using our fields/filters.
|
||||
|
||||
@@ -17,16 +17,17 @@ FEATURES
|
||||
- Target language: `field`,`filter`. Should in most cases be an exposed filter.
|
||||
Also, there is an extra filter option: *Remove rows where source language is equal to target language*
|
||||
|
||||
These fields/filters will display information about the current content in the selected target language:
|
||||
These fields/filters will display information about the each row in the selected target language:
|
||||
- Translation outdated: `field`,`filter`
|
||||
- Translation status: `field`,`filter`
|
||||
- Target language equals default language: `field`,`filter`: Checks if the target language is the same as the original language of the node.
|
||||
- Translation changed time: `field`
|
||||
- Translation source equals row language: `field`,`filter`: Checks if the source translation of the target language is the same as the language of the row
|
||||
- Source translation of target language equals row language: `field`,`filter`: Checks if the source translation of the row is the same as the target language
|
||||
- Translation operations: `field`
|
||||
- Translation moderation state: `field`
|
||||
|
||||
**Source translation**
|
||||
- Translation counter: `field`,`filter`
|
||||
- Translation counter: `field`,`filter`: count translations of oirignal language. You can also configure the field to include original language in the count.
|
||||
|
||||
REQUIREMENTS
|
||||
------------
|
||||
@@ -65,9 +66,12 @@ Exposed filters:
|
||||
Hidden filters
|
||||
- Source content outdated must be false: Make sure you do not translation from outdated nodes.
|
||||
- Target language equals default language must be false: As there is no use to check status of original language as a target language.
|
||||
- The target language must be untranslated or outdated: Make sure translated and updated content disappear from the list.
|
||||
- The target language must be untranslated or the same as the source language of translation: This makes sure that once there is a translation in target language it will only be displayed if the source language is the correct source language. If target language is not translated you can use different language as source translation.
|
||||
|
||||
MODULE INTEGRATION
|
||||
-------------
|
||||
You can limit the target language filter list to the users registered translation skill if you're using [Local Translation](https://www.drupal.org/project/local_translation)
|
||||
|
||||
MAINTAINERS
|
||||
-----------
|
||||
Developed by [vlad.dancer](https://drupal.org/u/vladdancer)
|
||||
|
||||
+3
-76
@@ -612,7 +612,7 @@ display:
|
||||
identifier: translation_target_language
|
||||
required: true
|
||||
remember: true
|
||||
multiple: true
|
||||
multiple: false
|
||||
remember_roles:
|
||||
anonymous: anonymous
|
||||
authenticated: authenticated
|
||||
@@ -679,7 +679,7 @@ display:
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: 2
|
||||
value: '0'
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
@@ -754,7 +754,7 @@ display:
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: 0
|
||||
value: '0'
|
||||
group: 2
|
||||
exposed: false
|
||||
expose:
|
||||
@@ -819,79 +819,6 @@ display:
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: translation_views_source_equals_row
|
||||
translation_status_2:
|
||||
id: translation_status_2
|
||||
table: node_translation
|
||||
field: translation_status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: 0
|
||||
group: 3
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: node
|
||||
plugin_id: translation_views_status
|
||||
translation_outdated_1:
|
||||
id: translation_outdated_1
|
||||
table: node_translation_target
|
||||
field: translation_outdated
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: '1'
|
||||
group: 3
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: boolean
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
|
||||
+29
-8
@@ -4,19 +4,15 @@ views.filter.translation_views_translation_count:
|
||||
|
||||
views.filter_value.translation_views_translation_count:
|
||||
type: views.filter_value.numeric
|
||||
label: 'Filter rows by amount of translations (without default language)'
|
||||
label: 'Filter rows by amount of translations'
|
||||
|
||||
views.filter.translation_views_source_equals_row:
|
||||
type: views.filter.boolean
|
||||
value: 'A boolean indicating whether the translation source of target language is same as the row language'
|
||||
|
||||
views.filter.translation_views_status:
|
||||
type: views_filter
|
||||
label: 'A value indicating whether the node is translated into target language'
|
||||
mapping:
|
||||
value:
|
||||
type: integer
|
||||
label: 'Value'
|
||||
type: views.filter.boolean
|
||||
label: 'A boolean indicating whether the node is translated into target language'
|
||||
|
||||
views.filter.translation_views_target_language:
|
||||
type: views_filter
|
||||
@@ -28,10 +24,27 @@ views.filter.translation_views_target_language:
|
||||
remove:
|
||||
type: boolean
|
||||
label: 'Remove rows where source language is equal to target language'
|
||||
limit:
|
||||
type: boolean
|
||||
label: 'Enable limiting languages list using Local Translation module'
|
||||
column:
|
||||
type: mapping
|
||||
label: 'Column'
|
||||
mapping:
|
||||
from:
|
||||
type: string
|
||||
lable: 'Source language'
|
||||
to:
|
||||
type: string
|
||||
lable: 'Target language'
|
||||
|
||||
views.field.translation_views_translation_count:
|
||||
type: views.field.numeric
|
||||
label: 'Amount of translations (without default language)'
|
||||
label: 'Amount of translations'
|
||||
mapping:
|
||||
include_original_language:
|
||||
type: boolean
|
||||
label: 'Include original language in count'
|
||||
|
||||
views.field.translation_views_operations:
|
||||
type: views_field
|
||||
@@ -48,3 +61,11 @@ views.field.translation_views_status:
|
||||
views.field.translation_views_target_language:
|
||||
type: views.field.language
|
||||
label: 'The target language'
|
||||
|
||||
views.field.translation_moderation_state:
|
||||
type: views_field
|
||||
label: 'Translation moderation state'
|
||||
mapping:
|
||||
display_name:
|
||||
type: string
|
||||
label: 'Formatter'
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\translation_views;
|
||||
|
||||
use Drupal\content_translation\ContentTranslationHandlerInterface;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Class EntityInfo.
|
||||
*
|
||||
* Special object to store common entity related properties,
|
||||
* it will be used by all operations link builder functions,
|
||||
* just as "trait" but for method's values.
|
||||
*
|
||||
* @package Drupal\translation_views
|
||||
*/
|
||||
class EntityInfo {
|
||||
|
||||
/**
|
||||
* Source entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
public $entity;
|
||||
|
||||
/**
|
||||
* The entity type id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $entityTypeId;
|
||||
|
||||
/**
|
||||
* Entity type instance.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
public $entityType;
|
||||
|
||||
public $translations;
|
||||
|
||||
public $translatable;
|
||||
|
||||
public $rowLanguage;
|
||||
|
||||
public $access;
|
||||
|
||||
public $currentLanguage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(ContentEntityInterface $entity, ContentTranslationHandlerInterface $access, LanguageInterface $language, LanguageInterface $row_lang) {
|
||||
$this->entity = $entity;
|
||||
$this->access = $access;
|
||||
|
||||
$this->rowLanguage = $row_lang;
|
||||
$this->currentLanguage = $language;
|
||||
|
||||
$this->entityTypeId = $entity->getEntityTypeId();
|
||||
$this->entityType = $entity->getEntityType();
|
||||
$this->translations = $entity->getTranslationLanguages();
|
||||
$this->translatable = $entity->isTranslatable();
|
||||
}
|
||||
|
||||
/**
|
||||
* An wrapper to get translation access by particular entity per operation.
|
||||
*
|
||||
* @see \Drupal\content_translation\ContentTranslationHandlerInterface::getTranslationAccess,
|
||||
* for available operations.
|
||||
*/
|
||||
public function getTranslationAccess($op) {
|
||||
$access = $this->access->getTranslationAccess($this->entity, $op);
|
||||
return $access->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\translation_views;
|
||||
|
||||
use Drupal\content_translation\ContentTranslationHandlerInterface;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Class EntityTranslationInfo.
|
||||
*
|
||||
* Stores entity translation related propertie used by
|
||||
* operations link builder functions as a trait.
|
||||
*
|
||||
* @package Drupal\translation_views
|
||||
*/
|
||||
class EntityTranslationInfo {
|
||||
|
||||
/**
|
||||
* Entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
public $entity;
|
||||
/**
|
||||
* Entity type id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $entityTypeId;
|
||||
/**
|
||||
* Entity type instance.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
public $entityType;
|
||||
/**
|
||||
* Translation access handler.
|
||||
*
|
||||
* @var \Drupal\content_translation\ContentTranslationHandlerInterface
|
||||
*/
|
||||
public $accessHandler;
|
||||
/**
|
||||
* Source language.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageInterface
|
||||
*/
|
||||
public $sourceLanguage;
|
||||
/**
|
||||
* Target language.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageInterface
|
||||
*/
|
||||
public $targetLanguage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(ContentEntityInterface $entity, ContentTranslationHandlerInterface $accessHandler, LanguageInterface $targetLanguage, LanguageInterface $sourceLanguage) {
|
||||
$this->entity = $entity;
|
||||
$this->accessHandler = $accessHandler;
|
||||
|
||||
$this->sourceLanguage = $sourceLanguage;
|
||||
$this->targetLanguage = $targetLanguage;
|
||||
|
||||
$this->entityTypeId = $entity->getEntityTypeId();
|
||||
$this->entityType = $entity->getEntityType();
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for getting translation access per operation.
|
||||
*
|
||||
* @see \Drupal\content_translation\ContentTranslationHandlerInterface::getTranslationAccess,
|
||||
* for available operations.
|
||||
*/
|
||||
public function getTranslationAccess($operation) {
|
||||
$access = $this->accessHandler->getTranslationAccess($this->entity, $operation);
|
||||
return $access->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Drupal\translation_views\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\translation_views\TranslationCountTrait;
|
||||
use Drupal\views\Plugin\views\field\NumericField;
|
||||
@@ -57,4 +58,26 @@ class TranslationCountField extends NumericField implements ContainerFactoryPlug
|
||||
$this->field_alias = $query->addField($join_alias, 'count_langs', $this->realField);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['include_original_language'] = ['default' => FALSE];
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide option to include original language in count.
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$form['include_original_language'] = [
|
||||
'#title' => $this->t('Include original language in count'),
|
||||
'#description' => $this->t("Enable to also count the original language."),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => !empty($this->options['include_original_language']),
|
||||
];
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\translation_views\Plugin\views\field;
|
||||
|
||||
use Drupal\content_moderation\ModerationInformationInterface;
|
||||
use Drupal\content_translation\ContentTranslationManager;
|
||||
use Drupal\Core\Entity\EntityTypeManager;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\views\Plugin\views\field\FieldPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\translation_views\TranslationViewsTargetLanguage as TargetLanguage;
|
||||
|
||||
/**
|
||||
* Provides a field that adds moderation state.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
* @ViewsField("translation_moderation_state")
|
||||
*/
|
||||
class TranslationModerationState extends FieldPluginBase {
|
||||
|
||||
use TargetLanguage;
|
||||
|
||||
/**
|
||||
* The moderation information service.
|
||||
*
|
||||
* @var \Drupal\content_moderation\ModerationInformationInterface
|
||||
*/
|
||||
protected $moderationInfo;
|
||||
/**
|
||||
* Entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManager
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
ModerationInformationInterface $moderation_info,
|
||||
LanguageManagerInterface $language_manager,
|
||||
EntityTypeManager $entity_type_manager
|
||||
) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->moderationInfo = $moderation_info;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(
|
||||
ContainerInterface $container,
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
) {
|
||||
return new static(
|
||||
$configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('content_moderation.moderation_information'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['display_name'] = ['default' => TRUE];
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$default_value = 'state';
|
||||
$states = [
|
||||
'state' => $this->t('Moderation State'),
|
||||
'name' => $this->t('Machine Name'),
|
||||
];
|
||||
if (!empty($this->options['display_name'])) {
|
||||
$default_value = $this->options['display_name'];
|
||||
}
|
||||
$form['display_name'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Formatter'),
|
||||
'#options' => $states,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $default_value,
|
||||
];
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clickSortable() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(ResultRow $values) {
|
||||
if ($values->_entity->id()) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
|
||||
$entityTypeId = $values->_entity->getEntityTypeId();
|
||||
$storage = $this->entityTypeManager->getStorage($entityTypeId);
|
||||
$entity = $storage->load($values->_entity->id());
|
||||
$target_langcode = $this->getTargetLangcode();
|
||||
$pending_revision_enabled = ContentTranslationManager::isPendingRevisionSupportEnabled($entityTypeId);
|
||||
|
||||
if (empty($target_langcode) || $target_langcode == '***LANGUAGE_site_default***') {
|
||||
$target_langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
}
|
||||
|
||||
$translation_has_revision = $storage->getLatestTranslationAffectedRevisionId($values->_entity->id(), $target_langcode);
|
||||
if ($entity && $pending_revision_enabled && $target_langcode && $translation_has_revision) {
|
||||
$latest_revision = $storage->loadRevision($translation_has_revision);
|
||||
if ($entity && $latest_revision->hasTranslation($target_langcode)) {
|
||||
$workflow = $this->moderationInfo->getWorkflowForEntity($latest_revision);
|
||||
$translation = $latest_revision->getTranslation($target_langcode);
|
||||
$translation_state = $translation->moderation_state->value;
|
||||
|
||||
if (!empty($this->options['display_name']) && $workflow !== NULL) {
|
||||
if ($this->options['display_name'] == 'state') {
|
||||
$translation_label = $workflow->getTypePlugin()
|
||||
->getState($translation_state)
|
||||
->label();
|
||||
$values->{$this->field_alias} = $translation_label ? $translation_label : NULL;
|
||||
}
|
||||
else {
|
||||
$values->{$this->field_alias} = $translation_state ? $translation_state : NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::render($values);
|
||||
}
|
||||
|
||||
}
|
||||
+200
-59
@@ -2,12 +2,18 @@
|
||||
|
||||
namespace Drupal\translation_views\Plugin\views\field;
|
||||
|
||||
use Drupal\content_translation\ContentTranslationManager;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManager;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Session\AccountProxyInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\translation_views\EntityInfo as HelperEntityInfo;
|
||||
use Drupal\translation_views\EntityTranslationInfo;
|
||||
use Drupal\translation_views\TranslationViewsTargetLanguage as TargetLanguage;
|
||||
use Drupal\views\Plugin\views\field\EntityOperations;
|
||||
use Drupal\views\ResultRow;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Renders translation operations links.
|
||||
@@ -19,16 +25,65 @@ use Drupal\views\ResultRow;
|
||||
class TranslationOperationsField extends EntityOperations {
|
||||
use TargetLanguage;
|
||||
|
||||
/**
|
||||
* Current user account object.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountProxyInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
/**
|
||||
* Entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManager
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
array $plugin_definition,
|
||||
EntityManagerInterface $entity_manager,
|
||||
EntityTypeManager $entity_type_manager,
|
||||
LanguageManagerInterface $language_manager,
|
||||
AccountProxyInterface $account
|
||||
) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $language_manager);
|
||||
$this->currentUser = $account;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(
|
||||
ContainerInterface $container,
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
) {
|
||||
return new static(
|
||||
$configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Build operation links.
|
||||
*/
|
||||
public function render(ResultRow $values) {
|
||||
/* @var ContentEntityInterface $entity */
|
||||
$entity = $this->getEntity($values);
|
||||
$langcode_key = $this->buildSourceEntityLangcodeKey($entity);
|
||||
$operations = $this->getOperations($entity, $values->{$langcode_key});
|
||||
/* @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->getEntity($values);
|
||||
$langcode_key = $this->buildSourceEntityLangcodeKey($entity);
|
||||
$source_langcode = $values->{$langcode_key};
|
||||
$operations = $this->getTranslationOperations($entity, $source_langcode);
|
||||
|
||||
if ($this->options['destination']) {
|
||||
foreach ($operations as &$operation) {
|
||||
@@ -39,7 +94,7 @@ class TranslationOperationsField extends EntityOperations {
|
||||
}
|
||||
}
|
||||
$build = [
|
||||
'#type' => 'operations',
|
||||
'#type' => 'operations',
|
||||
'#links' => $operations,
|
||||
];
|
||||
$build['#cache']['contexts'][] = 'url.query_args:target_language';
|
||||
@@ -76,20 +131,21 @@ class TranslationOperationsField extends EntityOperations {
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The source entity to get context for decision.
|
||||
* @param string $row_lang
|
||||
* The target langcode of the row.
|
||||
* @param string $source_langcode
|
||||
* The langcode of the row.
|
||||
*
|
||||
* @return array
|
||||
* Operation links' render array.
|
||||
*
|
||||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
|
||||
* @throws \Drupal\Core\Entity\EntityMalformedException
|
||||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
|
||||
*/
|
||||
protected function getOperations(ContentEntityInterface $entity, $row_lang) {
|
||||
protected function getTranslationOperations(ContentEntityInterface $entity, $source_langcode) {
|
||||
$links = [];
|
||||
$current = $this->getTargetLanguage()
|
||||
? $this->getTargetLanguage()
|
||||
: $row_lang;
|
||||
$target_langcode = $this->getTargetLangcode()
|
||||
? $this->getTargetLangcode()
|
||||
: $source_langcode;
|
||||
|
||||
/* @var \Drupal\content_translation\ContentTranslationHandlerInterface $handler */
|
||||
$handler = $this->getEntityManager()
|
||||
@@ -98,74 +154,159 @@ class TranslationOperationsField extends EntityOperations {
|
||||
// Construct special object to store common properties,
|
||||
// it will be used by all builder functions,
|
||||
// just as "trait" but for methods.
|
||||
$entity_info = new HelperEntityInfo(
|
||||
$translation_info = new EntityTranslationInfo(
|
||||
$entity,
|
||||
$handler,
|
||||
$this->languageManager->getLanguage($current),
|
||||
$this->languageManager->getLanguage($row_lang)
|
||||
$this->languageManager->getLanguage($target_langcode),
|
||||
$this->languageManager->getLanguage($source_langcode)
|
||||
);
|
||||
|
||||
$is_source = $entity->getUntranslated()->language()->getId() === $entity_info->rowLanguage->getId();
|
||||
$is_default = static::isDefaultTranslation($translation_info);
|
||||
|
||||
// Build edit & delete link.
|
||||
if (array_key_exists($current, $entity_info->translations)) {
|
||||
if (array_key_exists($target_langcode, $entity->getTranslationLanguages())) {
|
||||
// If the user is allowed to edit the entity we point the edit link to
|
||||
// the entity form, otherwise if we are not dealing with the original
|
||||
// language we point the link to the translation form.
|
||||
if ($entity->access('update', NULL, TRUE)->isAllowed()
|
||||
&& $entity_info->entityType->hasLinkTemplate('edit-form')
|
||||
if ($entity->access('update', NULL)
|
||||
&& $translation_info->entityType->hasLinkTemplate('edit-form')
|
||||
) {
|
||||
$links += $this->buildEditLink($entity_info, 'entity');
|
||||
$links += $this->buildEditLink($translation_info, 'entity');
|
||||
}
|
||||
elseif (!$is_source && $entity_info->getTranslationAccess('update')) {
|
||||
$links += $this->buildEditLink($entity_info, 'translation');
|
||||
elseif (!$is_default
|
||||
&& $translation_info->getTranslationAccess('update')
|
||||
|| $this->checkForOperationTranslationPermission('update')
|
||||
) {
|
||||
$links += $this->buildEditLink($translation_info, 'translation');
|
||||
}
|
||||
|
||||
// Build delete link.
|
||||
if (!$is_source) {
|
||||
if ($entity->access('delete')
|
||||
&& $entity_info->entityType->hasLinkTemplate('delete-form')
|
||||
) {
|
||||
$links += $this->buildDeleteLink($entity_info, 'entity');
|
||||
}
|
||||
elseif ($entity_info->getTranslationAccess('update')) {
|
||||
$links += $this->buildDeleteLink($entity_info, 'translation');
|
||||
}
|
||||
if ($entity->access('delete')
|
||||
&& $translation_info->entityType->hasLinkTemplate('delete-form')
|
||||
) {
|
||||
$links += $this->buildDeleteLink($translation_info, 'entity');
|
||||
}
|
||||
elseif (!$is_default
|
||||
&& $translation_info->getTranslationAccess('delete')
|
||||
|| $this->checkForOperationTranslationPermission('delete')
|
||||
) {
|
||||
$links += $this->buildDeleteLink($translation_info, 'translation');
|
||||
}
|
||||
}
|
||||
// Check if there are pending revisions.
|
||||
elseif ($this->pendingRevisionExist($translation_info)) {
|
||||
// If the user is allowed to edit the entity we point the edit link to
|
||||
// the entity form, otherwise if we are not dealing with the original
|
||||
// language we point the link to the translation form.
|
||||
if ($entity->access('update', NULL)
|
||||
&& $translation_info->entityType->hasLinkTemplate('edit-form')
|
||||
) {
|
||||
$links += $this->buildEditLink($translation_info, 'entity');
|
||||
}
|
||||
elseif (!$is_default
|
||||
&& $translation_info->getTranslationAccess('update')
|
||||
|| $this->checkForOperationTranslationPermission('update')
|
||||
) {
|
||||
$links += $this->buildEditLink($translation_info, 'translation');
|
||||
}
|
||||
}
|
||||
// Build add link.
|
||||
elseif (!empty($current)
|
||||
&& $entity_info->translatable
|
||||
&& $entity_info->getTranslationAccess('create')
|
||||
elseif (!empty($target_langcode)
|
||||
&& $translation_info->entity->isTranslatable()
|
||||
&& $translation_info->getTranslationAccess('create')
|
||||
) {
|
||||
// No such translation.
|
||||
$links += $this->buildAddLink($entity_info);
|
||||
$links += $this->buildAddLink($translation_info);
|
||||
}
|
||||
return $links;
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user has appropriate translation permission.
|
||||
*
|
||||
* @param string $operation
|
||||
* Operation name.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE - if user permitted to perform specified operation, FALSE otherwise.
|
||||
*/
|
||||
protected function checkForOperationTranslationPermission($operation) {
|
||||
if (!in_array($operation, ['create', 'update', 'delete'], TRUE)) {
|
||||
return FALSE;
|
||||
}
|
||||
return $this->currentUser
|
||||
->hasPermission("$operation content translations");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if target translation is the default translation.
|
||||
*
|
||||
* @param \Drupal\translation_views\EntityInfo $translation_info
|
||||
* Entity info object.
|
||||
*
|
||||
* @return bool
|
||||
* Checking result.
|
||||
*/
|
||||
protected static function isDefaultTranslation(EntityTranslationInfo $translation_info) {
|
||||
$default_langcode = $translation_info->entity
|
||||
->getUntranslated()
|
||||
->language()
|
||||
->getId();
|
||||
$target_langcode = $translation_info->targetLanguage->getId();
|
||||
return $default_langcode === $target_langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if pending revision exist for this translation.
|
||||
*
|
||||
* @param \Drupal\translation_views\EntityInfo $translation_info
|
||||
* Entity info object.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE - if pending revision exist, FALSE otherwise.
|
||||
*
|
||||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
|
||||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
|
||||
*/
|
||||
protected function pendingRevisionExist(EntityTranslationInfo $translation_info) {
|
||||
$pending_revision_enabled = ContentTranslationManager::isPendingRevisionSupportEnabled($translation_info->entityTypeId);
|
||||
if ($this->moduleHandler->moduleExists('content_moderation') && $pending_revision_enabled) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
|
||||
$storage = $this->entityTypeManager->getStorage($translation_info->entityTypeId);
|
||||
$entity = $storage->load($translation_info->entity->id());
|
||||
$translation_has_revision = $storage->getLatestTranslationAffectedRevisionId(
|
||||
$entity->id(),
|
||||
$translation_info->targetLanguage->getId()
|
||||
);
|
||||
if ($translation_has_revision) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add link builder.
|
||||
*/
|
||||
protected function buildAddLink(HelperEntityInfo $entity_info) {
|
||||
protected function buildAddLink(EntityTranslationInfo $translation_info) {
|
||||
$links = [];
|
||||
|
||||
$add_url = new Url(
|
||||
"entity.{$entity_info->entityTypeId}.content_translation_add",
|
||||
"entity.{$translation_info->entityTypeId}.content_translation_add",
|
||||
[
|
||||
'source' => $entity_info->rowLanguage->getId(),
|
||||
'target' => $entity_info->currentLanguage->getId(),
|
||||
$entity_info->entityTypeId => $entity_info->entity->id(),
|
||||
'source' => $translation_info->sourceLanguage->getId(),
|
||||
'target' => $translation_info->targetLanguage->getId(),
|
||||
$translation_info->entityTypeId => $translation_info->entity->id(),
|
||||
],
|
||||
[
|
||||
'language' => $entity_info->currentLanguage,
|
||||
'language' => $translation_info->targetLanguage,
|
||||
]
|
||||
);
|
||||
|
||||
$links['add'] = [
|
||||
'title' => $this->t('Add'),
|
||||
'url' => $add_url,
|
||||
'url' => $add_url,
|
||||
];
|
||||
return $links;
|
||||
}
|
||||
@@ -173,7 +314,7 @@ class TranslationOperationsField extends EntityOperations {
|
||||
/**
|
||||
* Delete link builder.
|
||||
*/
|
||||
protected function buildDeleteLink(HelperEntityInfo $entity_info, $type = FALSE) {
|
||||
protected function buildDeleteLink(EntityTranslationInfo $translation_info, $type = FALSE) {
|
||||
$links = [];
|
||||
|
||||
if (!$type) {
|
||||
@@ -182,22 +323,22 @@ class TranslationOperationsField extends EntityOperations {
|
||||
|
||||
if ($type == 'entity') {
|
||||
$links['delete'] = [
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => $entity_info->entity->urlInfo('delete-form'),
|
||||
'language' => $entity_info->rowLanguage,
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => $translation_info->entity->urlInfo('delete-form'),
|
||||
'language' => $translation_info->targetLanguage,
|
||||
];
|
||||
}
|
||||
elseif ($type == 'translation') {
|
||||
$links['delete'] = [
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => new Url(
|
||||
"entity.{$entity_info->entityTypeId}.content_translation_delete",
|
||||
'url' => new Url(
|
||||
"entity.{$translation_info->entityTypeId}.content_translation_delete",
|
||||
[
|
||||
'language' => $entity_info->rowLanguage->getId(),
|
||||
$entity_info->entityTypeId => $entity_info->entity->id(),
|
||||
'language' => $translation_info->targetLanguage->getId(),
|
||||
$translation_info->entityTypeId => $translation_info->entity->id(),
|
||||
],
|
||||
[
|
||||
'language' => $entity_info->rowLanguage,
|
||||
'language' => $translation_info->targetLanguage,
|
||||
]
|
||||
),
|
||||
];
|
||||
@@ -210,22 +351,22 @@ class TranslationOperationsField extends EntityOperations {
|
||||
*
|
||||
* @throws \Drupal\Core\Entity\EntityMalformedException
|
||||
*/
|
||||
protected function buildEditLink(HelperEntityInfo $entity_info, $type = FALSE) {
|
||||
protected function buildEditLink(EntityTranslationInfo $translation_info, $type = FALSE) {
|
||||
$links = [];
|
||||
|
||||
if ($type == 'entity') {
|
||||
$links['edit']['url'] = $entity_info->entity->toUrl('edit-form');
|
||||
$links['edit']['language'] = $entity_info->rowLanguage;
|
||||
$links['edit']['url'] = $translation_info->entity->toUrl('edit-form');
|
||||
$links['edit']['language'] = $translation_info->targetLanguage;
|
||||
}
|
||||
elseif ($type == 'translation') {
|
||||
$links['edit']['url'] = new Url(
|
||||
"entity.{$entity_info->entityTypeId}.content_translation_edit",
|
||||
"entity.{$translation_info->entityTypeId}.content_translation_edit",
|
||||
[
|
||||
'language' => $entity_info->rowLanguage->getId(),
|
||||
$entity_info->entityTypeId => $entity_info->entity->id(),
|
||||
'language' => $translation_info->targetLanguage->getId(),
|
||||
$translation_info->entityTypeId => $translation_info->entity->id(),
|
||||
],
|
||||
[
|
||||
'language' => $entity_info->rowLanguage,
|
||||
'language' => $translation_info->targetLanguage,
|
||||
]
|
||||
);
|
||||
;
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ class TranslationSourceLangcodeEqualsRowLangcodeField extends Boolean {
|
||||
|
||||
$this->query->addField(
|
||||
NULL,
|
||||
"IF($table_alias.content_translation_source = $base_table.langcode, 1, 0)",
|
||||
"IF(($table_alias.content_translation_source = $base_table.langcode) OR ($table_alias.default_langcode = 1), 1, 0)",
|
||||
'source_lang_eq_row'
|
||||
);
|
||||
}
|
||||
|
||||
+2
-2
@@ -57,13 +57,13 @@ class TranslationTargetLanguageField extends LanguageField implements ContainerF
|
||||
* instead from ResultRow.
|
||||
*/
|
||||
public function render(ResultRow $values) {
|
||||
$target_lang = $this->getTargetLanguage();
|
||||
$target_langcode = $this->getTargetLangcode();
|
||||
|
||||
$languages = $this->options['native_language']
|
||||
? $this->languageManager->getNativeLanguages()
|
||||
: $this->languageManager->getLanguages();
|
||||
|
||||
$build['#markup'] = $languages[$target_lang]->getName();
|
||||
$build['#markup'] = $languages[$target_langcode]->getName();
|
||||
$build['#cache']['contexts'][] = 'url.query_args:' . self::$targetExposedKey;
|
||||
|
||||
return $build;
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ class TranslationSourceLangcodeEqualsRowLangcodeFilter extends BooleanOperator {
|
||||
|
||||
$this->query->addWhereExpression(
|
||||
$this->options['group'],
|
||||
"IF($table_alias.content_translation_source $this->operator $base_table.langcode, 1, 0) = :value", [
|
||||
"IF(($table_alias.content_translation_source $this->operator $base_table.langcode) OR ($table_alias.default_langcode $this->operator 1), 1, 0) = :value", [
|
||||
':value' => $this->value,
|
||||
]
|
||||
);
|
||||
|
||||
+10
-92
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace Drupal\translation_views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\filter\FilterPluginBase;
|
||||
use Drupal\views\Plugin\views\filter\BooleanOperator;
|
||||
|
||||
/**
|
||||
* Provides filtering by translation status.
|
||||
@@ -12,85 +11,13 @@ use Drupal\views\Plugin\views\filter\FilterPluginBase;
|
||||
*
|
||||
* @ViewsFilter("translation_views_status")
|
||||
*/
|
||||
class TranslationStatusFilter extends FilterPluginBase {
|
||||
|
||||
const VALUE_UNTRANSLATED = 0;
|
||||
const VALUE_TRANSLATED = 1;
|
||||
const VALUE_BOTH = 2;
|
||||
class TranslationStatusFilter extends BooleanOperator {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildExposeForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildExposeForm($form, $form_state);
|
||||
|
||||
unset($form['expose']['multiple']);
|
||||
unset($form['expose']['required']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['value']['default'] = FALSE;
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Remove "all" option because we don't need it.
|
||||
*/
|
||||
public function buildExposedForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildExposedForm($form, $form_state);
|
||||
|
||||
if (!empty($this->options['expose']['identifier'])) {
|
||||
$value_id = $this->options['expose']['identifier'];
|
||||
}
|
||||
else {
|
||||
$value_id = 'translation_views_status';
|
||||
}
|
||||
|
||||
unset($form[$value_id]['#options']['All']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function valueForm(&$form, FormStateInterface $form_state) {
|
||||
parent::valueForm($form, $form_state);
|
||||
|
||||
$exposed = $form_state->get('exposed');
|
||||
|
||||
if (!empty($this->options['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
$user_input = $form_state->getUserInput();
|
||||
|
||||
// We need set exposed input to our "BOTH" value,
|
||||
// when there is no selected value by user yet,
|
||||
// usually when there is no any changes in exposed filters.
|
||||
if ($exposed && !isset($user_input[$identifier])) {
|
||||
$user_input = $form_state->getUserInput();
|
||||
$user_input[$identifier] = self::VALUE_BOTH;
|
||||
|
||||
$form_state->setUserInput($user_input);
|
||||
$this->view->setExposedInput($user_input);
|
||||
}
|
||||
}
|
||||
|
||||
$form['value'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Status'),
|
||||
'#options' => [
|
||||
self::VALUE_BOTH => t('Both'),
|
||||
self::VALUE_UNTRANSLATED => t('Not translated'),
|
||||
self::VALUE_TRANSLATED => t('Translated'),
|
||||
],
|
||||
'#multiple' => FALSE,
|
||||
'#default_value' => $this->value,
|
||||
];
|
||||
public function getValueOptions() {
|
||||
$this->valueOptions = [1 => $this->t('Translated'), 0 => $this->t('Not translated')];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,33 +25,24 @@ class TranslationStatusFilter extends FilterPluginBase {
|
||||
*/
|
||||
public function query() {
|
||||
$table_alias = $this->ensureMyTable();
|
||||
$status = $this->value;
|
||||
|
||||
$status = is_array($this->value)
|
||||
? (int) reset($this->value)
|
||||
: $this->value;
|
||||
|
||||
// We don't want to build and run query,
|
||||
// when user specified both statuses.
|
||||
if ($status == self::VALUE_BOTH) {
|
||||
return FALSE;
|
||||
if ($status == 0) {
|
||||
$operation = '=';
|
||||
}
|
||||
|
||||
if ($status == self::VALUE_UNTRANSLATED) {
|
||||
$op = '=';
|
||||
}
|
||||
// Then self::VALUE_TRANSLATED is the case.
|
||||
// Then status translated is the case.
|
||||
else {
|
||||
// Mysql FIND_IN_SET func will return position of element,
|
||||
// when no element was found then it returns 0,
|
||||
// so we use "> 0" as condition to filter out untranslated rows.
|
||||
$op = '>';
|
||||
$operation = '>';
|
||||
$status = 0;
|
||||
}
|
||||
|
||||
/* @var \Drupal\views\Plugin\views\query\Sql */
|
||||
$this->query->addWhereExpression(
|
||||
$this->options['group'],
|
||||
"FIND_IN_SET(:langcode, $table_alias.langs) $op :status", [
|
||||
"FIND_IN_SET(:langcode, $table_alias.langs) $operation :status", [
|
||||
':langcode' => '***TRANSLATION_VIEWS_TARGET_LANG***',
|
||||
':status' => $status,
|
||||
]
|
||||
|
||||
+160
-13
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Drupal\translation_views\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
@@ -21,22 +22,40 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
class TranslationTargetLanguageFilter extends FilterPluginBase implements ContainerFactoryPluginInterface {
|
||||
use TargetLanguage;
|
||||
|
||||
/**
|
||||
* Flag about module 'local_translation_content' existence.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $localTranslation = FALSE;
|
||||
/**
|
||||
* Local Translation skills service.
|
||||
*
|
||||
* @var \Drupal\local_translation\Services\LocalTranslationUserSkills|null
|
||||
*/
|
||||
protected $skills = NULL;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('language_manager')
|
||||
$container->get('language_manager'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager, ModuleHandlerInterface $handler) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->languageManager = $language_manager;
|
||||
$this->localTranslation = $handler->moduleExists('local_translation_content');
|
||||
if ($this->localTranslation && \Drupal::hasService('local_translation.user_skills')) {
|
||||
$this->skills = \Drupal::service('local_translation.user_skills');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,12 +67,16 @@ class TranslationTargetLanguageFilter extends FilterPluginBase implements Contai
|
||||
unset($form['expose']['multiple']);
|
||||
unset($form['expose']['required']);
|
||||
|
||||
if ($this->localTranslation) {
|
||||
// We need to force this option to allow users to use only the languages,
|
||||
// specified as the user's translation skills.
|
||||
$form['expose']['reduce']['#default_value'] = TRUE;
|
||||
$form['expose']['reduce']['#disabled'] = TRUE;
|
||||
}
|
||||
|
||||
$form['expose']['identifier'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $this->options['expose']['identifier'],
|
||||
'#title' => $this->t('Filter identifier'),
|
||||
'#size' => 40,
|
||||
'#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed.'),
|
||||
'#value' => static::$targetExposedKey,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -62,13 +85,76 @@ class TranslationTargetLanguageFilter extends FilterPluginBase implements Contai
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['expose']['identifier'] = static::$targetExposedKey;
|
||||
|
||||
$options['expose']['contains']['label'] = [
|
||||
'default' => $this->t('Target language'),
|
||||
];
|
||||
|
||||
$options['expose']['contains']['identifier'] = [
|
||||
'default' => static::$targetExposedKey,
|
||||
];
|
||||
|
||||
$options['value']['default'] = '';
|
||||
$options['remove']['default'] = FALSE;
|
||||
$options['remove']['default'] = TRUE;
|
||||
$options['exposed']['default'] = TRUE;
|
||||
|
||||
if ($this->localTranslation) {
|
||||
$options['limit'] = ['default' => FALSE];
|
||||
$options['column'] = ['default' => ['from' => '', 'to' => 'to']];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
if ($this->localTranslation) {
|
||||
// Remove the values list - we will handle them on a background basis.
|
||||
// Only if limited option is checked.
|
||||
$form['value']['#states'] = [
|
||||
'visible' => [
|
||||
'input[name="options[limit]"]' => ['checked' => FALSE],
|
||||
],
|
||||
];
|
||||
// Build values list independently in order to see all the options,
|
||||
// while switching "limit" option without necessity to reload the form.
|
||||
$form['value']['#options'] = $this->listLanguages(
|
||||
LanguageInterface::STATE_ALL
|
||||
| LanguageInterface::STATE_SITE_DEFAULT
|
||||
| PluginBase::INCLUDE_NEGOTIATED
|
||||
);
|
||||
|
||||
$end = $form['clear_markup_end'];
|
||||
unset($form['clear_markup_end']);
|
||||
$form['limit'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Limit target languages by translation skills'),
|
||||
'#required' => FALSE,
|
||||
'#default_value' => $this->options['limit'],
|
||||
];
|
||||
$form['column'] = [
|
||||
'#type' => 'checkboxes',
|
||||
'#options' => [
|
||||
'from' => $this->t('Source languages'),
|
||||
'to' => $this->t('Target languages'),
|
||||
],
|
||||
'#title' => $this->t('Languages by translation skills'),
|
||||
'#required' => FALSE,
|
||||
'#default_value' => $this->options['column'],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'input[name="options[limit]"]' => ['checked' => TRUE],
|
||||
],
|
||||
],
|
||||
];
|
||||
$form['clear_markup_end'] = $end;
|
||||
$form['value']['#prefix'] = '<div class="views-group-box views-right-60">';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -77,26 +163,48 @@ class TranslationTargetLanguageFilter extends FilterPluginBase implements Contai
|
||||
|
||||
$exposed = $form_state->get('exposed');
|
||||
|
||||
$language_options = $this->buildLanguageOptions();
|
||||
$default_langcode = $this->languageManager->getDefaultLanguage()->getId();
|
||||
|
||||
if (!empty($this->options['exposed'])) {
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
$user_input = $form_state->getUserInput();
|
||||
|
||||
// We need set exposed input when there is no selected value by user yet.
|
||||
if ($exposed && !isset($user_input[$identifier])) {
|
||||
$value = PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT;
|
||||
$this->setExposedValue($identifier, $value, $form_state);
|
||||
if ($exposed) {
|
||||
if (!isset($this->options['limit'])) {
|
||||
$this->options['limit'] = FALSE;
|
||||
}
|
||||
if (!$this->options['limit']) {
|
||||
if (!isset($user_input[$identifier])
|
||||
|| (isset($user_input[$identifier]) && $user_input[$identifier] === $default_langcode)
|
||||
) {
|
||||
$this->setExposedValue($identifier, PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT, $form_state);
|
||||
}
|
||||
}
|
||||
elseif (isset($user_input[$identifier]) && !isset($language_options[$user_input[$identifier]])) {
|
||||
$this->setExposedValue($identifier, array_keys($language_options)[0], $form_state);
|
||||
$this->value = array_keys($language_options)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->always_required = TRUE;
|
||||
|
||||
$form['value'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Target language'),
|
||||
'#options' => $this->buildLanguageOptions(),
|
||||
'#multiple' => FALSE,
|
||||
'#weight' => 0,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $this->value,
|
||||
];
|
||||
|
||||
$form['expose']['identifier'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => static::$targetExposedKey,
|
||||
];
|
||||
|
||||
if (!$exposed) {
|
||||
$form['remove'] = [
|
||||
'#type' => 'checkbox',
|
||||
@@ -113,16 +221,55 @@ class TranslationTargetLanguageFilter extends FilterPluginBase implements Contai
|
||||
* Options are based on configurable languages or site default one.
|
||||
*/
|
||||
protected function buildLanguageOptions() {
|
||||
$options = [];
|
||||
if ($this->localTranslation && $this->options['limit']) {
|
||||
$skills = $this->skills->getSkills(NULL, TRUE);
|
||||
// Handle column options.
|
||||
foreach ($this->options['column'] as $name => $column) {
|
||||
if (!empty($column)) {
|
||||
foreach ($skills as $langs) {
|
||||
$this->processColumnOption($langs, $name, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
$site_default = $this->languageManager->getDefaultLanguage();
|
||||
$options = $this->listLanguages(LanguageInterface::STATE_CONFIGURABLE);
|
||||
|
||||
if (isset($options[$site_default->getId()])) {
|
||||
unset($options[$site_default->getId()]);
|
||||
}
|
||||
|
||||
return [PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT => $site_default->getName()] + $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process column options.
|
||||
*
|
||||
* @param array $languages
|
||||
* Languages array.
|
||||
* @param string $column
|
||||
* Column name.
|
||||
*/
|
||||
protected function processColumnOption(array $languages, $column, &$options) {
|
||||
$key = "language_$column";
|
||||
if (isset($languages[$key])) {
|
||||
$key = $languages[$key];
|
||||
$options[$key] = $this->languageManager
|
||||
->getLanguage($key)
|
||||
->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listLanguages($flags = LanguageInterface::STATE_ALL, array $current_values = NULL) {
|
||||
return array_map(function ($language) {
|
||||
return (string) $language;
|
||||
}, parent::listLanguages($flags, $current_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
+5
-5
@@ -29,7 +29,7 @@ class TranslationLanguageJoin extends JoinPluginBase implements ContainerFactory
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->database = $database;
|
||||
$this->eid = $this->configuration['entity_pk'];
|
||||
$this->eid = $this->configuration['entity_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,14 +53,14 @@ class TranslationLanguageJoin extends JoinPluginBase implements ContainerFactory
|
||||
|
||||
if (!empty($this->configuration['langcodes_as_count'])) {
|
||||
$query->addExpression("COUNT(efd.langcode)", 'count_langs');
|
||||
if (isset($this->configuration['include_original_language'])
|
||||
&& $this->configuration['include_original_language'] == FALSE) {
|
||||
$query->where('efd.default_langcode != 1');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$query->addExpression("GROUP_CONCAT(efd.langcode separator ',')", 'langs');
|
||||
}
|
||||
|
||||
if (!empty($this->configuration['exclude_default_langcode'])) {
|
||||
$query->where('efd.default_langcode != 1');
|
||||
}
|
||||
$query->groupBy('efd.' . $this->eid);
|
||||
$this->configuration['table formula'] = $query;
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ trait TranslationCountTrait {
|
||||
'field' => $keys['id'],
|
||||
'table' => $query_base_table,
|
||||
'left_table' => $query_base_table,
|
||||
'exclude_default_langcode' => TRUE,
|
||||
'include_original_language' => !empty($this->options['include_original_language']),
|
||||
'langcodes_as_count' => TRUE,
|
||||
'entity_pk' => $keys['id'],
|
||||
'entity_id' => $keys['id'],
|
||||
];
|
||||
|
||||
$tableAlias = $query->ensureTable($query_base_table, $this->relationship);
|
||||
|
||||
+22
-5
@@ -10,7 +10,7 @@ namespace Drupal\translation_views;
|
||||
final class TranslationViewsFieldDefinitions {
|
||||
|
||||
/**
|
||||
* Ttranslation status field definition.
|
||||
* Translation status field definition.
|
||||
*/
|
||||
public static function buildStatusField() {
|
||||
return [
|
||||
@@ -34,7 +34,7 @@ final class TranslationViewsFieldDefinitions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translations count field definition.
|
||||
* Translation count field definition.
|
||||
*/
|
||||
public static function buildCountField() {
|
||||
return [
|
||||
@@ -44,11 +44,11 @@ final class TranslationViewsFieldDefinitions {
|
||||
'title' => t('Translation counter'),
|
||||
'field' => [
|
||||
'id' => 'translation_views_translation_count',
|
||||
'help' => t('Amount of translations (without default language).'),
|
||||
'help' => t('Amount of translations.'),
|
||||
],
|
||||
'filter' => [
|
||||
'id' => 'translation_views_translation_count',
|
||||
'help' => t('Filter rows by amount of translations (without default language).'),
|
||||
'help' => t('Filter rows by amount of translations.'),
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -93,7 +93,7 @@ final class TranslationViewsFieldDefinitions {
|
||||
$field['translation_source']['filter']['id'] = 'translation_views_source_equals_row';
|
||||
$field['translation_source']['field']['help'] = t('A boolean indicating whether the translation source of target language is same as the row language');
|
||||
$field['translation_source']['filter']['help'] = t('A boolean indicating whether the translation source of target language is same as the row language');
|
||||
$field['translation_source']['title'] = t('Translation source equals row language');
|
||||
$field['translation_source']['title'] = t('Source translation of target language equals row language');
|
||||
return $field;
|
||||
}
|
||||
|
||||
@@ -144,4 +144,21 @@ final class TranslationViewsFieldDefinitions {
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation moderation state field definition.
|
||||
*/
|
||||
public static function buildModerationStateField() {
|
||||
return [
|
||||
'translation_moderation_state' => [
|
||||
'title' => t('Translation moderation state'),
|
||||
'field' => [
|
||||
'id' => 'translation_moderation_state',
|
||||
'property' => 'translation_moderation_state',
|
||||
'field_name' => t('Translation moderation state'),
|
||||
'help' => t('Moderation state of the translation.'),
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-4
@@ -20,18 +20,24 @@ trait TranslationViewsTargetLanguage {
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Target exposed key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $targetExposedKey = 'translation_target_language';
|
||||
|
||||
/**
|
||||
* Get target language from exposed input.
|
||||
*
|
||||
* @return string
|
||||
* Current selected target langcode
|
||||
* The selected target langcode.
|
||||
*/
|
||||
protected function getTargetLanguage() {
|
||||
protected function getTargetLangcode() {
|
||||
$inputs = $this->view->getExposedInput();
|
||||
$langcode = $inputs[self::$targetExposedKey];
|
||||
$langcode = isset($inputs[self::$targetExposedKey])
|
||||
? $inputs[self::$targetExposedKey]
|
||||
: PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT;
|
||||
|
||||
return $langcode == PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT
|
||||
? $this->languageManager->getDefaultLanguage()->getId()
|
||||
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- core.entity_view_mode.node.teaser
|
||||
module:
|
||||
- node
|
||||
- translation_views
|
||||
- user
|
||||
id: test_local_translation_content_integration
|
||||
label: 'Test local translation content integration'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: none
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: 'entity:node'
|
||||
options:
|
||||
relationship: none
|
||||
view_mode: teaser
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
langcode:
|
||||
id: langcode
|
||||
table: node_field_data
|
||||
field: langcode
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: language
|
||||
settings:
|
||||
link_to_entity: false
|
||||
native_language: false
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: langcode
|
||||
plugin_id: field
|
||||
filters:
|
||||
translation_target_language:
|
||||
id: translation_target_language
|
||||
table: node_translation
|
||||
field: translation_target_language
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: '***LANGUAGE_site_default***'
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: 'Target language'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: translation_target_language
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
remove: true
|
||||
limit: false
|
||||
column:
|
||||
from: ''
|
||||
to: 'to'
|
||||
entity_type: node
|
||||
plugin_id: translation_views_target_language
|
||||
sorts: { }
|
||||
title: 'Test local translation content filter'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test-local-translation-content-filter
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
name: 'Translation views Local Translation integration test'
|
||||
type: module
|
||||
description: ''
|
||||
package: Testing
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- drupal:node
|
||||
- drupal:views
|
||||
- drupal:translation_views
|
||||
- drupal:content_translation
|
||||
- drupal:language
|
||||
- local_translation:local_translation
|
||||
- local_translation:local_translation_content
|
||||
|
||||
# Information added by Drupal.org packaging script on 2019-02-07
|
||||
version: '8.x-1.0-alpha5'
|
||||
core: '8.x'
|
||||
project: 'translation_views'
|
||||
datestamp: 1549581183
|
||||
+4
-3
@@ -358,7 +358,7 @@ display:
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Target language equals default language'
|
||||
label: 'Source translation of target language equals row language'
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
@@ -514,6 +514,7 @@ display:
|
||||
format_plural_string: !!binary MQNAY291bnQ=
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
include_original_language: false
|
||||
entity_type: comment
|
||||
plugin_id: translation_views_translation_count
|
||||
translation_outdated:
|
||||
@@ -577,7 +578,7 @@ display:
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Translation source equals row language'
|
||||
label: 'Source translation of target language equals row language'
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
@@ -881,7 +882,7 @@ display:
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: 2
|
||||
value: All
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
uuid: 9f3298b4-2171-4aac-8684-01bdc45909c8
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- node
|
||||
- translation_views
|
||||
- user
|
||||
id: content_moderation_integration_test
|
||||
label: 'Content Moderation Integration test'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
translation_moderation_state:
|
||||
id: translation_moderation_state
|
||||
table: node_translation
|
||||
field: translation_moderation_state
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
display_name: state
|
||||
entity_type: node
|
||||
plugin_id: translation_moderation_state
|
||||
filters:
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
article: article
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
title: 'Content Moderation Integration test'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: content-moderation-integration-test
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
uuid: 0df3cfda-b782-4b0d-9810-3ca90a1638cc
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- node
|
||||
- translation_views
|
||||
- user
|
||||
id: test_operations_links
|
||||
label: test_operations_links
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
langcode:
|
||||
id: langcode
|
||||
table: node_field_data
|
||||
field: langcode
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: language
|
||||
settings:
|
||||
link_to_entity: false
|
||||
native_language: false
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: node
|
||||
entity_field: langcode
|
||||
plugin_id: field
|
||||
translation_operations:
|
||||
id: translation_operations
|
||||
table: node_translation
|
||||
field: translation_operations
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
destination: false
|
||||
entity_type: node
|
||||
plugin_id: translation_views_operations
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
article: article
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
title: Test
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test_operations_links
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
+4
-3
@@ -322,7 +322,7 @@ display:
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Target language equals default language'
|
||||
label: 'Source translation of target language equals row language'
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
@@ -478,6 +478,7 @@ display:
|
||||
format_plural_string: !!binary MQNAY291bnQ=
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
include_original_language: false
|
||||
entity_type: node
|
||||
plugin_id: translation_views_translation_count
|
||||
translation_outdated:
|
||||
@@ -541,7 +542,7 @@ display:
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Translation source equals row language'
|
||||
label: 'Source translation of target language equals row language'
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
@@ -836,7 +837,7 @@ display:
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: 2
|
||||
value: All
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- content_moderation
|
||||
id: editorial
|
||||
label: Editorial
|
||||
type: content_moderation
|
||||
type_settings:
|
||||
states:
|
||||
archived:
|
||||
label: Archived
|
||||
weight: 5
|
||||
published: false
|
||||
default_revision: true
|
||||
draft:
|
||||
label: Draft
|
||||
published: false
|
||||
default_revision: false
|
||||
weight: -5
|
||||
published:
|
||||
label: Published
|
||||
published: true
|
||||
default_revision: true
|
||||
weight: 0
|
||||
transitions:
|
||||
archive:
|
||||
label: Archive
|
||||
from:
|
||||
- published
|
||||
to: archived
|
||||
weight: 2
|
||||
archived_draft:
|
||||
label: 'Restore to Draft'
|
||||
from:
|
||||
- archived
|
||||
to: draft
|
||||
weight: 3
|
||||
archived_published:
|
||||
label: Restore
|
||||
from:
|
||||
- archived
|
||||
to: published
|
||||
weight: 4
|
||||
create_new_draft:
|
||||
label: 'Create New Draft'
|
||||
to: draft
|
||||
weight: 0
|
||||
from:
|
||||
- draft
|
||||
- published
|
||||
publish:
|
||||
label: Publish
|
||||
to: published
|
||||
weight: 1
|
||||
from:
|
||||
- draft
|
||||
- published
|
||||
entity_types:
|
||||
node:
|
||||
- article
|
||||
+5
-3
@@ -9,9 +9,11 @@ dependencies:
|
||||
- drupal:translation_views
|
||||
- drupal:content_translation
|
||||
- drupal:language
|
||||
- drupal:content_moderation
|
||||
- drupal:workflows
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-05-23
|
||||
version: '8.x-1.0-alpha2'
|
||||
# Information added by Drupal.org packaging script on 2019-02-07
|
||||
version: '8.x-1.0-alpha5'
|
||||
core: '8.x'
|
||||
project: 'translation_views'
|
||||
datestamp: 1527090186
|
||||
datestamp: 1549581183
|
||||
|
||||
+5
-5
@@ -116,7 +116,7 @@ class CommentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'langcode' => $default_params[0],
|
||||
'translation_target_language' => $default_params[1],
|
||||
'translation_outdated' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => $orderColumn,
|
||||
'sort' => $sort,
|
||||
],
|
||||
@@ -234,7 +234,7 @@ class CommentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
$this->assertTextInRow(1, 'translation-changed', ':');
|
||||
$this->assertTextInRow(1, 'translation-count', '0');
|
||||
$this->assertTextInRow(1, 'translation-outdated', 'No');
|
||||
$this->assertTextInRow(1, 'translation-source', 'No');
|
||||
$this->assertTextInRow(1, 'translation-source', 'Yes');
|
||||
$this->assertTextInRow(1, 'translation-status', 'Translated');
|
||||
$this->assertTextInRow(1, 'translation-operations', 'Edit');
|
||||
}
|
||||
@@ -347,7 +347,7 @@ class CommentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
2 => 'Yes',
|
||||
]);
|
||||
|
||||
// Translation source equals row language.
|
||||
// Source translation of target language equals row language.
|
||||
$this->assertOrder('translation_source', 'asc', [
|
||||
'All',
|
||||
'***LANGUAGE_site_default***',
|
||||
@@ -357,7 +357,7 @@ class CommentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
2 => 'No',
|
||||
3 => 'No',
|
||||
4 => 'No',
|
||||
5 => 'No',
|
||||
5 => 'Yes',
|
||||
6 => 'Yes',
|
||||
]);
|
||||
|
||||
@@ -370,7 +370,7 @@ class CommentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
5 => 'No',
|
||||
4 => 'No',
|
||||
3 => 'No',
|
||||
2 => 'No',
|
||||
2 => 'Yes',
|
||||
1 => 'Yes',
|
||||
]);
|
||||
|
||||
|
||||
+19
-19
@@ -116,7 +116,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => '***LANGUAGE_site_default***',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -131,7 +131,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'de',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -146,7 +146,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'fr',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -161,7 +161,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => 'de',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -176,7 +176,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => 'fr',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -191,7 +191,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 1,
|
||||
'translation_status' => '1',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -206,7 +206,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 0,
|
||||
'translation_status' => '0',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
@@ -227,7 +227,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'title',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -247,7 +247,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'title',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
@@ -268,7 +268,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'langcode',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -288,7 +288,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'langcode',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
@@ -309,7 +309,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_default',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -329,7 +329,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_default',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
@@ -350,7 +350,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_changed',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -370,7 +370,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_changed',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
@@ -391,7 +391,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_count',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -411,7 +411,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_count',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
@@ -432,7 +432,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_status',
|
||||
'sort' => 'asc',
|
||||
],
|
||||
@@ -452,7 +452,7 @@ class ContentFullViewFiltersFieldsTest extends ViewTestBase {
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => '***LANGUAGE_site_default***',
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 2,
|
||||
'translation_status' => 'All',
|
||||
'order' => 'translation_status',
|
||||
'sort' => 'desc',
|
||||
],
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\translation_views\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\workflows\Entity\Workflow;
|
||||
|
||||
/**
|
||||
* Class ContentModerationIntegration.
|
||||
*
|
||||
* @package Drupal\Tests\translation_views\Functional
|
||||
*
|
||||
* @group translation_views
|
||||
*/
|
||||
class ContentModerationIntegration extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['translation_views_test_views'];
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['content_moderation_integration_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp($import_test_views = TRUE) {
|
||||
// Inherit set up from the parent class.
|
||||
parent::setUp($import_test_views);
|
||||
// Login as a root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
// Import test views.
|
||||
ViewTestData::createTestViews(get_class($this), ['translation_views_test_views']);
|
||||
// Create additional language.
|
||||
ConfigurableLanguage::createFromLangcode('af')->save();
|
||||
|
||||
// Enable translation for article nodes.
|
||||
$this->drupalPostForm('admin/config/regional/content-language', [
|
||||
"entity_types[node]" => 1,
|
||||
"settings[node][article][translatable]" => 1,
|
||||
"settings[node][article][settings][language][language_alterable]" => 1,
|
||||
], 'Save configuration');
|
||||
// Flush definitions caches.
|
||||
\Drupal::entityTypeManager()->clearCachedDefinitions();
|
||||
|
||||
// Enable moderation state for article nodes.
|
||||
$workflow = Workflow::load('editorial');
|
||||
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'article');
|
||||
$workflow->save();
|
||||
// Logout.
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test view's field "Translation Moderation State".
|
||||
*/
|
||||
public function testTranslationModerationFieldViews() {
|
||||
// Login as a root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
// Create node for test.
|
||||
$node = $this->createNode(['type' => 'article']);
|
||||
|
||||
// Ensure we have moderation state "Draft" by default
|
||||
// in the newly created node.
|
||||
$this->assertTrue($node->hasField('moderation_state'));
|
||||
$this->assertFalse($node->get('moderation_state')->isEmpty());
|
||||
$this->assertEquals('draft', $node->get('moderation_state')->first()->getString());
|
||||
|
||||
// Go to the testing view's page.
|
||||
$this->drupalGet('/content-moderation-integration-test');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Check that created node has "Draft" moderation state by default.
|
||||
$this->assertSession()->elementTextContains(
|
||||
'css',
|
||||
'.views-field-translation-moderation-state span',
|
||||
'Draft'
|
||||
);
|
||||
|
||||
// Change moderation state to "Published".
|
||||
$node->set('moderation_state', 'published')->save();
|
||||
|
||||
// Reload the testing view's page.
|
||||
$this->drupalGet('/content-moderation-integration-test');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Check that the moderation state value has been changed in view's field.
|
||||
$this->assertSession()->elementTextContains(
|
||||
'css',
|
||||
'.views-field-translation-moderation-state span',
|
||||
'Published'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\translation_views\Functional;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Class LocalTranslationContentIntegrationTest.
|
||||
*
|
||||
* @package Drupal\Tests\translation_views\Functional
|
||||
*
|
||||
* @group translation_views
|
||||
* @requires module local_translation
|
||||
*/
|
||||
class LocalTranslationContentIntegrationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['translation_views_local_translation_test'];
|
||||
|
||||
/**
|
||||
* Local translation skills service.
|
||||
*
|
||||
* @var \Drupal\local_translation\Services\LocalTranslationUserSkills
|
||||
*/
|
||||
protected $skills;
|
||||
/**
|
||||
* User registered skills.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $registeredSkills = ['en', 'fr'];
|
||||
/**
|
||||
* User unregistered skills.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $unregisteredSkills = ['de', 'sq'];
|
||||
/**
|
||||
* Default language ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultLanguage = 'en';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->setUpTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional steps for tests set up.
|
||||
*/
|
||||
protected function setUpTest() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->skills = $this->container->get('local_translation.user_skills');
|
||||
$this->createLanguages();
|
||||
$this->enableTranslation('node', 'article');
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of all testing languages.
|
||||
*
|
||||
* @return array
|
||||
* All testing langcodes array.
|
||||
*/
|
||||
private static function getAllTestingLanguages() {
|
||||
return array_merge(static::$registeredSkills, static::$unregisteredSkills);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change language settings for entity types.
|
||||
*
|
||||
* @param string $category
|
||||
* Entity category (e.g. node).
|
||||
* @param string $subcategory
|
||||
* Entity subcategory (e.g. article).
|
||||
*/
|
||||
protected function enableTranslation($category, $subcategory) {
|
||||
$this->drupalPostForm('admin/config/regional/content-language', [
|
||||
"entity_types[$category]" => 1,
|
||||
"settings[$category][$subcategory][translatable]" => 1,
|
||||
"settings[$category][$subcategory][settings][language][language_alterable]" => 1,
|
||||
], 'Save configuration');
|
||||
\Drupal::entityTypeManager()->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register translation skills for testing.
|
||||
*
|
||||
* @throws \Drupal\Core\Entity\EntityStorageException
|
||||
*/
|
||||
protected function registerTestSkills() {
|
||||
$this->skills->addSkill(static::$registeredSkills);
|
||||
foreach (static::$registeredSkills as $skill) {
|
||||
$this->assertTrue($this->skills->userHasSkill($skill));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create additional languages for testing.
|
||||
*/
|
||||
protected function createLanguages() {
|
||||
try {
|
||||
foreach (static::getAllTestingLanguages() as $language) {
|
||||
if ($language === $this->defaultLanguage) {
|
||||
continue;
|
||||
}
|
||||
$this->assertEquals(1, ConfigurableLanguage::createFromLangcode($language)->save());
|
||||
}
|
||||
}
|
||||
catch (EntityStorageException $e) {
|
||||
$this->fail('Additional languages have not been created');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply check that all required modules have been installed.
|
||||
*/
|
||||
public function testDependencyInstallation() {
|
||||
$this->assertTrue($this->container->get('module_handler')
|
||||
->moduleExists('local_translation'));
|
||||
$this->assertTrue($this->container->get('module_handler')
|
||||
->moduleExists('local_translation_content'));
|
||||
$this->assertTrue($this->container->has('local_translation.user_skills'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test local translation content integration for target language filter.
|
||||
*/
|
||||
public function testLocalTranslationLanguageFilterInView() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->registerTestSkills();
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
Node::create([
|
||||
'type' => 'article',
|
||||
'title' => $this->randomString(),
|
||||
'langcode' => static::$registeredSkills[0],
|
||||
])
|
||||
->addTranslation(static::$registeredSkills[1], ['title' => $this->randomString()])
|
||||
->save();
|
||||
}
|
||||
|
||||
$this->drupalGet('/test-local-translation-content-filter');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->statusCodeNotEquals(404);
|
||||
|
||||
// Find langcode field element.
|
||||
$langcode_field = $this->getSession()
|
||||
->getPage()
|
||||
->findField('translation_target_language');
|
||||
$this->assertNotNull($langcode_field);
|
||||
|
||||
// Get all existing options of the langcode filter dropdown.
|
||||
$options = $langcode_field->findAll('xpath', '//option');
|
||||
$this->assertNotNull($options);
|
||||
|
||||
// Prepare array of options' values.
|
||||
$language_options = array_map(function ($option) {
|
||||
return $option->getAttribute('value') ?: $option->getText();
|
||||
}, $options);
|
||||
|
||||
$this->assertCount(4, $language_options);
|
||||
$this->assertContains('***LANGUAGE_site_default***', $language_options);
|
||||
$this->assertContains('fr', $language_options);
|
||||
$this->assertContains('de', $language_options);
|
||||
$this->assertContains('sq', $language_options);
|
||||
|
||||
$this->drupalGet('/admin/structure/views/nojs/handler/test_local_translation_content_integration/page_1/filter/translation_target_language');
|
||||
// Check for the default state of the options.
|
||||
$this->assertSession()->checkboxNotChecked('options[limit]');
|
||||
$this->assertSession()->checkboxNotChecked('options[column][from]');
|
||||
$this->assertSession()->checkboxChecked('options[column][to]');
|
||||
// Update options.
|
||||
$this->drupalPostForm(NULL, [
|
||||
'options[limit]' => 1,
|
||||
'options[column][from]' => 1,
|
||||
'options[column][to]' => 1,
|
||||
], 'Apply');
|
||||
$this->click('input[value="Save"]');
|
||||
|
||||
$this->drupalGet('/test-local-translation-content-filter');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->statusCodeNotEquals(404);
|
||||
|
||||
// Find langcode field element.
|
||||
$langcode_field = $this->getSession()
|
||||
->getPage()
|
||||
->findField('translation_target_language');
|
||||
$this->assertNotNull($langcode_field);
|
||||
|
||||
// Get all existing options of the langcode filter dropdown.
|
||||
$options = $langcode_field->findAll('xpath', '//option');
|
||||
$this->assertNotNull($options);
|
||||
|
||||
// Prepare array of options' values.
|
||||
$language_options = array_map(function ($option) {
|
||||
return $option->getAttribute('value') ?: $option->getText();
|
||||
}, $options);
|
||||
|
||||
$this->assertCount(2, $language_options);
|
||||
$this->assertContains('en', $language_options);
|
||||
$this->assertContains('fr', $language_options);
|
||||
$this->assertNotContains('de', $language_options);
|
||||
$this->assertNotContains('sq', $language_options);
|
||||
}
|
||||
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\translation_views\Functional;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Class TranslationOperationTargetLanguageTest.
|
||||
*
|
||||
* @package Drupal\Tests\translation_views\Functional
|
||||
*
|
||||
* @group translation_views
|
||||
*/
|
||||
class TranslationOperationTargetLanguageTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* List of the additional language IDs to be created for the tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $langcodes = ['fr', 'de', 'it', 'af', 'sq'];
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'node',
|
||||
'translation_views',
|
||||
'translation_views_test_views',
|
||||
];
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
/**
|
||||
* Testing views ID array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['translation_views_all_filters_and_fields'];
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
private $adminUser;
|
||||
/**
|
||||
* Default language ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $defaultLangcode;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->adminUser = $this->createUser([], 'test_admin', TRUE);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->defaultLangcode = \Drupal::languageManager()
|
||||
->getDefaultLanguage()
|
||||
->getId();
|
||||
|
||||
// Set up testing views.
|
||||
ViewTestData::createTestViews(get_class($this), ['translation_views_test_views']);
|
||||
try {
|
||||
$this->setUpLanguages();
|
||||
}
|
||||
catch (EntityStorageException $e) {
|
||||
$this->verbose($e->getMessage());
|
||||
}
|
||||
// Enable translation for Article nodes.
|
||||
$this->enableTranslation('node', 'article');
|
||||
|
||||
// Create testing node.
|
||||
$this->drupalPostForm('node/add/article', [
|
||||
'title[0][value]' => $this->randomString(),
|
||||
], 'Save');
|
||||
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up languages.
|
||||
*
|
||||
* @throws \Drupal\Core\Entity\EntityStorageException
|
||||
*/
|
||||
private function setUpLanguages() {
|
||||
foreach (self::$langcodes as $langcode) {
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change language settings for entity types.
|
||||
*
|
||||
* @param string $category
|
||||
* Entity category (e.g. node).
|
||||
* @param string $subcategory
|
||||
* Entity subcategory (e.g. article).
|
||||
*/
|
||||
private function enableTranslation($category, $subcategory) {
|
||||
$this->drupalPostForm('admin/config/regional/content-language', [
|
||||
"entity_types[$category]" => 1,
|
||||
"settings[$category][$subcategory][translatable]" => 1,
|
||||
"settings[$category][$subcategory][settings][language][language_alterable]" => 1,
|
||||
], 'Save configuration');
|
||||
\Drupal::entityTypeManager()->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate node all specified languages.
|
||||
*/
|
||||
private function translateNode() {
|
||||
$node = Node::load(1);
|
||||
foreach (self::$langcodes as $langcode) {
|
||||
if (!$node->hasTranslation($langcode)) {
|
||||
$this->assertFalse($node->hasTranslation($langcode));
|
||||
$node->addTranslation($langcode, ['title' => $this->randomMachineName()])->save();
|
||||
$this->assertTrue($node->hasTranslation($langcode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random target language ID from available list.
|
||||
*
|
||||
* @return string
|
||||
* Language ID.
|
||||
*/
|
||||
private function generateTargetLanguage() {
|
||||
$target_language = self::$langcodes[mt_rand(0, 4)];
|
||||
$this->assertNotNull($target_language);
|
||||
return $target_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the response HTTP code is 200.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
private function assertResponseOk() {
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translation operations target language.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementHtmlException
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
public function testTranslationOperationsTargetLanguage() {
|
||||
$base_selector = 'table > tbody > tr:nth-child(1) .views-field-translation-operations ul li';
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Check for "Add" links target languages.
|
||||
$target_language = $this->generateTargetLanguage();
|
||||
$this->drupalGet('translation-views-all-filters-and-fields', [
|
||||
'query' => [
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => $target_language,
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertResponseOk();
|
||||
$expected_create_link = "/$target_language/node/1/translations/add/{$this->defaultLangcode}/$target_language";
|
||||
$this->assertSession()
|
||||
->elementAttributeContains(
|
||||
'css',
|
||||
"{$base_selector} a",
|
||||
'href',
|
||||
$expected_create_link
|
||||
);
|
||||
// Translate nodes.
|
||||
$this->translateNode();
|
||||
// Check for "Edit" and "Delete" links target languages.
|
||||
$target_language = $this->generateTargetLanguage();
|
||||
$this->drupalGet('translation-views-all-filters-and-fields', [
|
||||
'query' => [
|
||||
'content_translation_source' => 'All',
|
||||
'translation_target_language' => $target_language,
|
||||
'translation_default' => 'All',
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertResponseOk();
|
||||
$this->assertSession()
|
||||
->elementAttributeContains(
|
||||
'css',
|
||||
"{$base_selector}.edit a",
|
||||
'href',
|
||||
"/$target_language/node/1/edit"
|
||||
);
|
||||
$this->assertSession()
|
||||
->elementAttributeContains(
|
||||
'css',
|
||||
"{$base_selector}.delete a",
|
||||
'href',
|
||||
"/$target_language/node/1/delete"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\translation_views\Functional;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Class TranslationOperationsFieldPermissionsTest.
|
||||
*
|
||||
* @group translation_views
|
||||
*
|
||||
* @package Drupal\Tests\translation_views\Functional
|
||||
*/
|
||||
class TranslationOperationsFieldPermissionsTest extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* List of the additional language IDs to be created for the tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $langcodes = ['fr', 'de', 'it', 'af', 'sq'];
|
||||
/**
|
||||
* User with permission to create translation.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
private $userCreate;
|
||||
/**
|
||||
* User with permission to update translation.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
private $userUpdate;
|
||||
/**
|
||||
* User with permission to delete translation.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
private $userDelete;
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
private $adminUser;
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'node',
|
||||
'translation_views',
|
||||
'translation_views_test_views',
|
||||
];
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
/**
|
||||
* Testing views ID array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_operations_links'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->setUpUsers();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Set up testing views.
|
||||
ViewTestData::createTestViews(get_class($this), ['translation_views_test_views']);
|
||||
try {
|
||||
$this->setUpLanguages();
|
||||
}
|
||||
catch (EntityStorageException $e) {
|
||||
$this->verbose($e->getMessage());
|
||||
}
|
||||
// Enable translation for Article nodes.
|
||||
$this->enableTranslation('node', 'article');
|
||||
|
||||
// Create testing node.
|
||||
$this->drupalPostForm('node/add/article', [
|
||||
'title[0][value]' => $this->randomString(),
|
||||
], 'Save');
|
||||
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up users with different sets of permissions.
|
||||
*/
|
||||
private function setUpUsers() {
|
||||
$this->adminUser = $this->createUser([], 'test_admin', TRUE);
|
||||
$this->userCreate = $this->createUser(['create content translations']);
|
||||
$this->userUpdate = $this->createUser(['update content translations']);
|
||||
$this->userDelete = $this->createUser(['delete content translations']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up languages.
|
||||
*
|
||||
* @throws \Drupal\Core\Entity\EntityStorageException
|
||||
*/
|
||||
private function setUpLanguages() {
|
||||
foreach (self::$langcodes as $langcode) {
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that text is in specific row.
|
||||
*
|
||||
* @param int $row_number
|
||||
* Table row order number.
|
||||
* @param string $css_class
|
||||
* Part of the css class of required field.
|
||||
* @param string $text
|
||||
* Text that should be found in the element.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementTextException
|
||||
*/
|
||||
private function assertTextInRow($row_number, $css_class, $text) {
|
||||
$this->assertSession()
|
||||
->elementTextContains(
|
||||
'css',
|
||||
".view-content > div:nth-child({$row_number}) .views-field-{$css_class}",
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change language settings for entity types.
|
||||
*
|
||||
* @param string $category
|
||||
* Entity category (e.g. node).
|
||||
* @param string $subcategory
|
||||
* Entity subcategory (e.g. article).
|
||||
*/
|
||||
private function enableTranslation($category, $subcategory) {
|
||||
$this->drupalPostForm('admin/config/regional/content-language', [
|
||||
"entity_types[$category]" => 1,
|
||||
"settings[$category][$subcategory][translatable]" => 1,
|
||||
"settings[$category][$subcategory][settings][language][language_alterable]" => 1,
|
||||
], 'Save configuration');
|
||||
\Drupal::entityTypeManager()->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the /translate/content page.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
private function goToTestingView() {
|
||||
$this->drupalGet('/test_operations_links');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate node all specified languages.
|
||||
*/
|
||||
private function translateNode() {
|
||||
$node = Node::load(1);
|
||||
foreach (self::$langcodes as $langcode) {
|
||||
if (!$node->hasTranslation($langcode)) {
|
||||
$node->addTranslation($langcode, ['title' => $this->randomMachineName()])
|
||||
->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add specific set of permissions to the "authenticated" role.
|
||||
*
|
||||
* @param array $permissions
|
||||
* Permissions array.
|
||||
*/
|
||||
private function addPermissionsForAuthUser(array $permissions = []) {
|
||||
if (!empty($permissions)) {
|
||||
$role = Role::load(Role::AUTHENTICATED_ID);
|
||||
if ($role instanceof Role) {
|
||||
$this->grantPermissions($role, $permissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translation operation create permissions.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementTextException
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
public function testTranslationOperationsCreatePermissions() {
|
||||
$default_language = \Drupal::languageManager()->getDefaultLanguage();
|
||||
$target_language = static::$langcodes[mt_rand(0, 4)];
|
||||
$this->assertNotNull($target_language);
|
||||
$this->assertNotNull($default_language);
|
||||
|
||||
$this->drupalLogin($this->userCreate);
|
||||
|
||||
$this->assertTrue($this->userCreate->hasPermission('create content translations'));
|
||||
$this->assertFalse($this->userCreate->hasPermission('translate any entity'));
|
||||
|
||||
$this->drupalGet('/translate/content', [
|
||||
'query' => [
|
||||
'langcode' => $default_language->getId(),
|
||||
'translation_target_language' => $target_language,
|
||||
'translation_outdated' => 'All',
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->elementNotExists(
|
||||
'css',
|
||||
'table > tbody > tr:nth-child(1) .views-field-translation-operations ul li a'
|
||||
);
|
||||
|
||||
$this->addPermissionsForAuthUser(['translate any entity']);
|
||||
$this->assertTrue($this->userCreate->hasPermission('translate any entity'));
|
||||
|
||||
$this->drupalGet('/translate/content', [
|
||||
'query' => [
|
||||
'langcode' => $default_language->getId(),
|
||||
'translation_target_language' => $target_language,
|
||||
'translation_outdated' => 'All',
|
||||
'translation_status' => 'All',
|
||||
],
|
||||
]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()
|
||||
->elementTextContains(
|
||||
'css',
|
||||
"table > tbody > tr:nth-child(1) .views-field-translation-operations ul li a",
|
||||
'Add'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translation operation update permissions.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementTextException
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
public function testTranslationOperationsUpdatePermissions() {
|
||||
$this->translateNode();
|
||||
$this->assertTrue($this->userUpdate->hasPermission('update content translations'));
|
||||
$this->assertFalse($this->userUpdate->hasPermission('translate any entity'));
|
||||
$this->drupalLogin($this->userUpdate);
|
||||
$this->goToTestingView();
|
||||
$this->assertTextInRow(
|
||||
1,
|
||||
'translation-operations ul li a',
|
||||
'Edit'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translation operation delete permissions.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementTextException
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
public function testTranslationOperationsDeletePermissions() {
|
||||
$this->translateNode();
|
||||
$this->assertTrue($this->userDelete->hasPermission('delete content translations'));
|
||||
$this->assertFalse($this->userDelete->hasPermission('translate any entity'));
|
||||
$this->drupalLogin($this->userDelete);
|
||||
$this->goToTestingView();
|
||||
$this->assertTextInRow(
|
||||
1,
|
||||
'translation-operations ul li a',
|
||||
'Delete'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,8 +7,11 @@ dependencies:
|
||||
- drupal:content_translation
|
||||
- drupal:views
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-05-23
|
||||
version: '8.x-1.0-alpha2'
|
||||
test_dependencies:
|
||||
- local_translation:local_translation
|
||||
|
||||
# Information added by Drupal.org packaging script on 2019-02-07
|
||||
version: '8.x-1.0-alpha5'
|
||||
core: '8.x'
|
||||
project: 'translation_views'
|
||||
datestamp: 1527090186
|
||||
datestamp: 1549581183
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* @file
|
||||
* Provide hooks for translation_views module.
|
||||
*
|
||||
* Basicaly this file only used as workaround for this issue:
|
||||
* https://www.drupal.org/node/2325463.
|
||||
* Basicaly this file is only used as workaround for these issues:
|
||||
* https://www.drupal.org/project/drupal/issues/2954032
|
||||
* https://www.drupal.org/project/drupal/issues/2944278
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Query\AlterableInterface;
|
||||
@@ -41,12 +42,12 @@ function translation_views_form_alter(&$form, FormStateInterface $form_state) {
|
||||
}
|
||||
|
||||
$entity = $form_object->getEntity();
|
||||
$op = $form_object->getOperation();
|
||||
$operations = $form_object->getOperation();
|
||||
|
||||
if ($entity instanceof ContentEntityInterface
|
||||
&& $entity->isTranslatable()
|
||||
&& count($entity->getTranslationLanguages()) > 1
|
||||
&& in_array($op, ['edit', 'add', 'default'], TRUE)
|
||||
&& in_array($operations, ['edit', 'add', 'default'], TRUE)
|
||||
) {
|
||||
$form['source_langcode']['submit']['#submit'][] = 'translation_views_content_form_fix_destination';
|
||||
}
|
||||
@@ -66,9 +67,7 @@ function translation_views_content_form_fix_destination($form, FormStateInterfac
|
||||
$options = [];
|
||||
|
||||
// Remove destination parameter from request,
|
||||
// to allow "Change" button works like desired,
|
||||
// see similar issue here: https://www.drupal.org/node/2325463.
|
||||
// @todo: Create core issue for the content_translation module.
|
||||
// to allow "Change" button works like desired
|
||||
if ($query->has('destination')) {
|
||||
$options['query']['destination'] = $query->get('destination');
|
||||
$query->remove('destination');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provide views extra filters/fields for translator needs.
|
||||
* Provide views fields/filters for content translations.
|
||||
*
|
||||
* @ingroup views_module_handlers
|
||||
*/
|
||||
@@ -50,7 +50,7 @@ function translation_views_views_data_alter(array &$data) {
|
||||
$translations_table =& $data[$key];
|
||||
$translations_table_target =& $data[$target_key];
|
||||
|
||||
$pk = $entity_type->getKey('id');
|
||||
$entity_id = $entity_type->getKey('id');
|
||||
|
||||
$translations_table['table'] = [
|
||||
'group' => $group,
|
||||
@@ -58,10 +58,10 @@ function translation_views_views_data_alter(array &$data) {
|
||||
'join' => [
|
||||
$field_data_table => [
|
||||
'join_id' => 'translation_views_language_join',
|
||||
'entity_pk' => $pk,
|
||||
'entity_id' => $entity_id,
|
||||
'type' => 'LEFT',
|
||||
'left_field' => $pk,
|
||||
'field' => $pk,
|
||||
'left_field' => $entity_id,
|
||||
'field' => $entity_id,
|
||||
'table' => $field_data_table,
|
||||
],
|
||||
],
|
||||
@@ -72,13 +72,17 @@ function translation_views_views_data_alter(array &$data) {
|
||||
$translations_table += FieldDefinitions::buildOpLinksField();
|
||||
$translations_table += FieldDefinitions::buildCountField();
|
||||
|
||||
$module_handler = \Drupal::service('module_handler');
|
||||
if ($module_handler->moduleExists('content_moderation')) {
|
||||
$translations_table += FieldDefinitions::buildModerationStateField();
|
||||
}
|
||||
$translations_table_target['table'] = [
|
||||
'group' => $group,
|
||||
'join' => [
|
||||
$field_data_table => [
|
||||
'type' => 'LEFT',
|
||||
'left_field' => $pk,
|
||||
'field' => $pk,
|
||||
'left_field' => $entity_id,
|
||||
'field' => $entity_id,
|
||||
'table' => $field_data_table,
|
||||
'extra' => [
|
||||
[
|
||||
@@ -99,9 +103,11 @@ function translation_views_views_data_alter(array &$data) {
|
||||
$translations_table_target += FieldDefinitions::buildDefaultLangcodeField(
|
||||
$data[$field_data_table]['default_langcode']
|
||||
);
|
||||
$translations_table_target += FieldDefinitions::buildChangedField(
|
||||
$data[$field_data_table]['changed']
|
||||
);
|
||||
if (isset($data[$field_data_table]['changed'])) {
|
||||
$translations_table_target += FieldDefinitions::buildChangedField(
|
||||
$data[$field_data_table]['changed']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -23,3 +23,6 @@ views.field.views_bulk_operations_bulk_form:
|
||||
preconfiguration:
|
||||
type: ignore
|
||||
label: 'Preliminary configuration array'
|
||||
clear_on_exposed:
|
||||
type: boolean
|
||||
label: 'Clear on exposed'
|
||||
|
||||
+3
-3
@@ -6,8 +6,8 @@ package: 'Views Bulk Operations'
|
||||
dependencies:
|
||||
- drupal:views_bulk_operations
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-07-02
|
||||
version: '8.x-2.4'
|
||||
# Information added by Drupal.org packaging script on 2019-02-21
|
||||
version: '8.x-2.5'
|
||||
core: '8.x'
|
||||
project: 'views_bulk_operations'
|
||||
datestamp: 1530516826
|
||||
datestamp: 1550740388
|
||||
|
||||
+3
-3
@@ -6,8 +6,8 @@ package: 'Examples'
|
||||
dependencies:
|
||||
- drupal:views_bulk_operations
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-07-02
|
||||
version: '8.x-2.4'
|
||||
# Information added by Drupal.org packaging script on 2019-02-21
|
||||
version: '8.x-2.5'
|
||||
core: '8.x'
|
||||
project: 'views_bulk_operations'
|
||||
datestamp: 1530516826
|
||||
datestamp: 1550740388
|
||||
|
||||
+7
-1
@@ -9,6 +9,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Drupal\views_bulk_operations\Service\ViewsBulkOperationsActionProcessorInterface;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
|
||||
@@ -75,7 +76,12 @@ class ViewsBulkOperationsController extends ControllerBase implements ContainerI
|
||||
$this->deleteTempstoreData();
|
||||
|
||||
$this->actionProcessor->executeProcessing($view_data);
|
||||
return batch_process($view_data['redirect_url']);
|
||||
if ($view_data['batch']) {
|
||||
return batch_process($view_data['redirect_url']);
|
||||
}
|
||||
else {
|
||||
return new RedirectResponse($view_data['redirect_url']->setAbsolute()->toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+14
-3
@@ -215,6 +215,12 @@ class ViewsBulkOperationsBulkForm extends FieldPluginBase implements CacheableDe
|
||||
'redirect_url' => Url::createFromRequest(clone $this->requestStack->getCurrentRequest()),
|
||||
'exposed_input' => $this->view->getExposedInput(),
|
||||
];
|
||||
$query = $variable['redirect_url']->getOption('query');
|
||||
if (!$query) {
|
||||
$query = [];
|
||||
}
|
||||
$query += $variable['exposed_input'];
|
||||
$variable['redirect_url']->setOption('query', $query);
|
||||
|
||||
// Create tempstore data object if it doesn't exist.
|
||||
if (!is_array($this->tempStoreData)) {
|
||||
@@ -624,7 +630,7 @@ class ViewsBulkOperationsBulkForm extends FieldPluginBase implements CacheableDe
|
||||
$action_id = $form_state->getValue('action');
|
||||
if (!empty($action_id)) {
|
||||
$action = $this->actions[$action_id];
|
||||
if ($this->isConfigurable($action)) {
|
||||
if ($this->isActionConfigurable($action)) {
|
||||
$actionObject = $this->actionManager->createInstance($action_id);
|
||||
$form['header'][$this->options['id']]['configuration'] += $actionObject->buildConfigurationForm($form['header'][$this->options['id']]['configuration'], $form_state);
|
||||
$form['header'][$this->options['id']]['configuration']['#config_included'] = TRUE;
|
||||
@@ -778,7 +784,7 @@ class ViewsBulkOperationsBulkForm extends FieldPluginBase implements CacheableDe
|
||||
$this->tempStoreData['list'] = [];
|
||||
}
|
||||
|
||||
$configurable = $this->isConfigurable($action);
|
||||
$configurable = $this->isActionConfigurable($action);
|
||||
|
||||
// Get configuration if using AJAX.
|
||||
if ($configurable && empty($this->options['form_step'])) {
|
||||
@@ -794,6 +800,11 @@ class ViewsBulkOperationsBulkForm extends FieldPluginBase implements CacheableDe
|
||||
}
|
||||
|
||||
// Routing - determine redirect route.
|
||||
|
||||
// Set default redirection due to issue #2952498.
|
||||
// TODO: remove the next line when core cause is eliminated.
|
||||
$redirect_route = 'views_bulk_operations.execute_batch';
|
||||
|
||||
if ($this->options['form_step'] && $configurable) {
|
||||
$redirect_route = 'views_bulk_operations.execute_configurable';
|
||||
}
|
||||
@@ -887,7 +898,7 @@ class ViewsBulkOperationsBulkForm extends FieldPluginBase implements CacheableDe
|
||||
/**
|
||||
* Check if an action is configurable.
|
||||
*/
|
||||
protected function isConfigurable($action) {
|
||||
protected function isActionConfigurable($action) {
|
||||
return (in_array('Drupal\Core\Plugin\PluginFormInterface', class_implements($action['class']), TRUE) || method_exists($action['class'], 'buildConfigurationForm'));
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -7,8 +7,8 @@ dependencies:
|
||||
- drupal:views_bulk_operations
|
||||
- drupal:node
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-07-02
|
||||
version: '8.x-2.4'
|
||||
# Information added by Drupal.org packaging script on 2019-02-21
|
||||
version: '8.x-2.5'
|
||||
core: '8.x'
|
||||
project: 'views_bulk_operations'
|
||||
datestamp: 1530516826
|
||||
datestamp: 1550740388
|
||||
|
||||
+3
-3
@@ -6,8 +6,8 @@ package: 'Views'
|
||||
dependencies:
|
||||
- drupal:views (>=8.4)
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-07-02
|
||||
version: '8.x-2.4'
|
||||
# Information added by Drupal.org packaging script on 2019-02-21
|
||||
version: '8.x-2.5'
|
||||
core: '8.x'
|
||||
project: 'views_bulk_operations'
|
||||
datestamp: 1530516826
|
||||
datestamp: 1550740388
|
||||
|
||||
Reference in New Issue
Block a user