diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index d7204a5..b5eb488 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -285,7 +285,7 @@ function content_translation_get_config_key($entity_type, $bundle, $setting) {
  * @param string $setting
  *   The name of the setting.
  *
- * @returns mixed
+ * @return mixed
  *   The stored value for the given setting.
  */
 function content_translation_get_config($entity_type, $bundle, $setting) {
@@ -319,7 +319,7 @@ function content_translation_set_config($entity_type, $bundle, $setting, $value)
  *   (optional) The bundle of the entity. If no bundle is provided, all the
  *   available bundles are checked.
  *
- * @returns
+ * @return bool
  *   TRUE if the specified bundle is translatable. If no bundle is provided
  *   returns TRUE if at least one of the entity bundles is translatable.
  *
@@ -885,3 +885,41 @@ function content_translation_save_settings($settings) {
   entity_info_cache_clear();
   \Drupal::service('router.builder')->setRebuildNeeded();
 }
+
+/**
+ * Returns the localized links for the given path.
+ *
+ * @param string $path
+ *   The path for which language switch links should be provided.
+ *
+ * @return array
+ *   A renderable array of language switch links.
+ */
+function _content_translation_get_switch_links($path) {
+  $links = language_negotiation_get_switch_links(Language::TYPE_CONTENT, $path);
+  if (empty($links)) {
+    // If content language is set up to fall back to the interface language,
+    // then there will be no switch links for Language::TYPE_CONTENT, ergo we
+    // also need to use interface switch links.
+    $links = language_negotiation_get_switch_links(Language::TYPE_INTERFACE, $path);
+  }
+  return $links;
+}
+
+/**
+ * Populates target values with the source values.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity being translated.
+ * @param \Drupal\Core\Language\Language $source
+ *   The language to be used as source.
+ * @param \Drupal\Core\Language\Language $target
+ *   The language to be used as target.
+ */
+function content_translation_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
+  if ($entity instanceof ContentEntityInterface) {
+    $source_translation = $entity->getTranslation($source->id);
+    $entity->addTranslation($target->id, $source_translation->getPropertyValues());
+  }
+}
+
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
deleted file mode 100644
index 4d2fefc..0000000
--- a/core/modules/content_translation/content_translation.pages.inc
+++ /dev/null
@@ -1,234 +0,0 @@
-<?php
-
-/**
- * @file
- * The content translation user interface.
- */
-
-use Drupal\Core\Language\Language;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\ContentEntityInterface;
-
-/**
- * Translations overview page callback.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity whose translation overview should be displayed.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- *   Use \Drupal\content_translation\Controller\ContentTranslationController::overview().
- */
-function content_translation_overview(EntityInterface $entity) {
-  $controller = content_translation_controller($entity->getEntityTypeId());
-  $languages = \Drupal::languageManager()->getLanguages();
-  $original = $entity->getUntranslated()->language()->id;
-  $translations = $entity->getTranslationLanguages();
-  $administrator = \Drupal::currentUser()->hasPermission('administer languages');
-
-  $rel = array();
-  foreach (array('canonical', 'edit-form', 'drupal:content-translation-overview') as $name) {
-    $rel[$name] = $entity->getSystemPath($name);
-  }
-
-  $header = array(t('Language'), t('Translation'), t('Source language'), t('Status'), t('Operations'));
-  $rows = array();
-
-  if (\Drupal::languageManager()->isMultilingual()) {
-
-    // Determine whether the current entity is translatable.
-    $translatable = FALSE;
-    foreach (\Drupal::entityManager()->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle()) as $field_definition) {
-      if ($field_definition->isTranslatable()) {
-        $translatable = TRUE;
-        break;
-      }
-    }
-
-    foreach ($languages as $language) {
-      $language_name = $language->name;
-      $langcode = $language->id;
-
-      $add_path = $rel['drupal:content-translation-overview'] . '/add/' . $original . '/' . $langcode;
-      $translate_path = $rel['drupal:content-translation-overview'] . '/edit/' . $langcode;
-
-      $add_links = _content_translation_get_switch_links($add_path);
-      $edit_links = _content_translation_get_switch_links($rel['edit-form']);
-      $translate_links = _content_translation_get_switch_links($translate_path);
-      $delete_links = _content_translation_get_switch_links($rel['drupal:content-translation-overview'] . '/delete/' . $langcode);
-
-      $operations = array(
-        'data' => array(
-          '#type' => 'operations',
-          '#links' => array(),
-        ),
-      );
-      $links = &$operations['data']['#links'];
-
-      if (isset($translations[$langcode])) {
-        // Existing translation in the translation set: display status.
-        $source = isset($entity->translation[$langcode]['source']) ? $entity->translation[$langcode]['source'] : '';
-        $is_original = $langcode == $original;
-        $label = $entity->getTranslation($langcode)->label();
-        $link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array('href' => $rel['canonical'], 'language' => $language);
-        $row_title = l($label, $link['href'], $link);
-
-        if (empty($link['href'])) {
-          $row_title = $is_original ? $label : t('n/a');
-        }
-
-        // If the user is allowed to edit the entity we point the edit link to
-        // the entity form, otherwise if we are not dealing with the original
-        // language we point the link to the translation form.
-        if ($entity->access('update')) {
-          $links['edit'] = isset($edit_links->links[$langcode]['href']) ? $edit_links->links[$langcode] : array('href' => $rel['edit-form'], 'language' => $language);
-        }
-        elseif (!$is_original && $controller->getTranslationAccess($entity, 'update')) {
-          $links['edit'] = isset($translate_links->links[$langcode]['href']) ? $translate_links->links[$langcode] : array('href' => $translate_path, 'language' => $language);
-        }
-
-        if (isset($links['edit'])) {
-          $links['edit']['title'] = t('Edit');
-        }
-
-        $translation = $entity->translation[$langcode];
-        $status = !empty($translation['status']) ? t('Published') : t('Not published');
-        // @todo Add a theming function here.
-        $status = '<span class="status">' . $status . '</span>' . (!empty($translation['outdated']) ? ' <span class="marker">' . t('outdated') . '</span>' : '');
-
-        if ($is_original) {
-          $language_name = t('<strong>@language_name (Original language)</strong>', array('@language_name' => $language_name));
-          $source_name = t('n/a');
-        }
-        else {
-          $source_name = isset($languages[$source]) ? $languages[$source]->name : t('n/a');
-          if ($controller->getTranslationAccess($entity, 'delete')) {
-            $links['delete'] = isset($delete_links->links[$langcode]['href']) ? $delete_links->links[$langcode] : array('href' => $delete_links, 'language' => $language);
-            $links['delete']['title'] = t('Delete');
-          }
-        }
-      }
-      else {
-        // No such translation in the set yet: help user to create it.
-        $row_title = $source_name = t('n/a');
-        $source = $entity->language()->id;
-
-        if ($source != $langcode && $controller->getTranslationAccess($entity, 'create')) {
-          if ($translatable) {
-            $links['add'] = isset($add_links->links[$langcode]['href']) ? $add_links->links[$langcode] : array('href' => $add_path, 'language' => $language);
-            $links['add']['title'] = t('Add');
-          }
-          elseif ($administrator) {
-            $links['nofields'] = array('title' => t('No translatable fields'), 'route_name' => 'language.content_settings_page', 'language' => $language);
-          }
-        }
-
-        $status = t('Not translated');
-      }
-
-      $rows[] = array($language_name, $row_title, $source_name, $status, $operations);
-    }
-  }
-
-  $build['#title'] = t('Translations of %label', array('%label' => $entity->label()));
-
-  // Add metadata to the build render array to let other modules know about
-  // which entity this is.
-  $build['#entity'] = $entity;
-
-  $build['content_translation_overview'] = array(
-    '#type' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-  );
-
-  return $build;
-}
-
-/**
- * Returns the localized links for the given path.
- *
- * @param string $path
- *   The path for which language switch links should be provided.
- *
- * @returns
- *   A renderable array of language switch links.
- */
-function _content_translation_get_switch_links($path) {
-  $links = \Drupal::languageManager()->getLanguageSwitchLinks(Language::TYPE_CONTENT, $path);
-  if (empty($links)) {
-    // If content language is set up to fall back to the interface language,
-    // then there will be no switch links for Language::TYPE_CONTENT, ergo we
-    // also need to use interface switch links.
-    $links = \Drupal::languageManager()->getLanguageSwitchLinks(Language::TYPE_INTERFACE, $path);
-  }
-  return $links;
-}
-
-/**
- * Page callback for the translation addition page.
- *
- * @param EntityInterface $entity
- *   The entity being translated.
- * @param Language $source
- *   (optional) The language of the values being translated. Defaults to the
- *   entity language.
- * @param Language $target
- *   (optional) The language of the translated values. Defaults to the current
- *   content language.
- *
- * @return array
- *   A processed form array ready to be rendered.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- *   Use \Drupal\content_translation\Controller\ContentTranslationController::add().
- */
-function content_translation_add_page(EntityInterface $entity, Language $source = NULL, Language $target = NULL) {
-  $source = !empty($source) ? $source : $entity->language();
-  $target = !empty($target) ? $target : \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT);
-  // @todo Exploit the upcoming hook_entity_prepare() when available.
-  content_translation_prepare_translation($entity, $source, $target);
-  $form_state['langcode'] = $target->id;
-  $form_state['content_translation']['source'] = $source;
-  $form_state['content_translation']['target'] = $target;
-  $form_state['content_translation']['translation_form'] = !$entity->access('update');
-  return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
-}
-
-/**
- * Page callback for the translation edit page.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity being translated.
- * @param \Drupal\Core\Language\Language $language
- *   (optional) The language of the translated values. Defaults to the current
- *   content language.
- *
- * @return array
- *   A processed form array ready to be rendered.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- *   Use \Drupal\content_translation\Controller\ContentTranslationController::edit().
- */
-function content_translation_edit_page(EntityInterface $entity, Language $language = NULL) {
-  $language = !empty($language) ? $language : \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT);
-  $form_state['langcode'] = $language->id;
-  $form_state['content_translation']['translation_form'] = TRUE;
-  return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
-}
-
-/**
- * Populates target values with the source values.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entitiy being translated.
- * @param \Drupal\Core\Language\Language $source
- *   The language to be used as source.
- * @param \Drupal\Core\Language\Language $target
- *   The language to be used as target.
- */
-function content_translation_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
-  if ($entity instanceof ContentEntityInterface) {
-    $source_translation = $entity->getTranslation($source->id);
-    $entity->addTranslation($target->id, $source_translation->toArray());
-  }
-}
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php b/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
index b9b4904..d85c4a3 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
@@ -53,8 +53,8 @@ public function access(Route $route, Request $request, AccountInterface $account
 
       switch ($operation) {
         case 'create':
-          $source = language_load($request->attributes->get('source'));
-          $target = language_load($request->attributes->get('target'));
+          $source = $request->attributes->get('source');
+          $target = $request->attributes->get('target');
           $source = !empty($source) ? $source : $entity->language();
           $target = !empty($target) ? $target : \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT);
           return ($source->id != $target->id
@@ -66,8 +66,8 @@ public function access(Route $route, Request $request, AccountInterface $account
 
         case 'update':
         case 'delete':
-          $language = language_load($request->attributes->get('language'));
-          $language = !empty($language) ? $language : \Drupal::languageManager()->getCurrentLanguage(Language::TYPE_CONTENT);
+          $language = $request->attributes->get('language');
+          $language = !empty($language) ? $language : language(Language::TYPE_CONTENT);
           return isset($languages[$language->id])
             && $language->id != $entity->getUntranslated()->language()->id
             && isset($translations[$language->id])
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationHandler.php b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationHandler.php
index 76723c2..087ae13 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationHandler.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationHandler.php
@@ -197,8 +197,11 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
         // A new translation is not available in the translation metadata, hence
         // it should count as one more.
         $published = $new_translation;
-        foreach ($entity->translation as $translation) {
-          $published += $translation['status'];
+        // When creating a brand new translation, $entity->translation is not set.
+        if (!($new_translation)) {
+          foreach ($entity->translation as $translation) {
+            $published += $translation['status'];
+          }
         }
         $enabled = $published > 1;
       }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Controller/ContentTranslationController.php b/core/modules/content_translation/lib/Drupal/content_translation/Controller/ContentTranslationController.php
index 31a33d2..3c7d833 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Controller/ContentTranslationController.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Controller/ContentTranslationController.php
@@ -7,41 +7,281 @@
 
 namespace Drupal\content_translation\Controller;
 
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Url;
+use Drupal\field\FieldInfo;
+use Drupal\Core\Language\Language;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Base class for entity translation controllers.
  */
-class ContentTranslationController {
+class ContentTranslationController extends ControllerBase implements ContainerInjectionInterface {
 
   /**
-   * @todo Remove content_translation_overview().
+   * The field info service.
+   *
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
+   * Constructs a ContentTranslationController object.
+   *
+   * @param \Drupal\Field\FieldInfo
+   *   The field info service.
+   */
+  public function __construct(FieldInfo $field_info) {
+    $this->fieldInfo = $field_info;
+  }
+
+  /**
+   * {inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('field.info')
+    );
+  }
+
+  /**
+   * Populates target values with the source values.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entitiy being translated.
+   * @param \Drupal\Core\Language\Language $source
+   *   The language to be used as source.
+   * @param \Drupal\Core\Language\Language $target
+   *   The language to be used as target.
+   */
+  function prepareTranslation(EntityInterface $entity, Language $source, Language $target) {
+    if ($entity instanceof ContentEntityInterface) {
+      $source_translation = $entity->getTranslation($source->id);
+      $entity->addTranslation($target->id, $source_translation->toArray());
+    }
+  }
+
+  /**
+   * Translations overview page builder.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object from which to extract the entity type.
+   *
+   * @return array
+   *   Array of page elements to render.
    */
   public function overview(Request $request) {
-    $entity = $request->attributes->get($request->attributes->get('_entity_type_id'));
-    module_load_include('pages.inc', 'content_translation');
-    return content_translation_overview($entity);
+    $entity_type = $request->attributes->get('_entity_type_id');
+    $entity = $request->attributes->get($entity_type);
+    $account = $this->currentUser();
+    $controller = $this->entityManager()->getController($entity_type, 'translation');
+
+    $languages = language_list();
+    $original = $entity->getUntranslated()->language()->id;
+    $translations = $entity->getTranslationLanguages();
+    $field_ui = $this->moduleHandler()->moduleExists('field_ui') && $account->hasPermission('administer ' . $entity_type . ' fields');
+
+    $path = $entity->getSystemPath();
+    $base_path = $entity->getSystemPath('drupal:content-translation-overview');
+    $edit_path = $entity->getSystemPath('edit-form');
+
+    $header = array(
+      $this->t('Language'),
+      $this->t('Translation'),
+      $this->t('Source language'),
+      $this->t('Status'),
+      $this->t('Operations'),
+    );
+    $rows = array();
+
+    if ($this->languageManager()->isMultilingual()) {
+      // Determine whether the current entity is translatable.
+      $translatable = FALSE;
+      foreach ($this->fieldInfo->getBundleInstances($entity_type, $entity->bundle()) as $instance) {
+        if ($instance->isTranslatable()) {
+          $translatable = TRUE;
+          break;
+        }
+      }
+
+      foreach ($languages as $language) {
+        $language_name = $language->name;
+        $langcode = $language->id;
+        $add_path = $base_path . '/add/' . $original . '/' . $langcode;
+        $translate_path = $base_path . '/edit/' . $langcode;
+        $delete_path = $base_path . '/delete/' . $langcode;
+
+        $operations = array(
+          'data' => array(
+            '#type' => 'operations',
+            '#links' => array(),
+          ),
+        );
+        $links = &$operations['data']['#links'];
+
+        if (array_key_exists($langcode, $translations)) {
+          // Existing translation in the translation set: display status.
+          $source = isset($entity->translation[$langcode]['source']) ? $entity->translation[$langcode]['source'] : '';
+          $is_original = $langcode == $original;
+          $label = $entity->getTranslation($langcode)->label();
+          $link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array(
+            'href' => $path,
+          );
+          $row_title = l($label, $link['href'], $link);
+
+          if (empty($link['href'])) {
+            $row_title = $is_original ? $label : $this->t('n/a');
+          }
+
+          // If the user is allowed to edit the entity we point the edit link to
+          // the entity form, otherwise if we are not dealing with the original
+          // language we point the link to the translation form.
+          if ($edit_path && $entity->access('update')) {
+            $links['edit'] = array (
+              'href' => $edit_path,
+            );
+          }
+          elseif (!$is_original && $controller->getTranslationAccess($entity, 'update')) {
+            $links['edit'] = array (
+              'href' => $translate_path,
+            );
+          }
+
+          if (isset($links['edit'])) {
+            $links['edit']['title'] = $this->t('Edit');
+          }
+          $translation = $entity->translation[$langcode];
+          $status = !empty($translation['status']) ? $this->t('Published') : $this->t('Not published');
+          // @todo Add a theming function here.
+          $status = '<span class="status">' . $status . '</span>' . (!empty($translation['outdated']) ? ' <span class="marker">' . $this->t('outdated') . '</span>' : '');
+
+          if ($is_original) {
+            $language_name = $this->t('<strong>@language_name (Original language)</strong>', array('@language_name' => $language_name));
+            $source_name = $this->t('n/a');
+          }
+          else {
+            $source_name = isset($languages[$source]) ? $languages[$source]->name : $this->t('n/a');
+            if ($controller->getTranslationAccess($entity, 'delete')) {
+              $links['delete'] = array (
+                'title' => $this->t('Delete'),
+                'href' => $delete_path,
+              );
+            }
+          }
+        }
+        else {
+          // No such translation in the set yet: help user to create it.
+          $row_title = $source_name = $this->t('n/a');
+          $source = $entity->language()->id;
+
+          if ($source != $langcode && $controller->getTranslationAccess($entity, 'create')) {
+            if ($translatable) {
+              $links['add'] = array (
+                'title' => $this->t('Add'),
+                'href' => $add_path,
+              );
+            }
+            elseif ($field_ui) {
+              $entity_path = $this->entityManager()->getAdminRouteInfo($entity_type, $entity->bundle());
+
+              // Link directly to the fields tab to make it easier to find the
+              // setting to enable translation on fields.
+              $path = $entity_path . '/fields';
+              $links['nofields'] = array(
+                'title' => $this->t('No translatable fields'),
+                'href' => $path,
+              );
+            }
+          }
+
+          $status = $this->t('Not translated');
+        }
+
+        $rows[] = array(
+          $language_name,
+          $row_title,
+          $source_name,
+          $status,
+          $operations,
+        );
+      }
+    }
+
+    $build['#title'] = $this->t('Translations of %label', array('%label' => $entity->label()));
+
+    // Add metadata to the build render array to let other modules know about
+    // which entity this is.
+    $build['#entity'] = $entity;
+
+    $build['content_translation_overview'] = array(
+      '#theme' => 'table',
+      '#header' => $header,
+      '#rows' => $rows,
+    );
+
+    return $build;
   }
 
   /**
-   * @todo Remove content_translation_add_page().
+   * Translation addition page builder.
+   *
+   * @param \Drupal\language\Plugin\Condition\Language $source
+   *   (optional) The language of the values being translated. Defaults to the
+   *   entity language.
+   * @param \Drupal\language\Plugin\Condition\Language $target
+   *   (optional) The language of the translated values. Defaults to the current
+   *   content language.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object from which to extract the entity type.
+   *
+   * @return array
+   *   A processed form array ready to be rendered.
    */
-  public function add(Request $request, $source, $target) {
-    $entity = $request->attributes->get($request->attributes->get('_entity_type_id'));
-    module_load_include('pages.inc', 'content_translation');
-    $source = language_load($source);
-    $target = language_load($target);
-    return content_translation_add_page($entity, $source, $target);
+  public function add(Language $source, Language $target,  Request $request) {
+    $entity_type_id = $request->attributes->get('_entity_type_id');
+    $entity = $request->attributes->get($entity_type_id);
+
+    $source = !empty($source) ? $source : $entity->language();
+    $target = !empty($target) ? $target : language(Language::TYPE_CONTENT);
+
+    // @todo Exploit the upcoming hook_entity_prepare() when available.
+    $this->prepareTranslation($entity, $source, $target);
+    $info = $entity->getEntityType();
+
+    // @todo: $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default';
+    $operation = 'default';
+    $form_state['langcode'] = $target->id;
+    $form_state['content_translation']['source'] = $source;
+    $form_state['content_translation']['target'] = $target;
+    $form_state['content_translation']['translation_form'] = !$entity->access('update');
+
+    return $this->entityFormBuilder()->getForm($entity, $operation, $form_state);
   }
 
   /**
-   * @todo Remove content_translation_edit_page().
+   * Page callback for the edit translation page.
+   *
+   * @param \Drupal\language\Plugin\Condition\Language $language
+   *   (optional) The language of the translated values. Defaults to the current
+   *   content language.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object from which to extract the entity type.
+   *
+   * @return array
+   *   A processed form array ready to be rendered.
    */
-  public function edit(Request $request, $language) {
-    $entity = $request->attributes->get($request->attributes->get('_entity_type_id'));
-    module_load_include('pages.inc', 'content_translation');
-    $language = language_load($language);
-    return content_translation_edit_page($entity, $language);
+  public function edit(Language $language, Request $request) {
+    $entity_type = $request->attributes->get('_entity_type');
+    $entity = $request->attributes->get($entity_type);
+
+    $info = $entity->entityInfo();
+    $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default';
+    $form_state['langcode'] = $language->id;
+    $form_state['content_translation']['translation_form'] = TRUE;
+    return $this->entityManager()->getForm($entity, $operation, $form_state);
   }
 
 }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
index cab9ac4..c971387 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php
@@ -88,6 +88,12 @@ protected function alterRoutes(RouteCollection $collection, $provider) {
             'entity' => array(
               'type' => 'entity:' . $entity_type_id,
             ),
+            'source' => array(
+              'type' => 'language',
+            ),
+            'target' => array(
+              'type' => 'language',
+            ),
           ),
         )
       );
@@ -111,6 +117,9 @@ protected function alterRoutes(RouteCollection $collection, $provider) {
             'entity' => array(
               'type' => 'entity:' . $entity_type_id,
             ),
+            'language' => array(
+              'type' => 'language',
+            ),
           ),
         )
       );
@@ -133,6 +142,9 @@ protected function alterRoutes(RouteCollection $collection, $provider) {
             'entity' => array(
               'type' => 'entity:' . $entity_type_id,
             ),
+            'language' => array(
+              'type' => 'language',
+            ),
           ),
           '_access_mode' => 'ANY',
         )
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
index 43e5d77..37e2d72 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
@@ -176,7 +176,7 @@ protected function assertWorkflows(UserInterface $user, $expected_status) {
     else {
       $this->drupalGet($edit_translation_path, $options);
     }
-    $this->assertResponse($expected_status['edit_translation'], format_string('The @user_label has the expected translation creation access.', $args));
+    $this->assertResponse($expected_status['edit_translation'], format_string('The @user_label has the expected translation edit access.', $args));
   }
 
   /**
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index 7396d57..be977c0 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -16,3 +16,7 @@ services:
     arguments: ['@config.storage', '@event_dispatcher', '@config.typed']
     tags:
       - { name: config.factory.override, priority: -254 }
+  language_converter:
+    class: Drupal\language\LanguageConverter
+    tags:
+      - { name: paramconverter }
\ No newline at end of file
diff --git a/core/modules/language/lib/Drupal/language/LanguageConverter.php b/core/modules/language/lib/Drupal/language/LanguageConverter.php
new file mode 100644
index 0000000..375cfaf
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageConverter.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\language\LanguageConverter.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\ParamConverter\ParamConverterInterface;
+use Drupal\Core\Language\Language;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Parameter converter for upcasting entity ids to full objects.
+ */
+class LanguageConverter implements ParamConverterInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function convert($value, $definition, $name, array $defaults, Request $request) {
+    if (!empty($value)) {
+      $languages = language_list(Language::STATE_ALL);
+      return isset($languages[$value]) ? $languages[$value] : NULL;
+    }
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies($definition, $name, Route $route) {
+    if (!empty($definition['type']) && $definition['type'] == 'language') {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+}
