Вы здесь

Запретить доступ к нодам, которые не были переведены

0

На сайте использую Entity translation для перевода сайта на китайский (оригинала на английском). Часть нод не переведена на китайский, соответственно по ссылке /cn/node/%node отображается версия на английском. Это вобщем то не большая проблема, но гугл каким то образом нашел эту ссылку и теперь сообщает о дублировании контента. Есть ли способ перенаправлять запрос с /cn/node/%node на /node/%node либо возвращать 404 ошибку при переходе на страницу ноды, если нет перевода для выбранного языка?
Пробовал Global redirect, но он вроде пока не дружит с Entity translation

Версия Drupal: 
7.x
Категория: 
Multilingual
Связанные проекты: 
Entity Translation
Вопрос задан 20.11.2015 - 21:18

Ответы

0

Вот такое решение в итоге получилось. В добавок к отображению 404 ошибки, еще и добавляется линк с hreflang если нода/термин имеют перевод

<?php
/**
 * @file
 * Main module file.
 */

/**
 * Implements hook_permission().
 */
function ft_multilingual_permission() {
  return array(
    'view untranslated pages' => array(
      'title' => t('View untranslated pages'),
      'description' => t('Allow users to view untranslated pages.')
    )
  );
}

/**
 * Implements hook_page_build().
 */
function ft_multilingual_page_build(&$page) {
  // Return early if site is monolingual.
  if (!drupal_multilingual()) {
    return;
  }
  // No need to add hreflang tags for 404/403 pages.
  $status = drupal_get_http_header('status');
  if ($status == '404 Not Found' || $status == '403 Forbidden') {
    return;
  }

  $path = drupal_is_front_page() ? '' : $_GET['q'];
  $links = language_negotiation_get_switch_links(LANGUAGE_TYPE_INTERFACE, $path);
  if (empty($links->links)) {
    return;
  }

  $node = menu_get_object();
  $taxonomy_term = menu_get_object('taxonomy_term', 2);
  foreach ($links->links as $langcode => $link) {
    // Content translation module may unset the href attribute.
    if (!isset($link['href'])) {
      continue;
    }
    // No need to add link to untranslated node and taxonomy term pages.
    if (($node && !ft_multilingual_is_entity_translated('node', $node, $langcode)) ||
      ($taxonomy_term && !ft_multilingual_is_entity_translated('taxonomy_term', $taxonomy_term, $langcode))) {
      continue;
    }
    $link['absolute'] = TRUE;
    if (!isset($link['query'])) {
      $link['query'] = array();
    }
    $link['query'] += drupal_get_query_parameters();
    $attributes = array(
      'href' => url($link['href'], $link),
      'rel' => 'alternate',
      'hreflang' => $langcode,
    );
    drupal_add_html_head_link($attributes);
  }
}

/**
 * Implements hook_language_switch_links_alter().
 */
function ft_multilingual_language_switch_links_alter(array &$links, $type, $path) {
  $node = menu_get_object();
  $taxonomy_term = menu_get_object('taxonomy_term', 2);
  foreach ($links as $langcode => &$link) {
    // Exclude links to languages where node or taxonomy term were not translated.
    if (((($node && !ft_multilingual_is_entity_translated('node', $node, $langcode)) ||
      ($taxonomy_term && !ft_multilingual_is_entity_translated('taxonomy_term', $taxonomy_term, $langcode))) &&
      !user_access('view untranslated pages'))) {

      $link['href'] = '<front>';
    }
    else {
      $link['attributes']['hreflang'] = $langcode;
    }
  }
}

/**
 * Implements hook_init().
 */
function ft_multilingual_init() {
  if (!user_access('view untranslated pages')) {
    $node = menu_get_object();
    $taxonomy_term = menu_get_object('taxonomy_term', 2);
    if (($node && !ft_multilingual_is_entity_translated('node', $node)) ||
      ($taxonomy_term && !ft_multilingual_is_entity_translated('taxonomy_term', $taxonomy_term))) {
      drupal_not_found();
    }
  }
}

/**
 * Detect if entity have published translation.
 */
function ft_multilingual_is_entity_translated($entity_type, $entity, $langcode = NULL) {
  global $language;
  $langcode = empty($langcode) ? $language->language : $langcode;
  if (entity_translation_get_existing_language($entity_type, $entity, $langcode) != $langcode) {
    return FALSE;
  }

  $handler = entity_translation_get_handler($entity_type, $entity);
  $translations = $handler->getTranslations();
  if (!$translations->data[$langcode]['status']) {
    return FALSE;
  }

  return TRUE;
}

Ответ дан 24.11.2015 - 10:22
0

Есть три варианта решения проблемы.
1. сеошный. закрыть от индексации ненужные страницы и удалить их из индекса. Если настроен pathauto то можно будет масками закрывать. Если ненастроен, то точечно по конкретным нодам.
2. административный. Есть модули типа translation table. Скормить таблицу контент-менеджеру, который на каждую пока не переведенную страницу создаст заглушку типа "Наполнение сттаницы скоро появится".
3. Програмный. andlevashov дал ссылку на направление куда думать. Легкого пути тут нет, подтверждаю. Если же кто нашел - делитесь, мне тоже такое надо :)

Ответ дан 20.11.2015 - 23:39
0

код не проверял

function MODULE_init(){
    $arg = arg();

    if ($arg[0] == 'node' and isset($arg[1]) and is_numeric($arg[1]) and !isset($arg[2])) {
        $node = menu_get_object();
        global $language;

        if (isset($node->nid) and $language->language != $node->language) {
            drupal_not_found();
        }
    }
}
Ответ дан 21.11.2015 - 00:41

Не уверен насчет проверки

$language->language != $node->language

Насколько я понимаю, при использовании entity translation значение $node->language всегда одно и то же. перевод имеют поля, а не сама нода. Хотя пока и не копал код этого модуля и такой подход не тестил, возможно ошибаюсь

Комментарий оставлен 21.11.2015 - 12:47
0

Вот такое решение я использовал. Суть в том, что пишем простой access plugin для ctools.
Затем через админку в page_manager активируем шаблон для node/%nid и настраиваем нужные правила, например:
-ограничиваем типы материалов (статья)
-ограничиваем роли (все кроме администратора и редактора)
-eTranslation node == True
в качестве действий можно указать 404 или редирект на http:основнойдомен/node/%node:nid

В итоге, все простые пользователи (и поисковик) при попадании на не переведенную ноду будут перенаправлены на основной домен. А редакторы будут видеть данный материал и смогут нажать на заветную вкладку Translate.

Приведу код плагина. Его нужно подключать в своем модуле как любой access plugin

<?php

/**
 * @file
 * Describes ctools access example plugin.
 */

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = array(
  // Plugin user-friendly name.
  'title' => t('eTranslation node'),
  // Plugin description.
  'description' => t('Controls access eTranslate'),
  // Without required context plugin will now be shown in Panels UI.
  'required context' => array(new ctools_context_required(t('Node'), 'node')),
  // Function which will allow or restrict access.
  'callback' => 'zexler_node_etranslate_access',
);

/**
 * Check for access.
 */
function zexler_node_etranslate_access($conf, $context) {
  global $language;
  // There should always be a context at this point, but this
  // is safe.
  if (empty($context[0]) || empty($context[0]->data)) {
    return FALSE;
  }

  // We should ignore this access rule in case user is viewing his own profile.
  $entity = $context[0]->data;
  $language_default = language_default('language');

  if($entity->language == $language->language || ($language_default == $language->language && $entity->language == LANGUAGE_NONE)){
    return TRUE;
  }

  if (isset($entity->translations->data[$language->language]) && $entity->translations->data[$language->language]['status']) {
    return TRUE;
  }
  return FALSE;
}

Если заинтересовало решение, пишите, сделаю небольшой урок

Ответ дан 20.04.2017 - 19:46
-1

если global redirect не дружит с entity translation, тогда в robots пропишите по советам из http://drupalim.ru/comment/3324
конкретно ваш шаблон:
Disallow: /node/*
тут обсуждалось http://dru.io/question/2680

Ответ дан 20.11.2015 - 21:31

как вариант, можно закрыть все в robots.txt. Но хочется найти какое-то более общее решение, чтобы закрыть доступ к любой сущности и даже если для страницы сущности нет алиаса.

Комментарий оставлен 21.11.2015 - 12:51

хочется найти какое-то более общее решение, чтобы закрыть доступ к любой сущности и даже если для страницы сущности нет алиаса

Немного теории:
На большинстве Друпал сайтов используется views. Он в свою очередь требует ctools. В комплекте с ctools идет page_manager (это не панели, он не требует такой нагрузки). Из коробки он позволяет переопределить любой системный путь и выдать требуемый http response по заданному Вами условию. Просто включите его и попробуйте настроить
Теперь по теме:
Если у страницы сущности нет алиаса, но есть страница - значит есть системный путь (кстати, это отдельная тема - объяснить людям что такое системный путь, алиас и редирект). А если есть системный путь, значит его можно перехватить в page_manager. Выставить 404 там уже нет проблем. И суть задачи ограничивается только выставлением условий. А тут если нет стандартного решения, то всегда можно написать свой маленький плагин...

Комментарий оставлен 20.05.2017 - 06:11