You are here

tmgmt_i18n_string.module in Translation Management Tool 7

Source plugin for the Translation Management system that handles i18n strings.

File

sources/i18n_string/tmgmt_i18n_string.module
View source
<?php

/**
 * @file
 * Source plugin for the Translation Management system that handles i18n strings.
 */

/**
 * Implements hook_tmgmt_source_plugin_info().
 */
function tmgmt_i18n_string_tmgmt_source_plugin_info() {
  $info['i18n_string'] = array(
    'label' => t('i18n String'),
    'description' => t('Source handler for i18n strings.'),
    'plugin controller class' => 'TMGMTI18nStringSourcePluginController',
    'ui controller class' => 'TMGMTI18nStringDefaultSourceUIController',
  );
  foreach (i18n_object_info() as $object_type => $object_info) {

    // Only consider object types that have string translation information.
    if (isset($object_info['string translation'])) {
      $info['i18n_string']['item types'][$object_type] = $object_info['title'];
    }
  }
  return $info;
}

/**
 * Gets i18n strings for given type and label.
 *
 * @param string $type
 *   i18n object type.
 * @param string $search_label
 *   Label to search for.
 * @param string $target_language
 *   Target language.
 * @param string $target_status
 *   Target status.
 *
 * @return array
 *   List of i18n strings data.
 */
function tmgmt_i18n_string_get_strings($type, $search_label = NULL, $target_language = NULL, $target_status = 'untranslated_or_outdated') {
  $info = i18n_object_info($type);
  $languages = drupal_map_assoc(array_keys(language_list()));
  $select = db_select('i18n_string', 'i18n_s');
  $select
    ->addTag('tmgmt_sources_search');
  $select
    ->addMetaData('plugin', 'i18n_string');
  $select
    ->addMetaData('type', $type);
  $select
    ->condition('i18n_s.textgroup', $info['string translation']['textgroup']);
  if (!empty($target_language) && in_array($target_language, $languages)) {
    if ($target_status == 'untranslated_or_outdated') {
      $or = db_or();
      $or
        ->isNull("lt_{$target_language}.language");
      $or
        ->condition("lt_{$target_language}.i18n_status", I18N_STRING_STATUS_UPDATE);
      $select
        ->condition($or);
    }
    elseif ($target_status == 'outdated') {
      $select
        ->condition("lt_{$target_language}.i18n_status", I18N_STRING_STATUS_UPDATE);
    }
    elseif ($target_status == 'untranslated') {
      $select
        ->isNull("lt_{$target_language}.language");
    }
  }
  if (isset($info['string translation']['type'])) {
    $select
      ->condition('i18n_s.type', $info['string translation']['type']);
  }
  elseif ($type == 'field' || $type == 'field_instance') {

    // Fields and field instances share the same textgroup. Use list of bundles
    // to include/exclude field_instances.
    $bundles = array();
    foreach (entity_get_info() as $entity_info) {
      $bundles = array_merge($bundles, array_keys($entity_info['bundles']));
    }
    $select
      ->condition('i18n_s.objectid', $bundles, $type == 'field_instance' ? 'IN' : 'NOT IN');
  }
  $select
    ->join('locales_source', 'ls', 'ls.lid = i18n_s.lid');
  $select
    ->addField('ls', 'source');
  if (!empty($search_label)) {
    $select
      ->condition('ls.source', "%{$search_label}%", 'LIKE');
  }
  foreach ($languages as $langcode) {
    $langcode = str_replace('-', '', $langcode);
    $select
      ->leftJoin('locales_target', "lt_{$langcode}", "i18n_s.lid = %alias.lid AND %alias.language = '{$langcode}'");
    $select
      ->addField("lt_{$langcode}", 'language', "lang_{$langcode}");
  }
  $select
    ->fields("i18n_s", array(
    'lid',
    'textgroup',
    'context',
    'type',
    'objectid',
  ));
  $select
    ->addExpression("concat(i18n_s.textgroup, ':', i18n_s.type, ':', i18n_s.objectid)", 'job_item_id');
  $select
    ->orderBy('i18n_s.context');
  $select
    ->groupBy('type');
  $select
    ->groupBy('objectid');
  $select = $select
    ->extend('PagerDefault')
    ->limit(variable_get('tmgmt_source_list_limit', 20));
  return $select
    ->execute()
    ->fetchAll();
}

/**
 * Implements hook_form_ID_alter().
 *
 * Adds request translation capabilities into i18n translate tab.
 */
function tmgmt_i18n_string_form_i18n_string_translate_page_overview_form_alter(&$form, &$form_state) {
  $object = $form['object']['#value'];

  // Create the id: textgroup:type:objectid.
  $id = $object
    ->get_textgroup() . ':' . implode(':', $object
    ->get_string_context());
  $source_language = variable_get_value('i18n_string_source_language');
  $existing_items = tmgmt_job_item_load_latest('i18n_string', $object
    ->get_type(), $id, $source_language);
  $form['top_actions']['#type'] = 'actions';
  $form['top_actions']['#weight'] = -10;
  tmgmt_ui_add_cart_form($form['top_actions'], $form_state, 'i18n_string', $object
    ->get_type(), $id);
  $form['languages']['#type'] = 'tableselect';

  // Append lang code so that we can use it
  foreach ($form['languages']['#rows'] as $lang => $row) {
    if (isset($existing_items[$lang])) {
      $states = tmgmt_job_item_states();
      $row['status'] = $states[$existing_items[$lang]->state];
      if ($existing_items[$lang]
        ->isNeedsReview()) {
        $row['operations'] .= ' | ' . l(t('review'), 'admin/tmgmt/items/' . $existing_items[$lang]->tjiid, array(
          'query' => array(
            'destination' => $_GET['q'],
          ),
        ));
      }
      elseif ($existing_items[$lang]
        ->isActive()) {
        $row['operations'] .= ' | ' . l(t('in progress'), 'admin/tmgmt/items/' . $existing_items[$lang]->tjiid, array(
          'query' => array(
            'destination' => $_GET['q'],
          ),
        ));
      }
    }
    $form['languages']['#options'][$id . ':' . $lang] = $row;
    if ($lang == $source_language || isset($existing_items[$lang])) {
      $form['languages'][$id . ':' . $lang] = array(
        '#type' => 'checkbox',
        '#disabled' => TRUE,
      );
    }
  }
  unset($form['languages']['#rows'], $form['languages']['#theme']);
  $form['actions']['request_translation'] = array(
    '#type' => 'submit',
    '#value' => t('Request translation'),
    '#submit' => array(
      'tmgmt_i18n_string_translate_form_submit',
    ),
    '#validate' => array(
      'tmgmt_i18n_string_translate_form_validate',
    ),
  );
}

/**
 * Validation callback for the entity translation overview form.
 */
function tmgmt_i18n_string_translate_form_validate($form, &$form_state) {
  $selected = array_filter($form_state['values']['languages']);
  if (empty($selected)) {
    form_set_error('languages', t('You have to select at least one language for requesting a translation.'));
  }
}
function tmgmt_i18n_string_translate_form_submit($form, &$form_state) {
  $items = array_filter($form_state['values']['languages']);
  $type = $form_state['values']['object']
    ->get_type();
  $source_lang = variable_get_value('i18n_string_source_language');
  $jobs = array();
  $target_lang_registry = array();

  // Loop through entities and create individual jobs for each source language.
  foreach ($items as $item) {
    $item_parts = explode(':', $item);
    $target_lang = array_pop($item_parts);
    $key = implode(':', $item_parts);

    // For given source lang no job exists yet.
    if (!isset($target_lang_registry[$target_lang])) {

      // Create new job.
      $job = tmgmt_job_create($source_lang, $target_lang, $GLOBALS['user']->uid);

      // Add initial job item.
      $job
        ->addItem('i18n_string', $type, $key);

      // Add job identifier into registry
      $target_lang_registry[$target_lang] = $job->tjid;

      // Add newly created job into jobs queue.
      $jobs[$job->tjid] = $job;
    }
    else {
      $jobs[$target_lang_registry[$target_lang]]
        ->addItem('i18n_string', $type, $key);
    }
  }
  tmgmt_ui_job_checkout_and_redirect($form_state, $jobs);
}

/**
 * Implements hook_i18n_object_info_alter().
 */
function tmgmt_i18n_string_i18n_object_info_alter(&$info) {
  $entity_info = entity_get_info();

  // Add a entity key to the object info if neither load callback nor entity
  // keys are set and the object is an entity_type.
  // @todo: Add this as default in EntityDefaultI18nStringController.
  foreach ($info as $name => &$object) {
    if (!isset($object['load callback']) && !isset($object['entity']) && isset($entity_info[$name])) {
      $object['entity'] = $name;
    }
  }
}

/**
 * Returns the i18n wrapper object.
 *
 * I18N objects with one or two keys are supported.
 *
 * @param string $type
 *   I18n object type.
 * @param object $i18n_string
 *   Object with type and objectid properties.
 *
 * @return i18n_string_object_wrapper
 */
function tmgmt_i18n_string_get_wrapper($type, $i18n_string) {
  $object_key = i18n_object_info($type, 'key');

  // Special handling for i18nviews.
  if ($type == 'views') {

    // The construct method needs the full view object.
    $view = views_get_view($i18n_string->objectid);
    $wrapper = i18n_get_object($type, $i18n_string->objectid, $view);
    return $wrapper;
  }

  // Special handling for i18n_panels.
  $panels_objects = array(
    'pane_configuration' => 'panels_pane',
    'display_configuration' => 'panels_display',
  );
  if (in_array($type, array_keys($panels_objects))) {
    ctools_include('export');
    $wrapper = FALSE;
    switch ($type) {
      case 'display_configuration':
        $object_array = ctools_export_load_object($panels_objects[$type], 'conditions', array(
          'uuid' => $i18n_string->objectid,
        ));
        $wrapper = i18n_get_object($type, $i18n_string->objectid, $object_array[$i18n_string->objectid]);
        break;
      case 'pane_configuration':
        $obj = db_query("SELECT * FROM {panels_pane} WHERE uuid = :uuid", array(
          ':uuid' => $i18n_string->objectid,
        ))
          ->fetchObject();
        if ($obj) {
          $pane = ctools_export_unpack_object($panels_objects[$type], $obj);
          $translation = i18n_panels_get_i18n_translation_object($pane);
          $translation->uuid = $pane->uuid;
          $wrapper = i18n_get_object($type, $i18n_string->objectid, $translation);
        }
        break;
      default:
        break;
    }
    return $wrapper;
  }

  // Special handling if the object has two keys. Assume that they
  // mean type and object id.
  if ($type == 'field') {

    // Special case for fields which expect the type to be the identifier.
    $wrapper = i18n_get_object($type, $i18n_string->type);
    return $wrapper;
  }
  elseif ($type == 'field_instance') {

    // Special case for field instances, which use the field name as type and
    // bundle as object id. We don't know the entity_type, so we loop over all
    // entity_types to search for the bundle. This will clash if different
    // entity types have bundles with the same names.
    foreach (entity_get_info() as $entity_type => $entity_info) {
      if (isset($entity_info['bundles'][$i18n_string->objectid])) {
        list($type_key, $objectid_key) = $object_key;
        $wrapper = i18n_get_object($type, array(
          $type_key => $i18n_string->type,
          $objectid_key => $i18n_string->objectid,
        ), field_info_instance($entity_type, $i18n_string->type, $i18n_string->objectid));
        return $wrapper;
      }
    }
  }
  elseif (count($object_key) == 2) {
    list($type_key, $objectid_key) = $object_key;
    $wrapper = i18n_get_object($type, array(
      $type_key => $i18n_string->type,
      $objectid_key => $i18n_string->objectid,
    ));
    return $wrapper;
  }
  else {

    // Otherwise, use the object id.
    $wrapper = i18n_get_object($type, $i18n_string->objectid);
    return $wrapper;
  }
}

/**
 * Implements hook_tmgmt_source_suggestions()
 */
function tmgmt_i18n_string_tmgmt_source_suggestions(array $items, TMGMTJob $job) {
  $suggestions = array();
  foreach ($items as $item) {
    if ($item instanceof TMGMTJobItem && $item->item_type == 'node') {

      // Load translatable menu items related to this node.
      $query = db_select('menu_links', 'ml')
        ->condition('ml.link_path', 'node/' . $item->item_id)
        ->fields('ml', array(
        'mlid',
      ));
      $query
        ->join('menu_custom', 'mc', 'ml.menu_name = mc.menu_name AND mc.i18n_mode = ' . I18N_MODE_MULTIPLE);
      $results = $query
        ->execute()
        ->fetchAllAssoc('mlid');
      foreach ($results as $result) {
        $menu_link = menu_link_load($result->mlid);

        // Add suggestion.
        $suggestions[] = array(
          'job_item' => tmgmt_job_item_create('i18n_string', 'menu_link', "menu:item:{$result->mlid}"),
          'reason' => t('Menu link @title', array(
            '@title' => $menu_link['link_title'],
          )),
          'from_item' => $item->tjiid,
        );
      }
    }
  }
  return $suggestions;
}