translators-8.x-1.x-dev/modules/translators_content/translators_content.module
modules/translators_content/translators_content.module
<?php
/**
* @file
* Basic module file.
*/
use Drupal\comment\CommentInterface;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\translators_content\Controller\TranslatorsContentEntityLangcodeFieldController as LangcodeFieldController;
use Drupal\translators_content\Plugin\views\filter\TranslationLanguageLimitedToTranslationSkills;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\ViewExecutable;
use Drupal\node\Entity\Node;
/**
* Implements hook_views_query_alter().
*/
function translators_content_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
if (!empty($view->filter)) {
// Prepare available translation skills for the current user.
$translatorSkills = \Drupal::service('translators.skills')->getTranslationSkills();
// Prevent any operations in case of empty skills list.
// Traverse through the view's filters list.
foreach ($view->filter as $filter) {
// Handle only filters of plugin "translator_skills_filter".
// And if the default "All" option has been selected
// or non-exposed filter is used.
if ($filter instanceof TranslationLanguageLimitedToTranslationSkills
&& ($filter->options['limit'])) {
// Prepare skills list.
$skills_list = [];
// Filter list of skills by the specified columns option
// in the filter's settings form.
foreach ($filter->options['column'] as $name => $column) {
if (!empty($column)) {
foreach ($translatorSkills as $skill) {
if (isset($skill["language_$name"])) {
$skills_list[] = $skill["language_$name"];
}
}
}
}
// Prevent possibly duplicated entries.
$skills_list = array_unique($skills_list);
if (!empty($skills_list)) {
$operator = 'in';
if (isset($filter->options['remove']) && $filter->options['remove'] == 1) {
$operator = 'not in';
}
// Add condition to the new where group
// to prevent harming existing where groups logic.
$query->addWhere(
$query->setWhereGroup(),
"$filter->table.$filter->realField",
$skills_list,
$operator
);
}
else {
// Prevent query being executed at all
// if no user skills are exist.
$view->executed = TRUE;
continue;
}
}
}
}
}
/**
* Implements hook_views_plugins_filter_alter().
*/
function translators_content_views_plugins_filter_alter(array &$plugins) {
// Replace the core's language filter class with our own class,
// which extends the original filter functionality.
if (isset($plugins['language']) && !empty($plugins['language'])) {
$plugins['language']['class'] = TranslationLanguageLimitedToTranslationSkills::class;
$plugins['language']['provider'] = 'translators_content';
}
}
/**
* Implements hook_theme_registry_alter().
*/
function translators_content_theme_registry_alter(&$theme_registry) {
// Specify the path for the template of views_ui_expose_filter_form.
$path = \Drupal::service('extension.list.module')->getPath('translators_content') . '/templates';
$theme_registry['views_ui_expose_filter_form']['path'] = $path;
}
/**
* Implements hook_entity_access().
*/
function translators_content_entity_access(EntityInterface $entity, $operation) {
if ($operation !== 'update' && $operation !== 'delete') {
return AccessResult::neutral();
}
if ($entity instanceof ContentEntityInterface) {
$langcode = $entity->language()->getId();
if ($entity->isDefaultTranslation()) {
$entity_type_id = $entity->getEntityTypeId();
if ($entity_type_id == 'node'
|| $entity_type_id == 'taxonomy_term'
|| $entity_type_id == 'media') {
$entity_bundle = $entity->bundle();
$operation = $operation == 'update' ? 'edit' : $operation;
$currentUser = \Drupal::currentUser();
if ($currentUser->hasPermission("translators_content $operation any $entity_bundle $entity_type_id")) {
$translatorSkills = \Drupal::service('translators.skills');
return AccessResult::allowedIf(
$translatorSkills->hasLangcode($langcode))
->cachePerPermissions()->addCacheableDependency($entity);
}
else {
return AccessResult::neutral();
}
}
}
else {
$handler = \Drupal::entityTypeManager()->getHandler($entity->getEntityTypeId(), 'translation');
return $handler->getTranslationAccess($entity, $operation, $langcode);
}
}
}
/**
* Implements hook_entity_create_access().
*/
function translators_content_entity_create_access(AccountInterface $account, array $context, $entity_bundle) {
$entity_type_id = $context['entity_type_id'];
if ($entity_type_id == 'node'
|| $entity_type_id == 'taxonomy_term'
|| $entity_type_id == 'media') {
$currentUser = \Drupal::currentUser();
if ($currentUser->hasPermission("translators_content create $entity_bundle $entity_type_id")) {
$langcode = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
$translatorSkills = \Drupal::service('translators.skills');
return AccessResult::allowedIf($translatorSkills->hasLangcode($langcode))
->cachePerPermissions();
}
}
}
/**
* Implements hook_config_schema_info_alter().
*/
function translators_content_config_schema_info_alter(&$definitions) {
$definition =& $definitions['views.filter.language'];
$definition['mapping']['limit'] = [
'type' => 'boolean',
'label' => 'Enable limiting languages list using Translators module',
];
$definition['mapping']['column'] = [
'type' => 'mapping',
'label' => 'Column',
'mapping' => [
'source' => [
'type' => 'string',
'label' => 'Source language',
],
'target' => [
'type' => 'string',
'label' => 'Target language',
],
],
];
}
/**
* Implements hook_form_alter().
*/
function translators_content_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$build_info = $form_state->getBuildInfo();
$entity_form = $build_info['callback_object'];
if (!($entity_form instanceof ContentEntityFormInterface)) {
return;
}
// Filter original language options.
if (isset($form['langcode'])) {
$form['langcode']['widget']['#after_build'][] = [
LangcodeFieldController::class,
'entityFormLangcodeAfterBuild'
];
}
// Filter source language options.
$source_options =& $form['source_langcode']['source']['#options'];
if (isset($source_options)) {
$user = \Drupal::currentUser();
$build_info = $form_state->getBuildInfo();
$entity_form = $build_info['callback_object'];
$entity = $entity_form->getEntity();
$config = \Drupal::configFactory()->get('translators.settings');
$operation = \Drupal::routeMatch()
->getRouteObject()
->getRequirement('_access_content_translation_manage');
if ($user->hasPermission("$operation content translations")
|| (($entity instanceof Node) && $user->hasPermission('bypass node access'))) {
return;
}
elseif ($user->hasPermission("translators_content $operation content translations")) {
if ($config->get('enable_strict_translation_skill_pairing') == TRUE) {
// Remove if user doesn't have the source-target language pair.
LangcodeFieldController::filterLanguageOptions($source_options, 'source_skill_languages_only');
}
else {
// Remove if user doesn't have the source language.
LangcodeFieldController::filterLanguageOptions($source_options, 'all_skill_languages');
}
}
}
}
/**
* Implements hook_module_implements_alter().
*/
function translators_content_module_implements_alter(&$implementations, $hook) {
if (stripos($hook, 'form_alter') !== FALSE) {
if (isset($implementations['translators_content'])) {
$temp = $implementations['translators_content'];
unset($implementations['translators_content']);
$implementations['translators_content'] = $temp;
}
}
}
/**
* Implements hook_entity_type_alter().
*/
function translators_content_entity_type_alter(array &$entity_types) {
foreach ($entity_types as $name => $entity_type) {
if ($entity_type->isTranslatable()) {
switch ($name) {
case 'block_content':
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentBlockContentTranslationHandler');
break;
case 'comment':
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentCommentTranslationHandler');
break;
case 'node':
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentNodeTranslationHandler');
break;
case 'taxonomy_term':
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentTermTranslationHandler');
break;
case 'user':
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentProfileTranslationHandler');
break;
default:
$entity_type->setHandlerClass('translation', 'Drupal\translators_content\Handler\TranslatorsContentTranslationHandler');
}
}
}
}
/**
* Implements hook_comment_links_alter().
*/
function translators_content_comment_links_alter(array &$links, CommentInterface $entity, array &$context) {
// @todo: Remove when core issue is fixed: https://www.drupal.org/project/drupal/issues/3134223
$links['#links'] = [];
$entity = $entity->getTranslation($context['langcode']);
$commented_entity = $entity->getCommentedEntity();
$status = $commented_entity->get($entity->getFieldName())->status;
if ($status == CommentItemInterface::OPEN) {
if ($entity->access('delete')) {
$links['#links']['comment-delete'] = [
'title' => t('Delete'),
'url' => $entity->toUrl('delete-form'),
'language' => $entity->language(),
];
}
if ($entity->access('update')) {
$links['#links']['comment-edit'] = [
'title' => t('Edit'),
'url' => $entity->toUrl('edit-form'),
'language' => $entity->language(),
];
}
if ($entity->access('create')) {
$links['#links']['comment-reply'] = [
'title' => t('Reply'),
'url' => Url::fromRoute('comment.reply', [
'entity_type' => $entity->getCommentedEntityTypeId(),
'entity' => $entity->getCommentedEntityId(),
'field_name' => $entity->getFieldName(),
'pid' => $entity->id(),
]),
'language' => $entity->language(),
];
}
if (!$entity->isPublished() && $entity->access('approve')) {
$links['#links']['comment-approve'] = [
'title' => t('Approve'),
'url' => Url::fromRoute('comment.approve', ['comment' => $entity->id()]),
'language' => $entity->language(),
];
}
if (empty($links) && \Drupal::currentUser()->isAnonymous()) {
$links['comment-forbidden']['title'] = \Drupal::commentManager()->forbiddenMessage($commented_entity, $entity->getFieldName());
}
}
$handler = \Drupal::entityTypeManager()->getHandler($entity->getEntityTypeId(), 'translation');
// Add translations link for translation-enabled comment bundles.
if ($handler->getBundleTranslationAccess($entity)->isAllowed()
&& $handler->hasOperationTranslationAccess()) {
$links['#links']['comment-translations'] = [
'title' => t('Translate'),
'url' => $entity->toUrl('drupal:content-translation-overview'),
];
}
}
