diff --git a/entity_translation.info b/entity_translation.info
index 2a92c44..123b384 100644
--- a/entity_translation.info
+++ b/entity_translation.info
@@ -7,3 +7,9 @@ dependencies[] = locale
 files[] = includes/translation.handler.inc
 files[] = includes/translation.handler.node.inc
 files[] = tests/entity_translation.test
+files[] = views/entity_translation_handler_relationship.inc
+files[] = views/entity_translation_handler_field_translate_link.inc
+files[] = views/entity_translation_handler_field_label.inc
+files[] = views/entity_translation_handler_filter_entity_type.inc
+files[] = views/entity_translation_handler_filter_language.inc
+files[] = views/entity_translation_handler_filter_translation_exists.inc
diff --git a/entity_translation.module b/entity_translation.module
index 3f23a23..22b2ce6 100644
--- a/entity_translation.module
+++ b/entity_translation.module
@@ -102,6 +102,16 @@ function entity_translation_entity_info_alter(&$entity_info) {
 }
 
 /**
+ * Implements hook_views_api().
+ */
+function entity_translation_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'entity_translation') . '/views',
+  );
+}
+
+/**
  * Helper function to determine if the given entity type is translatable.
  */
 function entity_translation_enabled($entity_type, $skip_handler = FALSE) {
diff --git a/views/entity_translation.views.inc b/views/entity_translation.views.inc
new file mode 100644
index 0000000..3353c1d
--- /dev/null
+++ b/views/entity_translation.views.inc
@@ -0,0 +1,227 @@
+<?php
+/**
+ * @file
+ *
+ * Provide views data and handlers for entity_translation.
+ */
+
+/**
+ * Implements hook_views_data().
+ */
+function entity_translation_views_data() {
+  $data = array();
+  $data['entity_translation']['table']['group'] = t('Entity translation');
+  // Advertise this table as a possible base table.
+  $data['entity_translation']['table']['base'] = array(
+    'field' => 'entity_id',
+    'title' => t('Entity translation'),
+    'help' => t('Information about a translation of an entity.'),
+  );
+  $data['entity_translation']['entity_id'] = array(
+    'title' => t('Entity id'),
+    'help' => t('The entity id.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+      'validate type' => 'entity_id',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['entity_type'] = array(
+    'title' => t('Entity type'),
+    'help' => t('The entity type.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+      'numeric' => FALSE,
+      'validate type' => 'entity_type',
+    ),
+    'filter' => array(
+      'handler' => 'entity_translation_handler_filter_entity_type',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['language'] = array(
+    'title' => t('Language'),
+    'help' => t('The language of this translation.'),
+    'field' => array(
+      'handler' => 'views_handler_field_locale_language',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_locale_language',
+      'numeric' => FALSE,
+      'validate type' => 'language',
+    ),
+    'filter' => array(
+      'handler' => 'entity_translation_handler_filter_language',
+      'allow empty' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['source'] = array(
+    'title' => t('Source'),
+    'help' => t('The source language.'),
+    'field' => array(
+      'handler' => 'views_handler_field_locale_language',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_locale_language',
+      'name field' => 'title',
+      'numeric' => FALSE,
+      'validate type' => 'string',
+    ),
+    'filter' => array(
+      'handler' => 'entity_translation_handler_filter_language',
+      'allow empty' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['status'] = array(
+    'title' => t('Translation status'),
+    'help' => t('The status of this translation.'),
+    'field' => array(
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+      'validate type' => 'boolean',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['translate'] = array(
+    'title' => t('Needs update'),
+    'help' => t('Indicates if the translation needs to be updated.'),
+    'field' => array(
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'name field' => 'title',
+      'numeric' => TRUE,
+      'validate type' => 'boolean',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['entity_translation']['created'] = array(
+    'title' => t('Created'),
+    'help' => t('Created date.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_date',
+      'numeric' => FALSE,
+      'validate type' => 'date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+  );
+  $data['entity_translation']['changed'] = array(
+    'title' => t('Changed'),
+    'help' => t('Changed date.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_date',
+      'numeric' => FALSE,
+      'validate type' => 'date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+  );
+  $data['entity_translation']['translate_link'] = array(
+    'title' => t('Translate link'),
+    'help' => t('Link to translation overview page.'),
+    'field' => array(
+      'handler' => 'entity_translation_handler_field_translate_link',
+    ),
+  );
+  $data['entity_translation']['translation_exists'] = array(
+    'title' => t('Translation exists'),
+    'help' => t('Link to translation overview page.'),
+    'filter' => array(
+      'handler' => 'entity_translation_handler_filter_translation_exists',
+    ),
+  );
+  $data['entity_translation']['label'] = array(
+    'title' => t('Label'),
+    'help' => t('The label of the entity.'),
+    'field' => array(
+      'handler' => 'entity_translation_handler_field_label',
+    ),
+  );
+  return $data;
+}
+
+/**
+ * Implements hook_views_data_alter().
+ *
+ * Add entity translation information to the various entity tables.
+ */
+function entity_translation_views_data_alter(&$data) {
+  foreach (entity_get_info() as $type =>  $info) {
+    if ($info['fieldable'] && isset($data[$info['base table']])) {
+      $table = &$data[$info['base table']];
+      $table['entity_translations'] = array(
+        'title' => t('Entity translation: translations'),
+        'help' => t('Translation information.'),
+        'relationship' => array(
+          'label' => t('Translations'),
+          'base' => 'entity_translation',
+          'base field' => 'entity_id',
+          'relationship field' => $info['entity keys']['id'],
+          'handler' => 'entity_translation_handler_relationship',
+          // We add our information here in the definition, so we can copy it
+          // later.
+          'left_table' => $info['base table'],
+          'left_field' => $info['entity keys']['id'],
+          'entity type' => $type,
+        ),
+      );
+    }
+  }
+}
diff --git a/views/entity_translation_handler_field_label.inc b/views/entity_translation_handler_field_label.inc
new file mode 100644
index 0000000..dd972d3
--- /dev/null
+++ b/views/entity_translation_handler_field_label.inc
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @file
+ * This file contains a label field handler for entity translation.
+ */
+
+/**
+ * This handler shows the entity label for entities in the entity_translation table.
+ */
+class entity_translation_handler_field_label extends views_handler_field {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['entity_id'] = 'entity_id';
+    $this->additional_fields['entity_type'] = 'entity_type';
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+  /**
+   * Add a 'link to entity' option definition.
+   * @see views_handler_field::option:definition()
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_to_entity'] = array('default' => '', 'translatable' => FALSE);
+    return $options;
+  }
+
+  /**
+   * Add a 'link to entity' option.
+   * @see views_handler_field::options_form()
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link_to_entity'] = array(
+      '#title' => t('Link this field to it\'s entity'),
+      '#type' => 'checkbox',
+      '#default_value' => $this->options['link_to_entity']
+    );
+  }
+
+  /**
+   * Load all entities, so that we can get the label.
+   */
+  function post_execute(&$values) {
+    $ids = array();
+    $ids_by_type = array();
+    foreach ($values as $row) {
+      $ids_by_type[$this->get_value($row, 'entity_type')][] = $this->get_value($row, 'entity_id');
+    }
+    foreach ($ids_by_type as $type => $ids) {
+      $this->entities[$type] = entity_load($type, $ids);
+    }
+  }
+
+  function render($values) {
+    $entity_type = $this->get_value($values, 'entity_type');
+    $entity_id = $this->get_value($values, 'entity_id');
+    $entity = $this->entities[$entity_type][$entity_id];
+    // We could also use entity_label(), but since this we might want to let
+    // the handler decide what's best to show.
+    $handler = entity_translation_get_handler($entity_type, $entity);
+    $label = $handler->getLabel();
+    if ($this->options['link_to_entity']) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = $handler->getViewPath();
+    }
+    return $label;
+  }
+}
diff --git a/views/entity_translation_handler_field_translate_link.inc b/views/entity_translation_handler_field_translate_link.inc
new file mode 100644
index 0000000..bc8d8b9
--- /dev/null
+++ b/views/entity_translation_handler_field_translate_link.inc
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @file
+ * Translate link plugin.
+ */
+
+/**
+ * This handler adds translate link for all translatable entities.
+ */
+class entity_translation_handler_field_translate_link extends views_handler_field {
+
+  function construct() {
+    parent::construct();
+    $this->additional_fields['entity_id'] = 'entity_id';
+    $this->additional_fields['entity_type'] = 'entity_type';
+    $this->additional_fields['language'] = 'language';
+  }
+
+  /**
+   * Add required additional fields.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  /**
+   * Add the text option.
+   * @see views_handler_field::option_definition()
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+    return $options;
+  }
+
+  /**
+   * Add the option to set the title of the translate link.
+   * @see views_handler_field::options_form()
+   */
+  function options_form(&$form, &$form_state) {
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+    parent::options_form($form, $form_state);
+
+    // The path is set by render_link function so don't allow setting it.
+    $form['alter']['path'] = array('#access' => FALSE);
+    $form['alter']['external'] = array('#access' => FALSE);
+  }
+
+  /**
+   * Load all entities based on the data we have.
+   */
+  function post_execute(&$values) {
+    $ids = array();
+    $ids_by_type = array();
+    foreach ($values as $row) {
+      $ids_by_type[$this->get_value($row, 'entity_type')][] = $this->get_value($row, 'entity_id');
+    }
+    foreach ($ids_by_type as $type => $ids) {
+      $this->entities[$type] = entity_load($type, $ids);
+    }
+  }
+
+  /**
+   * @see views_handler_field::render()
+   */
+  function render($values) {
+    $type = $this->get_value($values, 'entity_type');
+    $entity_id = $this->get_value($values, 'entity_id');
+    $language = $this->get_value($values, 'language');
+    $entity = $this->entities[$type][$entity_id];
+    return $this->render_link($type, $entity_id, $language);
+  }
+
+  /**
+   * Render the link to the translation overview page of the entity.
+   */
+  function render_link($entity_type, $entity_id, $language) {
+    if (!entity_translation_enabled($entity_type) || !entity_translation_tab_access($entity_type) || $language == 'und') {
+      return;
+    }
+    // We use the entity info here to avoid having to call entity_load() for all
+    // the entities.
+    $info = entity_get_info($entity_type);
+    $path = $info['translation']['entity_translation']['base path'];
+    $path = str_replace($info['translation']['entity_translation']['path wildcard'], $entity_id, $path);
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = $path . '/translate';
+    $this->options['alter']['query'] = drupal_get_destination();
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('translate');
+    return $text;
+  }
+}
diff --git a/views/entity_translation_handler_filter_entity_type.inc b/views/entity_translation_handler_filter_entity_type.inc
new file mode 100644
index 0000000..0eb76e2
--- /dev/null
+++ b/views/entity_translation_handler_filter_entity_type.inc
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Contains an entity type filter handler.
+ */
+
+/**
+ * This handler shows all available entity types that are enabled for entity
+ * translation as options.
+ */
+class entity_translation_handler_filter_entity_type extends views_handler_filter_in_operator {
+
+  /**
+   * Show all entity types that are enabled for entity translation as options.
+   */
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $this->value_title = t('Entity type');
+      $allowed_types_options = variable_get('entity_translation_entity_types');
+      $allowed_types = array();
+      $entity_info = entity_get_info();
+      foreach ($allowed_types_options as $key => $allowed) {
+        if ($allowed) {
+          $allowed_types[$key] = $entity_info[$key]['label'];
+        }
+      }
+      $this->value_options = $allowed_types;
+    }
+  }
+}
diff --git a/views/entity_translation_handler_filter_language.inc b/views/entity_translation_handler_filter_language.inc
new file mode 100644
index 0000000..93cca9e
--- /dev/null
+++ b/views/entity_translation_handler_filter_language.inc
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ * Contains a language filter handler.
+ */
+
+/**
+ * Extends the locale language filter in order for it to work with the entity
+ * translation table structure.
+ */
+class entity_translation_handler_filter_language extends views_handler_filter_locale_language {
+
+  /**
+   * Override the default behaviour, insert an empty string instead of NULL.
+   */
+  function op_empty() {
+    $this->ensure_my_table();
+    if ($this->operator == 'empty') {
+      $operator = "=";
+    }
+    else {
+      $operator = "<>";
+    }
+
+    $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", '', $operator);
+  }
+}
diff --git a/views/entity_translation_handler_filter_translation_exists.inc b/views/entity_translation_handler_filter_translation_exists.inc
new file mode 100644
index 0000000..141008c
--- /dev/null
+++ b/views/entity_translation_handler_filter_translation_exists.inc
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @file
+ * Contains an entity type filter handler.
+ */
+
+/**
+ * This handler determines if a translation exists for a particular translation.
+ */
+class entity_translation_handler_filter_translation_exists extends views_handler_filter_locale_language {
+
+  /**
+   * Add a 'entity_type' option definition.
+   * @see views_handler_field::option:definition()
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['entity_type'] = array('default' => '', 'translatable' => FALSE);
+    $options['use_filter'] = array('default' => '', 'translatable' => FALSE);
+    $options['filter'] = array('default' => '', 'translatable' => FALSE);
+    return $options;
+  }
+
+  /**
+   * Override the default title for the operators.
+   */
+  function operators() {
+    $operators = parent::operators();
+    $operators['in']['title'] = t('Translation exists');
+    $operators['not in']['title'] = t('Translation doesn\'t exist');
+    return $operators;
+  }
+
+  /**
+   * Add option for setting entity type either directly or through a filter.
+   * @see views_handler_field::options_form()
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $filters = $this->get_entity_type_filters();
+    if (!empty($filters)) {
+      $form['use_filter'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Use an entity type filter.'),
+        '#default_value' => $this->options['use_filter'],
+      );
+      $form['filter'] = array(
+        '#type' => 'select',
+        '#title' => t('Filter'),
+        '#options' => $filters,
+        '#dependency' => array(
+          'edit-options-use-filter' => array(1)
+        ),
+        '#default_value' => $this->options['filter'],
+      );
+    }
+    $form['entity_type'] = array(
+      '#title' => t('Entity type'),
+      '#type' => 'select',
+      '#options' => $this->get_allowed_types(),
+      '#dependency' => array(
+        'edit-options-use-filter' => array(0)
+      ),
+      '#default_value' => $this->options['entity_type'],
+      '#description' => t('You have to filter on a particular entity type when you use this filter'),
+    );
+  }
+
+  /**
+   * Get all available entity type filters that can be used to build the query.
+   */
+  function get_entity_type_filters() {
+    // We need to build the query to know about the available fields.
+    $this->view->build();
+    $filters = array();
+     foreach ($this->view->filter as $key => $filter) {
+       // Break if we encounter our filter, the filter must be before this one.
+       if ($filter == $this) {
+         break;
+       }
+       if ($filter instanceof entity_translation_handler_filter_entity_type && count($filter->value) == 1 && empty($filter->options['expose']['multiple'])) {
+        $filters[$key] = $filter->value_title;
+      }
+    }
+    return $filters;
+  }
+
+  /**
+   * Get entity types managed by entity translation.
+   */
+  function get_allowed_types() {
+    $allowed_types_options = variable_get('entity_translation_entity_types');
+    $allowed_types = array();
+    $entity_info = entity_get_info();
+    foreach ($allowed_types_options as $key => $allowed) {
+      if ($allowed) {
+        $allowed_types[$key] = $entity_info[$key]['label'];
+      }
+    }
+    return $allowed_types;
+  }
+
+  /**
+   * Override the default behaviour of the handler.
+   */
+  function query() {
+    $this->ensure_my_table();
+    // We need a subquery to determine not in.
+    if ($this->operator == 'not in') {
+      $entity_type = 'node';
+      if ($this->options['use_filter'] && isset($this->view->filter[$this->options['filter']])) {
+        $filter = $this->view->filter[$this->options['filter']];
+        $entity_type = current($filter->value);
+      }
+      else {
+        $this->query->add_where($this->options['group'], "$this->table_alias.entity_type", $this->options['entity_type'], '=');
+        $entity_type = $this->options['entity_type'];
+      }
+      $query = db_select('entity_translation', 'es')
+        ->condition('entity_type', $entity_type)
+        ->condition('language', $this->value);
+      $query->addField('es', 'entity_id');
+      $this->query->add_where($this->options['group'], "$this->table_alias.entity_id", $query, $this->operator);
+    }
+    // We can determine if a translation exists without a subquery.
+    else {
+      $value = array_keys($this->value);
+      $this->query->add_where($this->options['group'], "$this->table_alias.source", '', '<>');
+      $this->query->add_where($this->options['group'], "$this->table_alias.language", array_values($this->value), $this->operator);
+    }
+  }
+}
diff --git a/views/entity_translation_handler_relationship.inc b/views/entity_translation_handler_relationship.inc
new file mode 100644
index 0000000..733c858
--- /dev/null
+++ b/views/entity_translation_handler_relationship.inc
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @file
+ * Contains the relationship plugin for relating entities to translation metadata.
+ */
+
+/**
+ * Add a relationship to the entity translation table.
+ */
+class entity_translation_handler_relationship extends views_handler_relationship {
+
+  /**
+   * Add a relationship to the entity_translation table.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $def = $this->definition;
+    $def['table'] = 'entity_translation';
+    $def['field'] = 'entity_id';
+    $def['type'] = empty($this->options['required']) ? 'LEFT' : 'INNER';
+    $join = new views_join();
+    $join->definition = $def;
+    $join->construct();
+    $join->adjusted = TRUE;
+    // Use a short alias for the table.
+    $alias = $def['table'] . '_' . $this->table;
+    // We need to add a condition on entity type to the join to avoid getting
+    // relationships to entities with other types.
+    $join->extra = "$alias.entity_type = '{$def['entity type']}'";
+    $this->alias = $this->query->add_relationship($alias, $join, 'entity_translation', $this->relationship);
+  }
+}
