diff --git a/core/lib/Drupal/Core/Controller/TitleResolver.php b/core/lib/Drupal/Core/Controller/TitleResolver.php
index 17b7a2eed7f696b3a7f15362f8ea99ab400dfa8e..359af1d9d46f7180ecb283024f8b0b57652f55cb 100644
--- a/core/lib/Drupal/Core/Controller/TitleResolver.php
+++ b/core/lib/Drupal/Core/Controller/TitleResolver.php
@@ -57,8 +57,12 @@ public function getTitle(Request $request, Route $route) {
       $route_title = call_user_func_array($callable, $arguments);
     }
     elseif ($title = $route->getDefault('_title')) {
+      $options = array();
+      if ($context = $route->getDefault('_title_context')) {
+        $options['context'] = $context;
+      }
       // Fall back to a static string from the route.
-      $route_title = $this->translationManager->translate($title);
+      $route_title = $this->translationManager->translate($title, array(), $options);
     }
     return $route_title;
   }
diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
index 7e4318d50b17bea8e08f1894e59eb4261926c825..d85ddede19d988d2d4e17159aae677b03bb569f2 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
@@ -27,6 +27,11 @@
  */
 class ViewSubscriber implements EventSubscriberInterface {
 
+  /**
+   * The content negotiation.
+   *
+   * @var \Drupal\Core\ContentNegotiation
+   */
   protected $negotiation;
 
   /**
@@ -91,8 +96,8 @@ public function onView(GetResponseForControllerResultEvent $event) {
       }
 
       // If no title was returned fall back to one defined in the route.
-      if (!isset($page_result['#title']) && $request->attributes->has('_title')) {
-        $page_result['#title'] = $request->attributes->get('_title');
+      if (!isset($page_result['#title'])) {
+        $page_result['#title'] = $this->titleResolver->getTitle($request, $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
       }
 
       $event->setResponse(new Response(drupal_render_page($page_result)));
@@ -109,8 +114,8 @@ public function onView(GetResponseForControllerResultEvent $event) {
       }
 
       // If no title was returned fall back to one defined in the route.
-      if (!isset($page_result['#title']) && $request->attributes->has('_title')) {
-        $page_result['#title'] = $request->attributes->get('_title');
+      if (!isset($page_result['#title'])) {
+        $page_result['#title'] = $this->titleResolver->getTitle($request, $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
       }
 
       $event->setResponse(new Response(drupal_render($page_result)));
diff --git a/core/lib/Drupal/Core/Menu/LocalActionDefault.php b/core/lib/Drupal/Core/Menu/LocalActionDefault.php
index be6e6abf1ee86ebe54f8d2b3692d96081500e1ce..1661ac9507461676277d80b77a2777bb856f8012 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionDefault.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionDefault.php
@@ -67,7 +67,11 @@ public function getRouteName() {
    */
   public function getTitle() {
     // Subclasses may pull in the request or specific attributes as parameters.
-    return $this->t($this->pluginDefinition['title']);
+    $options = array();
+    if (!empty($this->pluginDefinition['title_context'])) {
+      $options['context'] = $this->pluginDefinition['title_context'];
+    }
+    return $this->t($this->pluginDefinition['title'], array(), $options);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
index 058de09819214f56bd24734e21af712211dcc209..ef8d0232e9689c223cb7084f9e31284f16bdd5ba 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
@@ -75,7 +75,11 @@ public function getRouteParameters(Request $request) {
    */
   public function getTitle() {
     // Subclasses may pull in the request or specific attributes as parameters.
-    return $this->t($this->pluginDefinition['title']);
+    $options = array();
+    if (!empty($this->pluginDefinition['title_context'])) {
+      $options['context'] = $this->pluginDefinition['title_context'];
+    }
+    return $this->t($this->pluginDefinition['title'], array(), $options);
   }
 
   /**
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index b52ec6deaa9daec721bfcf58ca5a43c2a87058ad..fed1b60ed87ccf72a6f68db795f10304f2799914 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -115,6 +115,9 @@ public function form(array $form, array &$form_state) {
           '%title' => $comment->subject->value,
         ));
       }
+      else {
+        $form['#title'] = $this->t('Preview comment');
+      }
     }
     else {
       if ($this->currentUser->isAuthenticated()) {
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 69374b182b742c3e7240fd031fe8d99c27fe45ea..4281cb4e4d64be0eb9fe8b4b2cfddb4c925b836c 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -239,6 +239,8 @@ system.date_format_localize_reset:
 system.modules_list:
   path: '/admin/modules'
   defaults:
+    _title: 'Extend'
+    _title_context: 'With components'
     _form: 'Drupal\system\Form\ModulesListForm'
   requirements:
     _permission: 'administer modules'
diff --git a/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php b/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..085ef60c6c2261f73a1b676be8b291c97c92d652
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Controller\TitleResolverTest.
+ */
+
+namespace Drupal\Tests\Core\Controller;
+
+use Drupal\Component\Utility\String;
+use Drupal\Core\Controller\TitleResolver;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Tests the title resolver.
+ *
+ * @see \Drupal\Core\Controller\TitleResolver
+ */
+class TitleResolverTest extends UnitTestCase {
+
+  /**
+   * The mocked controller resolver.
+   *
+   * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $controllerResolver;
+
+  /**
+   * The mocked translation manager.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $translationManager;
+
+  /**
+   * The actual tested title resolver.
+   *
+   * @var \Drupal\Core\Controller\TitleResolver
+   */
+  protected $titleResolver;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Title resolver',
+      'description' => 'Tests the title resolver.',
+      'group' => 'Routing',
+    );
+  }
+
+  protected function setUp() {
+    $this->controllerResolver = $this->getMock('\Drupal\Core\Controller\ControllerResolverInterface');
+    $this->translationManager = $this->getMock('\Drupal\Core\StringTranslation\TranslationInterface');
+
+    $this->titleResolver = new TitleResolver($this->controllerResolver, $this->translationManager);
+  }
+
+  /**
+   * Tests a static title without a context.
+   *
+   * @see \Drupal\Core\Controller\TitleResolver::getTitle()
+   */
+  public function testStaticTitle() {
+    $request = new Request();
+    $route = new Route('/test-route', array('_title' => 'static title'));
+
+    $this->translationManager->expects($this->once())
+      ->method('translate')
+      ->with('static title', array(), array())
+      ->will($this->returnValue('translated title'));
+
+    $this->assertEquals('translated title', $this->titleResolver->getTitle($request, $route));
+  }
+
+  /**
+   * Tests a static title with a context.
+   *
+   * @see \Drupal\Core\Controller\TitleResolver::getTitle()
+   */
+  public function testStaticTitleWithContext() {
+    $request = new Request();
+    $route = new Route('/test-route', array('_title' => 'static title', '_title_context' => 'context'));
+
+    $this->translationManager->expects($this->once())
+      ->method('translate')
+      ->with('static title', array(), array('context' => 'context'))
+      ->will($this->returnValue('translated title with context'));
+
+    $this->assertEquals('translated title with context', $this->titleResolver->getTitle($request, $route));
+  }
+
+  /**
+   * Tests a dynamic title.
+   *
+   * @see \Drupal\Core\Controller\TitleResolver::getTitle()
+   */
+  public function testDynamicTitle() {
+    $request = new Request();
+    $route = new Route('/test-route', array('_title' => 'static title', '_title_callback' => 'Drupal\Tests\Core\Controller\TitleCallback::example'));
+
+    $callable = array(new TitleCallback(), 'example');
+    $this->controllerResolver->expects($this->once())
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\Tests\Core\Controller\TitleCallback::example')
+      ->will($this->returnValue($callable));
+    $this->controllerResolver->expects($this->once())
+      ->method('getArguments')
+      ->with($request, $callable)
+      ->will($this->returnValue(array('example')));
+
+    $this->assertEquals('test example', $this->titleResolver->getTitle($request, $route));
+  }
+
+}
+
+/**
+ * Provides an example title callback for the testDynamicTitle method above.
+ */
+class TitleCallback {
+
+  /**
+   * Gets the example string.
+   *
+   * @param string $value
+   *   The dynamic value.
+   *
+   * @return string
+   *   Returns the example string.
+   */
+  public function example($value) {
+    return String::format('test @value', array('@value' => $value));
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6039e83baca032ee252b0697886bf1d1ab249613
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Menu\LocalActionDefaultTest.
+ */
+
+namespace Drupal\Tests\Core\Menu;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Menu\LocalActionDefault;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the local action default class.
+ *
+ * @see \Drupal\Core\Menu\LocalActionDefault
+ */
+class LocalActionDefaultTest extends UnitTestCase {
+
+  /**
+   * The tested local action default plugin.
+   *
+   * @var \Drupal\Core\Menu\LocalActionDefault
+   */
+  protected $localActionDefault;
+
+  /**
+   * The used plugin configuration.
+   *
+   * @var array
+   */
+  protected $config = array();
+
+  /**
+   * The used plugin ID.
+   *
+   * @var string
+   */
+  protected $pluginId = 'local_action_default';
+
+  /**
+   * The used plugin definition.
+   *
+   * @var array
+   */
+  protected $pluginDefinition = array(
+    'id' => 'local_action_default',
+  );
+
+  /**
+   * The mocked translator.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $stringTranslation;
+
+  /**
+   * The mocked route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeProvider;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Local actions default plugin.',
+      'description' => 'Tests the local action default class.',
+      'group' => 'Menu',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->stringTranslation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
+    $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+  }
+
+  /**
+   * Setups the local action default.
+   */
+  protected function setupLocalActionDefault() {
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->stringTranslation);
+    \Drupal::setContainer($container);
+
+    $this->localActionDefault = new LocalActionDefault($this->config, $this->pluginId, $this->pluginDefinition, $this->routeProvider);
+  }
+
+  /**
+   * Tests the getTitle method without a translation context.
+   *
+   * @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
+   */
+  public function testGetTitle() {
+    $this->pluginDefinition['title'] = 'Example';
+    $this->stringTranslation->expects($this->once())
+      ->method('translate')
+      ->with($this->pluginDefinition['title'], array(), array())
+      ->will($this->returnValue('Example translated'));
+
+    $this->setupLocalActionDefault();
+    $this->assertEquals('Example translated', $this->localActionDefault->getTitle());
+  }
+
+  /**
+   * Tests the getTitle method with a translation context.
+   *
+   * @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
+   */
+  public function testGetTitleWithContext() {
+    $this->pluginDefinition['title'] = 'Example';
+    $this->pluginDefinition['title_context'] = 'context';
+    $this->stringTranslation->expects($this->once())
+      ->method('translate')
+      ->with($this->pluginDefinition['title'], array(), array('context' => 'context'))
+      ->will($this->returnValue('Example translated with context'));
+
+    $this->setupLocalActionDefault();
+    $this->assertEquals('Example translated with context', $this->localActionDefault->getTitle());
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
index 8cf9e962e8057048cc005cc2a34225bda2117d97..e708c6a9c727e69a3b24b90093761f0fa225ab34 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
@@ -253,20 +253,38 @@ public function testActive() {
   }
 
   /**
-   * Tests the getTitle method.
+   * Tests the getTitle method without a translation context.
    *
    * @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
    */
   public function testGetTitle() {
     $this->pluginDefinition['title'] = 'Example';
     $this->stringTranslation->expects($this->once())
-      ->method('translate', $this->pluginDefinition['title'])
+      ->method('translate')
+      ->with($this->pluginDefinition['title'], array(), array())
       ->will($this->returnValue('Example translated'));
 
     $this->setupLocalTaskDefault();
     $this->assertEquals('Example translated', $this->localTaskBase->getTitle());
   }
 
+  /**
+   * Tests the getTitle method with a translation context.
+   *
+   * @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
+   */
+  public function testGetTitleWithContext() {
+    $this->pluginDefinition['title'] = 'Example';
+    $this->pluginDefinition['title_context'] = 'context';
+    $this->stringTranslation->expects($this->once())
+      ->method('translate')
+      ->with($this->pluginDefinition['title'], array(), array('context' => 'context'))
+      ->will($this->returnValue('Example translated with context'));
+
+    $this->setupLocalTaskDefault();
+    $this->assertEquals('Example translated with context', $this->localTaskBase->getTitle());
+  }
+
   /**
    * Tests the getOption method.
    *