diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index d578499..56566e1 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -40,10 +40,6 @@ function template_preprocess_menu_local_task(&$variables) {
     $active = SafeMarkup::format('<span class="visually-hidden">@label</span>', array('@label' => t('(active tab)')));
     $link_text = t('@local-task-title@active', array('@local-task-title' => $link_text, '@active' => $active));
   }
-  else {
-    // @todo Remove this once https://www.drupal.org/node/2338081 is fixed.
-    $link_text = SafeMarkup::checkPlain($link_text);
-  }
 
   $link['localized_options']['set_active_class'] = TRUE;
 
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
index ecef19c..d8a792e 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
@@ -75,16 +75,7 @@ public function getRouteParameters(RouteMatchInterface $route_match) {
    * {@inheritdoc}
    */
   public function getTitle(Request $request = NULL) {
-    // Subclasses may pull in the request or specific attributes as parameters.
-    $options = array();
-    if (!empty($this->pluginDefinition['title_context'])) {
-      $options['context'] = $this->pluginDefinition['title_context'];
-    }
-    $args = array();
-    if (isset($this->pluginDefinition['title_arguments']) && $title_arguments = $this->pluginDefinition['title_arguments']) {
-      $args = (array) $title_arguments;
-    }
-    return $this->t($this->pluginDefinition['title'], $args, $options);
+    return (string) $this->pluginDefinition['title'];
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 86136d0..829c51f 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -125,7 +125,7 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    *   The current user.
    */
   public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
-    $this->discovery = new YamlDiscovery('links.task', $module_handler->getModuleDirectories());
+    $this->discovery = new YamlDiscovery('links.task', $module_handler->getModuleDirectories(), ['title' => ['title_arguments', 'title_context']]);
     $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
     $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\LocalTaskInterface');
     $this->controllerResolver = $controller_resolver;
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/YamlDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/YamlDiscovery.php
index 0b7d10f6..6943bca 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/YamlDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/YamlDiscovery.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 use Drupal\Component\Discovery\YamlDiscovery as ComponentYamlDiscovery;
 use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
+use Drupal\Core\StringTranslation\TranslationWrapper;
 
 /**
  * Allows YAML files to define plugin definitions.
@@ -26,6 +27,11 @@ class YamlDiscovery implements DiscoveryInterface {
   protected $discovery;
 
   /**
+   * @var array
+   */
+  protected $translatableProperties;
+
+  /**
    * Construct a YamlDiscovery object.
    *
    * @param string $name
@@ -33,9 +39,21 @@ class YamlDiscovery implements DiscoveryInterface {
    *   'MODULE.test.yml'.
    * @param array $directories
    *   An array of directories to scan.
+   * @param array $translatable_properties
+   *   An array of properties whose values should be treated. For example, if
+   *   the values for the 'title' and 'description' keys in the YAML need
+   *   translation, and if the corresponding translation arguments and context
+   *   can be found in the 'title_arguments', 'title_context',
+   *   'description_arguments', and 'description_context' keys, then
+   *   $translation_properties should be set to:
+   *   [
+   *     'title' => ['title_arguments', 'title_context'],
+   *     'description' => ['description_arguments', 'description_context'],
+   *   ].
    */
-  function __construct($name, array $directories) {
+  function __construct($name, array $directories, $translatable_properties = array()) {
     $this->discovery = new ComponentYamlDiscovery($name, $directories);
+    $this->translatableProperties = $translatable_properties;
   }
 
   /**
@@ -48,6 +66,24 @@ public function getDefinitions() {
     $definitions = array();
     foreach ($plugins as $provider => $list) {
       foreach ($list as $id => $definition) {
+        // Add translation wrappers.
+        foreach ($this->translatableProperties as $property => $arguments_and_contexts) {
+          if (isset($definition[$property])) {
+            list($arguments_property, $context_property) = $arguments_and_contexts;
+            $arguments = [];
+            $options = [];
+            if (isset($definition[$arguments_property])) {
+              $arguments = $definition[$arguments_property];
+              unset($definition[$arguments_property]);
+            }
+            if (isset($definition[$context_property])) {
+              $options['context'] = $definition[$context_property];
+              unset($definition[$context_property]);
+            }
+            $definition[$property] = new TranslationWrapper($definition[$property], $arguments, $options);
+          }
+        }
+        // Add ID and provider.
         $definitions[$id] = $definition + array(
           'provider' => $provider,
           'id' => $id,
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
index 573444b..d54aac5 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
@@ -10,8 +10,8 @@
 use Drupal\Core\Menu\LocalTaskDefault;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\Core\StringTranslation\TranslationWrapper;
 use Drupal\Tests\UnitTestCase;
-use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -234,11 +234,12 @@ public function testActive() {
   /**
    * @covers ::getTitle
    */
-  public function testGetTitleWithoutContext() {
-    $this->pluginDefinition['title'] = 'Example';
+  public function testGetTitle() {
+    $this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
+      ->setStringTranslation($this->stringTranslation);
     $this->stringTranslation->expects($this->once())
       ->method('translate')
-      ->with($this->pluginDefinition['title'], array(), array())
+      ->with('Example', array(), array())
       ->will($this->returnValue('Example translated'));
 
     $this->setupLocalTaskDefault();
@@ -246,37 +247,6 @@ public function testGetTitleWithoutContext() {
   }
 
   /**
-   * @covers ::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());
-  }
-
-  /**
-   * @covers ::getTitle
-   */
-  public function testGetTitleWithTitleArguments() {
-    $this->pluginDefinition['title'] = 'Example @test';
-    $this->pluginDefinition['title_arguments'] = array('@test' => 'value');
-    $this->stringTranslation->expects($this->once())
-      ->method('translate')
-      ->with($this->pluginDefinition['title'], $this->arrayHasKey('@test'), array())
-      ->will($this->returnValue('Example value'));
-
-    $this->setupLocalTaskDefault();
-    $request = new Request();
-    $this->assertEquals('Example value', $this->localTaskBase->getTitle($request));
-  }
-
-  /**
    * @covers ::getOptions
    */
   public function testGetOptions() {
