diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/argument/NodeTnid.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/argument/NodeTnid.php
new file mode 100644
index 0000000..8f2ca4c
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/argument/NodeTnid.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\argument\NodeTnid.
+ */
+
+namespace Drupal\translation\Plugin\views\argument;
+
+use Drupal\views\Plugin\views\argument\Numeric;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Argument handler to accept a node translation id.
+ *
+ * @ingroup views_argument_handlers
+ *
+ * @Plugin(
+ *   id = "node_tnid",
+ *   module = "translation"
+ * )
+ */
+class NodeTnid extends Numeric {
+
+  /**
+   * Override the behavior of title(). Get the title of the node.
+   */
+  function title_query() {
+    $titles = array();
+
+    $query = db_select('node', 'n');
+    $query->addField('n', 'title');
+    $query->condition('n.tnid', $this->value);
+    $result = $query->execute();
+    foreach ($result as $term) {
+      $titles[] = check_plain($term->title);
+    }
+    return $titles;
+  }
+
+}
diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeLinkTranslate.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeLinkTranslate.php
new file mode 100644
index 0000000..b77ec82
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeLinkTranslate.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\field\NodeLinkTranslate.
+ */
+
+namespace Drupal\translation\Plugin\views\field;
+
+use Drupal\node\Plugin\views\field\Link;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Field handler to present a link node translate.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @Plugin(
+ *   id = "node_link_translate",
+ *   module = "translation"
+ * )
+ */
+class NodeLinkTranslate extends Link {
+
+  function render_link($data, $values) {
+    // ensure user has access to edit this node.
+    $node = $this->get_value($values);
+    $node->status = 1; // unpublished nodes ignore access control
+    if (empty($node->langcode) || !translation_supported_type($node->type) || !node_access('view', $node) || !user_access('translate content')) {
+      return;
+    }
+
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "node/$node->nid/translate";
+    $this->options['alter']['query'] = drupal_get_destination();
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('translate');
+    return $text;
+  }
+
+}
diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeTranslationLink.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeTranslationLink.php
new file mode 100644
index 0000000..8a1cf2e
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/field/NodeTranslationLink.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\field\NodeTranslationLink.
+ */
+
+namespace Drupal\translation\Plugin\views\field;
+
+use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Field handler to present a link to the node.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @Plugin(
+ *   id = "node_translation_link",
+ *   module = "translation"
+ * )
+ */
+class NodeTranslationLink extends FieldPluginBase {
+
+  /**
+   * Overrides Drupal\views\Plugin\views\field\FieldPluginBase::init().
+   */
+  public function init(ViewExecutable $view, &$options) {
+    parent::init($view, $options);
+
+    $this->additional_fields['nid'] = 'nid';
+    $this->additional_fields['tnid'] = 'tnid';
+    $this->additional_fields['title'] = 'title';
+    $this->additional_fields['langcode'] = 'langcode';
+  }
+
+  public function query() {
+    $this->ensureMyTable();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $value = $this->get_value($values, 'tnid');
+    return $this->render_link($this->sanitizeValue($value), $values);
+  }
+
+  function render_link($data, $values) {
+    $language_interface = language(LANGUAGE_TYPE_INTERFACE);
+
+    $tnid = $this->get_value($values, 'tnid');
+    // Only load translations if the node isn't in the current language.
+    if ($this->get_value($values, 'langcode') != $language_interface->langcode) {
+      $translations = translation_node_get_translations($tnid);
+      if (isset($translations[$language_interface->langcode])) {
+        $values->{$this->aliases['nid']} = $translations[$language_interface->langcode]->nid;
+        $values->{$this->aliases['title']} = $translations[$language_interface->langcode]->title;
+      }
+    }
+
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "node/" . $this->get_value($values, 'nid');
+    return $this->get_value($values, 'title');
+  }
+
+}
diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnid.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnid.php
new file mode 100644
index 0000000..1e446d1
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnid.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\filter\NodeTnid.
+ */
+
+namespace Drupal\translation\Plugin\views\filter;
+
+use Drupal\views\Plugin\views\filter\FilterPluginBase;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Filter by whether the node is the original translation.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @Plugin(
+ *   id = "node_tnid",
+ *   module = "translation"
+ * )
+ */
+class NodeTnid extends FilterPluginBase {
+
+  public function adminSummary() { }
+
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+
+    $options['operator']['default'] = 1;
+
+    return $options;
+  }
+
+  /**
+   * Provide simple boolean operator
+   */
+  function operator_form(&$form, &$form_state) {
+    $form['operator'] = array(
+      '#type' => 'radios',
+      '#title' => t('Include untranslated content'),
+      '#default_value' => $this->operator,
+      '#options' => array(
+        1 => t('Yes'),
+        0 => t('No'),
+      ),
+    );
+  }
+
+  public function canExpose() { return FALSE; }
+
+  public function query() {
+    $table = $this->ensureMyTable();
+    // Select for source translations (tnid = nid). Conditionally, also accept either untranslated nodes (tnid = 0).
+    $this->query->add_where_expression($this->options['group'], "$table.tnid = $table.nid" . ($this->operator ? " OR $table.tnid = 0" : ''));
+  }
+
+}
diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnidChild.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnidChild.php
new file mode 100644
index 0000000..3881e77
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/filter/NodeTnidChild.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\filter\NodeTnidChild.
+ */
+
+namespace Drupal\translation\Plugin\views\filter;
+
+use Drupal\views\Plugin\views\filter\FilterPluginBase;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Filter by whether the node is not the original translation.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @Plugin(
+ *   id = "node_tnid_child",
+ *   module = "translation"
+ * )
+ */
+class NodeTnidChild extends FilterPluginBase {
+
+  public function adminSummary() { }
+
+  function operator_form(&$form, &$form_state) { }
+
+  public function canExpose() { return FALSE; }
+
+  public function query() {
+    $table = $this->ensureMyTable();
+    $this->query->add_where_expression($this->options['group'], "$table.tnid <> $table.nid AND $table.tnid > 0");
+  }
+
+}
diff --git a/core/modules/translation/lib/Drupal/translation/Plugin/views/relationship/Translation.php b/core/modules/translation/lib/Drupal/translation/Plugin/views/relationship/Translation.php
new file mode 100644
index 0000000..1324537
--- /dev/null
+++ b/core/modules/translation/lib/Drupal/translation/Plugin/views/relationship/Translation.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\translation\Plugin\views\relationship\Translation.
+ */
+
+namespace Drupal\translation\Plugin\views\relationship;
+
+use Drupal\views\Plugin\views\relationship\RelationshipPluginBase;
+use Drupal\Core\Annotation\Plugin;
+
+/**
+ * Handles relationships for content translation sets and provides multiple
+ * options.
+ *
+ * @ingroup views_relationship_handlers
+ *
+ * @Plugin(
+ *   id = "translation",
+ *   module = "translation"
+ * )
+ */
+class Translation extends RelationshipPluginBase {
+
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['language'] = array('default' => 'current');
+
+    return $options;
+  }
+
+  /**
+   * Add a translation selector.
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $options = array(
+      'all' => t('All'),
+      'current' => t('Current language'),
+      'default' => t('Default language'),
+    );
+    $options = array_merge($options, views_language_list());
+    $form['language'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+      '#default_value' => $this->options['language'],
+      '#title' => t('Translation option'),
+      '#description' => t('The translation options allows you to select which translation or translations in a translation set join on. Select "Current language" or "Default language" to join on the translation in the current or default language respectively. Select a specific language to join on a translation in that language. If you select "All", each translation will create a new row, which may appear to cause duplicates.'),
+    );
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   */
+  public function query() {
+    // Figure out what base table this relationship brings to the party.
+    $table_data = views_fetch_data($this->definition['base']);
+    $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
+
+    $this->ensureMyTable();
+
+    $def = $this->definition;
+    $def['table'] = $this->definition['base'];
+    $def['field'] = $base_field;
+    $def['left_table'] = $this->tableAlias;
+    $def['left_field'] = $this->field;
+    $def['adjusted'] = TRUE;
+    if (!empty($this->options['required'])) {
+      $def['type'] = 'INNER';
+    }
+
+    $def['extra'] = array();
+    if ($this->options['language'] != 'all') {
+      switch ($this->options['language']) {
+        case 'current':
+          $def['extra'][] = array(
+            'field' => 'langcode',
+            'value' => '***CURRENT_LANGUAGE***',
+          );
+          break;
+        case 'default':
+          $def['extra'][] = array(
+            'field' => 'langcode',
+            'value' => '***DEFAULT_LANGUAGE***',
+          );
+          break;
+        // Other values will be the language codes.
+        default:
+          $def['extra'][] = array(
+            'field' => 'langcode',
+            'value' => $this->options['language'],
+          );
+          break;
+      }
+    }
+
+    if (!empty($def['join_id'])) {
+      $id = $def['join_id'];
+    }
+    else {
+      $id = 'standard';
+    }
+    $join = drupal_container()->get('plugin.manager.views.join')->createInstance($id, $def);
+
+    // use a short alias for this:
+    $alias = $def['table'] . '_' . $this->table;
+
+    $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+  }
+
+}
diff --git a/core/modules/translation/translation.views.inc b/core/modules/translation/translation.views.inc
new file mode 100644
index 0000000..6564b31
--- /dev/null
+++ b/core/modules/translation/translation.views.inc
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Provide views data and handlers for translation.module.
+ *
+ * @ingroup views_module_handlers
+ */
+
+/**
+ * Implements hook_views_data_alter().
+ *
+ * Add translation information to the node table.
+ */
+function translation_views_data_alter(&$data) {
+
+  // Joins
+  $data['node']['table']['join']['node'] = array(
+    'left_field' => 'tnid',
+    'field' => 'tnid',
+  );
+
+  // The translation ID (nid of the "source" translation)
+  $data['node']['tnid'] = array(
+    'group' => t('Content translation'),
+    'title' => t('Translation set node ID'),
+    'help' => t('The ID of the translation set the content belongs to.'),
+    'field' => array(
+      'id' => 'node',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'id' => 'numeric',
+    ),
+    'argument' => array(
+      'id' => 'node_tnid',
+      'name field' => 'title', // the field to display in the summary.
+      'numeric' => TRUE,
+      'validate type' => 'tnid',
+    ),
+    'sort' => array(
+      'id' => 'standard',
+    ),
+    'relationship' => array(
+      'title' => t('Source translation'),
+      'help' => t('The source that this content was translated from.'),
+      'base' => 'node',
+      'base field' => 'nid',
+      'id' => 'standard',
+      'label' => t('Source translation'),
+    ),
+  );
+
+  // The source translation.
+  $data['node']['translation'] = array(
+    'group' => t('Content translation'),
+    'title' => t('Translations'),
+    'help' => t('Versions of content in different languages.'),
+    'relationship' => array(
+      'title' => t('Translations'),
+      'help' => t('Versions of content in different languages.'),
+      'base' => 'node',
+      'base field' => 'tnid',
+      'relationship table' => 'node',
+      'relationship field' => 'nid',
+      'id' => 'translation',
+      'label' => t('Translations'),
+    ),
+  );
+
+  // The source translation.
+  $data['node']['source_translation'] = array(
+    'group' => t('Content translation'),
+    'title' => t('Source translation'),
+    'help' => t('Content that is either untranslated or is the original version of a translation set.'),
+    'filter' => array(
+      'id' => 'node_tnid',
+    ),
+  );
+
+  // The source translation.
+  $data['node']['child_translation'] = array(
+    'group' => t('Node translation'),
+    'title' => t('Child translation'),
+    'help' => t('Content that is a translation of a source translation.'),
+    'filter' => array(
+      'id' => 'node_tnid_child',
+    ),
+  );
+
+  // Translation status
+  $data['node']['translate'] = array(
+    'group' => t('Content translation'),
+    'title' => t('Translation status'),
+    'help' => t('The translation status of the content - whether or not the translation needs to be updated.'),
+    'field' => array(
+      'id' => 'boolean',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'id' => 'boolean',
+      'label' => t('Outdated'),
+      'type' => 'yes-no',
+    ),
+    'sort' => array(
+      'id' => 'standard',
+    ),
+  );
+
+  // Translate node link.
+  $data['node']['translate_node'] = array(
+    'group' => t('Content translation'),
+    'title' => t('Translate link'),
+    'help' => t('Provide a simple link to translate the node.'),
+    'field' => array(
+      'id' => 'node_link_translate',
+    ),
+  );
+
+}
