cloudwords-8.x-1.x-dev/modules/cloudwords_translation/cloudwords_translation.module

modules/cloudwords_translation/cloudwords_translation.module
<?php

/**
 * @file
 * Integrates Cloudwords with the Contnent translation module.
 */

use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Core\Language\Language;
use Drupal\content_translation;

// @todo remove if not used "cloudwords_translation_menu_alter"
/**
 * Implements hook_menu_alter().
 *
 * Take control of node/%node/translate.
 */
function cloudwords_translation_menu_alter(&$items) {
  $items['node/%node/translate']['page callback'] = 'cloudwords_translation_node_overview_page';
  $items['node/%node/translate']['file'] = 'cloudwords_translation.pages.inc';
  $items['node/%node/translate']['file path'] = drupal_get_path('module', 'cloudwords_translation');
  $items['node/%node/translate']['module'] = 'cloudwords_translation';
}

// @todo remove if not used "cloudwords_module_implements_alter"
/**
 * Implements hook_module_implements_alter().
 *
 * Move our hook_menu_alter() to the end.
 */
function cloudwords_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'menu_alter') {
    $group = $implementations['cloudwords_translation'];
    unset($implementations['cloudwords_translation']);
    $implementations['cloudwords_translation'] = $group;
  }
}

/**
 * Implements hook_cloudwords_translatable_info().
 */
function cloudwords_translation_cloudwords_translatable_info() {
  // @todo only specify translatable configured entities?
  $entity_types = \Drupal::entityTypeManager()->getDefinitions();
  foreach($entity_types as $entity_type){
    // @todo prevent entity_reference_revisions from having a source controller
    if($entity_type->isTranslatable() && $entity_type->getConfigDependencyKey() == 'content') {
      $entity_controllers[$entity_type->id()] = [
        'controller class' => '\Drupal\cloudwords_translation\CloudwordsEntitySourceController',
      ];
    }
  }

  return $entity_controllers;
}


/**
 * Populates a field on an object with the provided field values.
 *
 * @param stdClass $entity
 *   The object to be populated.
 * @param array $data
 *   An array of values.
 * @param string $language
 *   The field language.
 */
function cloudwords_field_populate_entity($entity, array $data, $language, $hostLanguage, &$translated_fields) {
  $attachableEntityTypes = ['entity_reference_revisions'];

  $source_data = cloudwords_field_get_source_data($entity->getEntityTypeId(), $entity);

  $translated_fields = [];

  foreach (\Drupal\Core\Render\Element::children($data) as $field_name) {
    if ($info =\Drupal\field\Entity\FieldConfig::loadByName($entity->getEntityTypeId(), $entity->bundle(), $field_name)) {
      foreach (\Drupal\Core\Render\Element::children($data[$field_name]) as $delta) {

        //$langcode = $info->get('translatable') ? $language : \Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED;
        //exclude attached entity fields
        $module = $info->getFieldStorageDefinition()->get('module');
        if(!in_array($module,$attachableEntityTypes)){
          $columns = [];
          foreach (\Drupal\Core\Render\Element::children($data[$field_name][$delta]) as $column) {
            if (isset($data[$field_name][$delta][$column]['#translation']['#text'])) {
              $columns[$column] = $data[$field_name][$delta][$column]['#translation']['#text'];
            }
            // For elements which are not translatable, keep using the original value
            elseif (isset($data[$field_name][$delta][$column]['#translate']) && $data[$field_name][$delta][$column]['#translate'] == FALSE) {
              $columns[$column] = $data[$field_name][$delta][$column]['#text'];
            }
          }

          $translated_fields[$field_name][$delta] = $columns;

          //map field metadata
          // @todo refactor to use more self explanatory data structure. "#text" doesn't make sense for format values, uris, etc.
          foreach($source_data[$field_name][$delta] as $source_item_key => $source_item_value){
            if(is_array($source_item_value) && isset($source_item_value['#translate']) && $source_item_value['#translate'] == FALSE){
              $translated_fields[$field_name][$delta][$source_item_key] = $source_item_value['#text'];
            }
          }
        }
      }
    }
  }
}

// @todo alter this to work with entity reference revisions - not field collection specific
/**
 * Populates entities attached via reference.  Currently only supports field collections.
 *
 * @param string $entity_type
 *   The entity type.
 * @param stdClass $entity
 *   The object to be populated.
 * @param array $data
 *   An array of values.
 * @param string $language
 *   The field language.
 * @param string $hostLanguage
 *   The host entity's language.
 * @param string $iterationCount
 *   The iteration count for recursion. Does not recurse past $maxDepth int.
 */
function cloudwords_field_populate_attached_entities($entity_type, $entity, array $data, $language, $hostLanguage, $iterationCount = 0) {
  $maxDepth = 5;
  foreach (\Drupal\Core\Render\Element::children($data) as $field_name) {
    if ($info =\Drupal\field\Entity\FieldConfig::loadByName($entity->getEntityTypeId(), $entity->bundle(), $field_name)) {
      $module = $info->getFieldStorageDefinition()->get('module');
      if($module == 'entity_reference_revisions'){
        foreach (\Drupal\Core\Render\Element::children($data[$field_name]) as $delta) {
          // load entity
          $target_type = $entity->{$field_name}->getFieldDefinition()->getSetting('target_type');
          $e_ref_entity = \Drupal::entityTypeManager()->getStorage($target_type)->load($entity->{$field_name}[$delta]->target_id);
          $a_data = reset($data[$field_name][$delta]['value']);

          // populate entity values
          $translated_fields = [];
          cloudwords_field_populate_entity($e_ref_entity, $a_data, $language, $hostLanguage, $translated_fields);
          if(!$e_ref_entity->hasTranslation($language)){
            $e_ref_entity->addTranslation($language);
          }
          $translation = $e_ref_entity->getTranslation($language);

          foreach($translated_fields as $name => $value) {
            $translation->$name = $value;
          }
// @todo implement depth
//          if($iterationCount < $maxDepth) {
//            $iterationCount++;
//            cloudwords_field_populate_attached_entities($e_ref_entity->getEntityTypeId(), $e_ref_entity, $a_data, $language, $hostLanguage);
//          }
          $translation->save();
        }
      }
    }
  }
}

/**
 * Implements hook_cloudwords_source_translation_structure().
 *
 * This hook is implemented on behalf of the core text module.
 */
function text_cloudwords_source_translation_structure($field_name, $entity_type, $entity, $field_instance) {
  $structure = [];
  if (!empty($entity->get($field_name)->value)) {
    $field_info = \Drupal\field\Entity\FieldConfig::loadByName($entity_type, $entity->bundle(), $field_name);

    $structure['#label'] = \Drupal\Component\Utility\Html::escape($field_instance->get('label'));

    foreach ($entity->get($field_name) as $delta => $value) {
      $structure[$delta]['#label'] = t('Delta #@delta', ['@delta' => $delta]);
      $structure[$delta]['value'] = [
        '#label' => $structure['#label'],
        '#text' => $value->value,
        '#translate' => TRUE,
      ];

      // Add format.
      if(!empty($value->format)) {
        $structure[$delta]['format'] = [
          '#label' => '',
          '#text' => $value->format,
          '#translate' => FALSE,
        ];
      }
      // @todo text_with_summary
      if ($field_info->get('field_type') == 'text_with_summary' && !empty($value->summary)) {
        $structure[$delta]['summary'] = [
          '#label' => t('Summary'),
          '#text' => $value->summary,
          '#translate' => TRUE,
        ];
      }
    }
  }
  return $structure;
}

/**
 * Implements hook_cloudwords_source_translation_structure().
 *
 * Translate the title field of a link
 */
function link_cloudwords_source_translation_structure($field_name, $entity_type, $entity, $field_instance) {
  $structure = [];

  if (!empty($entity->get($field_name)->getLangcode())){
    foreach ($entity->get($field_name) as $delta => $value) {
      $structure[$delta]['#label'] = t('Delta #@delta', ['@delta' => $delta]);
      $structure[$delta]['title'] = [
        '#label' => 'Title',
        '#text' => $value->title,
        '#translate' => TRUE,
      ];
      $structure[$delta]['uri'] = [
        '#label' => 'URI',
        '#text' => $value->uri,
        '#translate' => FALSE,
      ];
    }
  }
  return $structure;
}

/**
 * Implements hook_cloudwords_source_translation_structure().
 *
 * This hook is implemented on behalf of the entity_reference_revisions module.
 */
function entity_reference_revisions_cloudwords_source_translation_structure($field_name, $entity_type, $entity, $field_instance) {
  $structure = [];

  $structure['#label'] = $field_instance->getLabel();
  foreach ($entity->{$field_name} as $delta => $value) {
    $target_type = $value->getFieldDefinition()->getSetting('target_type');
    $e_ref_entity = \Drupal::entityTypeManager()->getStorage($target_type)->load($value->target_id);

    $e_ref_structure = cloudwords_field_get_source_data($target_type, $e_ref_entity);
    $structure[$delta]['#label'] = t('Delta #@delta', ['@delta' => $delta]);
    $structure[$delta]['value'] = [
      '#label' => $structure['#label'],
      $e_ref_entity->id() => $e_ref_structure,
      '#translate' => TRUE,
    ];
  }

  return $structure;
}

// @todo remove and use handler for entity reference revisions which works on paragraphs (likely successor to field_collections)
/**
 * Implements hook_cloudwords_source_translation_structure().
 *
 * This hook is implemented on behalf of the field_collection module.
 */
//function field_collection_cloudwords_source_translation_structure($field_name, $entity_type, $entity, $field_instance) {
//  $field_lang = field_language($entity_type, $entity, $field_name);
//  $structure = array();
//  if (!empty($entity->{$field_name}[$field_lang])) {
//    $field_info = field_info_field($field_name);
//    $structure['#label'] = \Drupal\Component\Utility\Html::escape($field_instance['label']);
//    foreach ($entity->{$field_name}[$field_lang] as $delta => $value) {
//      $fc = \Drupal::entityManager()->getStorage('field_collection_item', array($value['value']));
//      $fc = reset($fc);
//      $fc_structure = cloudwords_field_get_source_data('field_collection_item', $fc);
//      $structure[$delta]['#label'] = t('Delta #@delta', array('@delta' => $delta));
//      $structure[$delta]['value'] = array(
//        '#label' => $structure['#label'],
//        $fc->item_id => $fc_structure,
//        '#translate' => TRUE,
//      );
//    }
//  }
//
//  return $structure;
//}

/**
 * Helper function for retrieving all translatable field values from an entity.
 *
 * @param string $entity_type
 *   The entity type.
 * @param object $entity
 *   An entity object.
 *
 * @return array
 *   The structured field data for all translatable fields
 */
function cloudwords_field_get_source_data($entity_type, $entity, $field_translation = FALSE) {
  $fields = [];
  $translate_field_instance = FALSE;
  // @todo figure out field instance translation handling
  $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $entity->bundle());

  $instances = [];
  foreach ($field_definitions as $key => $definition) {

    if ($definition instanceof \Drupal\field\Entity\FieldConfig) {
      $instances[$key] = $definition;
    }
  }

  foreach ($instances as $field_name => $field_instance) {
    $info = \Drupal\field\Entity\FieldConfig::loadByName($entity_type, $entity->bundle(), $field_name);

    // @todo clean up value access for module - there are likely other fields that should utilize the text_ hook
    $module = $info->getFieldStorageDefinition()->get('module');
    if($module == 'core' && $info->getFieldStorageDefinition()->get('type') == 'string'){
      $module = 'text';
    }

    if($module == 'entity_reference_revisions'){
      $translate_field_instance = TRUE;
    }elseif(!$field_translation || $info->isTranslatable()){
      $translate_field_instance = TRUE;
    }else{
      $translate_field_instance = FALSE;
    }

    if ($translate_field_instance && $data = \Drupal::moduleHandler()->invoke($module, 'cloudwords_source_translation_structure', [$field_name, $entity_type, $entity, $field_instance])) {
      $fields[$field_name] = $data;
    }
  }

  return $fields;
}

function cloudwords_translation_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id){
  switch($form_id){
    case 'node_page_edit_form':
      $form['actions']['submit']['#submit'][] = 'Drupal\cloudwords_translation\Form\CloudwordsTranslationFormAlter::entityFormSubmit';
    break;
  }
}

// @todo remove if not used
/**
 * Implements hook_form_FORM_ID_alter().
 */
//function cloudwords_translation_form_node_form_alter(&$form, &$form_state) {
//  $user = \Drupal::currentUser();
//  $node = $form['#node'];
//
//  // workaround/fix for translation.module line 164, where the groups are not taken into consideration
//  // $languages = language_list('enabled');
//  $languages = \Drupal::languageManager()->getLanguages();
//  $disabled_languages = isset($languages[0]) ? $languages[0] : FALSE;
//  $translator_widget = $disabled_languages && \Drupal::currentUser()->hasPermission('translate content');
//  $groups = array(t('Disabled'), t('Enabled'));
//  if (!empty($node->nid) && !empty($node->tnid)) {
//    // Disable languages for existing translations, so it is not possible to switch this
//    // node to some language which is already in the translation set. Also remove the
//    // language neutral option.
//    if ($translator_widget) {
//      foreach ($groups as $group) {
//        unset($form['language']['#options'][$group][\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED]);
//      }
//    }
//    else {
//      unset($form['language']['#options'][\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED]);
//    }
//  }
//  // end of fix
//
//
//  // prevent primary node from switching to neutral if active translatables exist
//  if (!empty($node->nid)) {
//    $translatables = cloudwords_get_translatables_by_property(array(
//      'type' => 'node_content',
//      'textgroup' => 'node',
//      'objectid' => !empty($node->tnid) ? $node->tnid : $node->nid,
//    ), 'language');
//
//    $allow_neutral = TRUE;
//    $disabled_langs = array();
//    foreach ($translatables as $langcode => $translatable) {
//      if ($translatable->status != CLOUDWORDS_QUEUE_NOT_IN_QUEUE || $translatable->uid != 0) {
//        $disabled_langs[] = $langcode;
//        $allow_neutral = FALSE;
//      }
//    }
//
//    if (!$allow_neutral) {
//      if ($translator_widget) {
//        foreach ($groups as $group) {
//          unset($form['language']['#options'][$group][\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED]);
//          foreach ($disabled_langs as $disabled_lang) {
//            unset($form['language']['#options'][$group][$disabled_lang]);
//          }
//        }
//      }
//      else {
//        unset($form['language']['#options'][\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED]);
//        foreach ($disabled_langs as $disabled_lang) {
//          unset($form['language']['#options'][$disabled_lang]);
//        }
//      }
//    }
//  }
//
//  $element = array(
//    '#type' => 'checkbox',
//    '#title' => t('Mark all languages for translation.'),
//    '#states' => array(
//      'invisible' => array(
//        ':input[name="language"]' => array(
//          'value' => 'und',
//        ),
//      ),
//    ),
//  );
//
//  if (empty($node->nid) && empty($node->translation_source) && cloudwords_translation_supported_type($node->type)) {
//    $form['cloudwords_add_to_queue'] = $element;
//  }
//  elseif (cloudwords_translation_supported_type($node->type)) {
//    $form['cloudwords_add_to_queue'] = $element;
//  }
//}

/**
 * Determines if the node is the primary node in a translation set.
 *
 * @param stdClass $node
 *   A node object.
 *
 * @return bool
 *   TRUE if the node is the primary node, and FALSE if not.
 */
function cloudwords_translation_is_primary_node(\Drupal\node\NodeInterface $node) {
  return !$node->tnid || $node->tnid == $node->id();
}

// @todo refresh translatables
/**
 * Implements hook_cloudwords_refresh_translatables().
 */

function cloudwords_translation_cloudwords_refresh_translatables(&$context) {
  $langcodes = array_keys(cloudwords_language_list());
  $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
  $langcodes = array_diff($langcodes, [$default_langcode]);
  $context['finished'] = 0;

  if(!isset($context['sandbox']['processed_runs'])){
    $context['sandbox']['processed_runs'] = 0;
  }

  if (!isset($context['sandbox']['translatable_items'])) {
    $context['sandbox']['translatables_created'] = 0;
    $entity_types = \Drupal::entityTypeManager()->getDefinitions();
    // @todo entityManager is deprecated, change
    $bundles = \Drupal::entityManager()->getAllBundleInfo();
    foreach ($entity_types as $entity_type_id => $entity_type) {
      if (!$entity_type instanceof \Drupal\Core\Entity\ContentEntityType || !$entity_type->hasKey('langcode') || !isset($bundles[$entity_type_id])) {
        continue;
      }
      foreach ($bundles[$entity_type_id] as $bundle => $bundle_info) {
        $config = \Drupal\language\Entity\ContentLanguageSettings::loadByEntityTypeBundle($entity_type_id, $bundle);
        $bundle_langs = array_diff($langcodes, [$config->language()->getId()]);
        $content_translation_settings = $config->getThirdPartySettings('content_translation');
        if(isset($content_translation_settings['enabled']) && $content_translation_settings['enabled'] == 1) {
          $additional = $entity_type->get('additional');
          // @todo find better mechanism for filtering out entity reference revision item and other translatable items with parent id
          if(!isset($additional['entity_revision_parent_type_field'])) {
            $ids = \Drupal::entityQuery($entity_type_id)->condition($entity_type->getKey('bundle'), $bundle)->execute();
            foreach($ids as $id){
              $context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id] = array_combine($bundle_langs, $bundle_langs);
            }
            $context['sandbox']['total'] += count($ids);
          }
        }
      }
    }

    $context['sandbox']['last'] = 0;
    $context['sandbox']['count'] = 0;

  } else {
    // prune the translatable items index to remove existing translatables
    foreach($context['sandbox']['translatable_items'] as $entity_type_id => $bundle_group){
      foreach($bundle_group as $bundle => $ids){

        $translatables = cloudwords_get_translatables_by_property([
          'translation_module' => CLOUDWORDS_CONTENT_TRANSLATION_TYPE,
          'type' => $entity_type_id,
          'objectid' => array_keys($ids),
          'bundle' => $bundle,
        ]);

        foreach($translatables as $translatable){
          $id = $translatable->getObjectId();
          $lang = $translatable->getLanguage();

          // If translatable exists, remove it from queue
          if(in_array($translatable->getObjectId(), array_keys($ids))){
            unset($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id][$lang]);
            if(count($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id]) == 0){
              unset($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id]);
            }
          }
        }
      }
    }
    // @todo batch this out to only run a few hundred or so at a time in case tens of thousands or translatables need saving
    // process translatable items
    foreach($context['sandbox']['translatable_items'] as $entity_type_id => $bundle_group){
      foreach($bundle_group as $bundle => $ids){
        foreach($ids as $id => $langs){
          $entity = \Drupal::entityTypeManager()->getStorage($entity_type_id)->load($id);
          foreach($langs as $lang) {
            $new = cloudwords_translatable_create([
              'translation_module' => CLOUDWORDS_CONTENT_TRANSLATION_TYPE,
              'objectid' => $id,
              'language' => $lang,
              'name' => $entity->label(),
              'textgroup' => $entity_type_id,
              'type' => $entity_type_id,
              'bundle' => $bundle,
              'user_id' => 0,
            ]);
            $new->save();
            $context['sandbox']['translatables_created'] += 1;
            unset($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id][$lang]);
            if(count($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id]) == 0){
              unset($context['sandbox']['translatable_items'][$entity_type_id][$bundle][$id]);
            }
          }
        }
        if(count($context['sandbox']['translatable_items'][$entity_type_id][$bundle]) == 0){
          unset($context['sandbox']['translatable_items'][$entity_type_id][$bundle]);
        }
        if(count($context['sandbox']['translatable_items'][$entity_type_id]) == 0){
          unset($context['sandbox']['translatable_items'][$entity_type_id]);
        }
      }
    }

    if (empty($context['sandbox']['translatable_items'])) {
      $msg = \Drupal::translation()->formatPlural($context['sandbox']['translatables_created'],
        'Content Translation: Created @count translatable',
        'Content Translation: Created @count translatables',
        ['%count' => $context['sandbox']['translatables_created']]);
      drupal_set_message($msg);
      $context['finished'] = 1;
    }

    // safeguard to prevent batch from running forever in the case of a data anomaly
    $context['sandbox']['processed_runs'] += 1;
    if($context['sandbox']['processed_runs'] == 100){
      $context['finished'] = 1;
    }
  }
}

/**
 * Implements hook_entity_insert().
 */
function cloudwords_translation_entity_insert(Drupal\Core\Entity\EntityInterface $entity){
  _cloudwords_translation_entity_upsert($entity);
}

/**
 * Implements hook_entity_update().
 */
function cloudwords_translation_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
  _cloudwords_translation_entity_upsert($entity);
}


function _cloudwords_translation_entity_upsert(Drupal\Core\Entity\EntityInterface $entity) {

  $entity_type_id = $entity->getEntityTypeId();
  $entity_info = \Drupal::entityTypeManager()->getDefinition($entity_type_id);

  $entity_values = $entity->toArray();
  //@TODO prohibit entity items with parents as well as entity items without labels.  Need better logic for rules defining which entities with parents shoudl be prohibited

  $content_translation_manager = \Drupal::service('content_translation.manager');

  if ($entity_info->isTranslatable() && $content_translation_manager->isEnabled($entity->getEntityTypeId(), $entity->bundle()) && !empty($entity->label()) && !isset($entity_values['parent_id']) && $entity->language()->isDefault()) {

    $queue_status = !empty($entity->cloudwords_add_to_queue) ? CLOUDWORDS_QUEUE_QUEUED : CLOUDWORDS_QUEUE_NOT_IN_QUEUE;
    //$entity_ids = entity_extract_ids($entity_type_id, $entity);
    $objectid = $entity->id();
    $textgroup = $entity_info->id();
    //@TODO change type
    $type = $entity_info->id();
    $label = $entity->label();
    $bundle = $entity->bundle();

    if ($entity->language() != \Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED) {

      //@todo translation_type and queue_status
      $translatables = cloudwords_get_translatables_by_property([
        'textgroup' => $textgroup,
     //   'type' => $translatable_type,
        'objectid' => $objectid,
      ], 'language');

      foreach (cloudwords_language_list() as $langcode => $language) {
        if(!isset($translatables[$langcode]) && $entity->language()->getId() != $langcode){
          $translatables[$langcode] = cloudwords_translatable_create([
            'translation_module' => CLOUDWORDS_CONTENT_TRANSLATION_TYPE,
            'textgroup' => $textgroup,
            'type' => $type,
            'objectid' => $objectid,
            'language' => $langcode,
            'name' => $label,
            'bundle' => $bundle,
            'user_id' => 0,
          ]);
        }
      }

      foreach($translatables as $translatable){
        $translatable->name = $entity->label();
     //   $translatable->status = $queue_status;
        $translatable->save();
      }
    }
  }
}

/**
 * Implements hook_entity_delete().
 */
function cloudwords_translation_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
  $entity_type_id = $entity->getEntityTypeId();
  $entity_info = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
  $objectid = $entity->id();
  $textgroup = $entity_info->id();
  //@TODO change type
  $type = $entity_info->id();
//  $label = $entity->label();
//  $bundle = $entity->bundle();
  $translatables = cloudwords_get_translatables_by_property([
    'translation_module' => CLOUDWORDS_CONTENT_TRANSLATION_TYPE,
    'textgroup' => $textgroup,
    'type' => $type,
    'objectid' => $objectid,
  ], 'language');

  if(!empty($translatables)){
    cloudwords_translatable_delete_by_property([
      'translation_module' => CLOUDWORDS_CONTENT_TRANSLATION_TYPE,
      'type' => $type,
      'textgroup' => $textgroup,
      'objectid' => $objectid,
    ]);
  }
}

//function cloudwords_translation_before_entity_save(&$node, $data, $source_language, $translation_type) {
//  foreach (\Drupal::moduleHandler()->getImplementations('cloudwords_translation_before_entity_save') as $module) {
//    $function = $module . '_cloudwords_translation_before_entity_save';
//    $function($node, $data, $source_language, $translation_type);
//  }
//}
/**
 * Implements hook_menu_links_discovered_alter().
 */
function cloudwords_translation_menu_links_discovered_alter(array &$links) {}

/**
 * Implements hook_menu_local_tasks_alter().
 */
function cloudwords_translation_menu_local_tasks_alter(array &$data, $route_name) {}

/**
 * Implements hook_menu_local_actions_alter().
 */
function cloudwords_translation_menu_local_actions_alter(array &$local_actions) {}

/**
 * Implements hook_contextual_links_view_alter().
 */
function cloudwords_translation_contextual_links_view_alter(array &$element, array $items) {}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc