diff --git a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
index 09f1e0e..02611b0 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Core\Cache\CacheBackendInterface;
 
 /**
  * Enables static and persistent caching of discovered plugin definitions.
@@ -30,6 +31,20 @@ class CacheDecorator implements CachedDiscoveryInterface {
   protected $cacheBin;
 
   /**
+   * The timestamp indicating when the definition list cache expires.
+   *
+   * @var int
+   */
+  protected $cacheExpire;
+
+  /**
+   * The cache tags associated with the definition list.
+   *
+   * @var array
+   */
+  protected $cacheTags;
+
+  /**
    * The plugin definitions of the decorated discovery class.
    *
    * @var array
@@ -54,11 +69,18 @@ class CacheDecorator implements CachedDiscoveryInterface {
    *   The cache identifier used for storage of the definition list.
    * @param string $cache_bin
    *   The cache bin used for storage and retrieval of the definition list.
+   * @param int $cache_expire
+   *   A Unix timestamp indicating that the definition list will be considered
+   *   invalid after this time.
+   * @param array $cache_tags
+   *   The cache tags associated with the definition list
    */
-  public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bin = 'cache') {
+  public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bin = 'cache', $cache_expire = CacheBackendInterface::CACHE_PERMANENT, array $cache_tags = array()) {
     $this->decorated = $decorated;
     $this->cacheKey = $cache_key;
     $this->cacheBin = $cache_bin;
+    $this->cacheExpire = $cache_expire;
+    $this->cacheTags = $cache_tags;
   }
 
   /**
@@ -124,7 +146,7 @@ protected function getCachedDefinitions() {
    */
   protected function setCachedDefinitions($definitions) {
     if (isset($this->cacheKey)) {
-      cache($this->cacheBin)->set($this->cacheKey, $definitions);
+      cache($this->cacheBin)->set($this->cacheKey, $definitions, $this->cacheExpire, $this->cacheTags);
     }
     $this->definitions = $definitions;
   }
@@ -145,4 +167,5 @@ public function clearCachedDefinitions() {
   public function __call($method, $args) {
     return call_user_func_array(array($this->decorated, $method), $args);
   }
+
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php
index f2fd0f7..fa63c23 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherManager.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\CacheDecorator;
 
 /**
  * Manages aggregator fetcher plugins.
@@ -18,6 +19,7 @@ class FetcherManager extends PluginManagerBase {
 
   public function __construct() {
     $this->discovery = new AnnotatedClassDiscovery('aggregator', 'fetcher');
+    $this->discovery = new CacheDecorator($this->discovery, 'aggregator_fetcher:' . language(LANGUAGE_TYPE_INTERFACE)->langcode);
     $this->factory = new DefaultFactory($this->discovery);
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php
new file mode 100644
index 0000000..697e170
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorLanguageTest.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Plugin\CacheDecoratorLanguageTest.
+ */
+
+namespace Drupal\system\Tests\Plugin;
+
+use Exception;
+use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests that the AlterDecorator fires and respects the alter hook.
+ */
+class CacheDecoratorLanguageTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('plugin_test', 'locale', 'language');
+
+  /**
+   * Stores a plugin manager which uses the AlterDecorator.
+   *
+   * @var Drupal\plugin_test\Plugin\AlterDecoratorTestPluginManager;
+   */
+  protected $alterTestPluginManager;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'CacheDecoratorLanguage',
+      'description' => 'Tests that the CacheDecorator stores definitions by language appropriately.',
+      'group' => 'Plugin API',
+    );
+  }
+
+  public function setUp() {
+    // Manually setup German as an additional language.
+    parent::setUp();
+    $this->languages = array('de');
+    require_once DRUPAL_ROOT .'/core/includes/language.inc';
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
+    $this->drupalLogin($admin_user);
+    $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'de'), t('Add language'));
+    // Add a default locale storage for all these tests.
+    $this->storage = locale_storage();
+
+    // Populate sample definitions.
+    $this->mockBlockExpectedDefinitions = array(
+      'user_login' => array(
+        'label' => 'User login',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserLoginBlock',
+      ),
+      'menu:main_menu' => array(
+        'label' => 'Main menu',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
+      ),
+      'menu:navigation' => array(
+        'label' => 'Navigation',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
+      ),
+      'layout' => array(
+        'label' => 'Layout',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock',
+      ),
+      'layout:foo' => array(
+        'label' => 'Layout Foo',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock',
+      ),
+    );
+  }
+
+  /**
+   * Check the translations of the cached plugin definitions.
+   */
+  public function testCacheDecoratorLanguage() {
+    $languages = $this->languages;
+    // Visit our destination first to prime any relevant strings.
+    $this->drupalGet('plugin_definition_test');
+    // Check for the expected block labels on the page.
+    foreach ($this->mockBlockExpectedDefinitions as $plugin_id => $definition) {
+      $this->assertText($definition['label']);
+      // Find the appropriate locales_source lid for the purposes of
+      // translating.
+      $results = db_select('locales_source', 'ls')
+        ->fields('ls')
+        ->condition('source', $definition['label'])
+        ->execute();
+      foreach ($results as $result) {
+        if ($result->lid) {
+          // Provide a translation for each mock block label.
+          foreach ($this->languages as $langcode) {
+            $this->storage->createTranslation(array(
+              'lid' => $result->lid,
+              'language' => $langcode,
+              'translation' => $langcode . ' ' . $definition['label'],
+            ))->save();
+          }
+        }
+      }
+    }
+    foreach ($languages as $langcode) {
+      $url = $langcode . '/plugin_definition_test';
+      // Foreach language visit the language specific version of the page again.
+      $this->drupalGet($url);
+      $cache = cache()->get('mock_block:' . $langcode);
+      debug($cache);
+      foreach ($this->mockBlockExpectedDefinitions as $plugin_id => $definition) {
+        // Find our provided translations.
+        $label = $langcode . ' ' . $definition['label'];
+        $this->assertText($label);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php
new file mode 100644
index 0000000..7a3f635
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/CachedMockBlockManager.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\plugin_test\Plugin\MockBlockManager.
+ */
+
+namespace Drupal\plugin_test\Plugin;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Plugin\Discovery\CacheDecorator;
+
+/**
+ * Defines a plugin manager used by Plugin API derivative unit tests.
+ */
+class CachedMockBlockManager extends MockBlockManager {
+  public function __construct() {
+    parent::__construct();
+    // The CacheDecorator allows us to cache these plugin definitions for
+    // quicker retrieval. In this case we are generating a cache key by
+    // language.
+    $this->discovery = new CacheDecorator($this->discovery, 'mock_block:' . language(LANGUAGE_TYPE_INTERFACE)->langcode);
+  }
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
index 14484f5..fcf1824 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
@@ -39,7 +39,7 @@ public function __construct() {
 
     // A simple plugin: the user login block.
     $this->discovery->setDefinition('user_login', array(
-      'label' => 'User login',
+      'label' => t('User login'),
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserLoginBlock',
     ));
 
@@ -61,7 +61,7 @@ public function __construct() {
     // MockLayoutBlockDeriver class ensures that both the base plugin and the
     // derivatives are available to the system.
     $this->discovery->setDefinition('layout', array(
-      'label' => 'Layout',
+      'label' => t('Layout'),
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock',
       'derivative' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlockDeriver',
     ));
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php
index c654bd0..1bfe806 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockLayoutBlockDeriver.php
@@ -46,7 +46,7 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
       // customized one, but in a real implementation, this would be fetched
       // from some config() object.
       'foo' => array(
-        'label' => 'Layout Foo',
+        'label' => t('Layout Foo'),
       ) + $base_plugin_definition,
     );
 
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
index aa84202..6b33d13 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
@@ -41,10 +41,10 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
     // Drupal's configuration to find out which menus actually exist.
     $derivatives = array(
       'main_menu' => array(
-        'label' => 'Main menu',
+        'label' => t('Main menu'),
       ) + $base_plugin_definition,
       'navigation' => array(
-        'label' => 'Navigation',
+        'label' => t('Navigation'),
       ) + $base_plugin_definition,
     );
 
diff --git a/core/modules/system/tests/modules/plugin_test/plugin_test.module b/core/modules/system/tests/modules/plugin_test/plugin_test.module
index 147e052..45e8568 100644
--- a/core/modules/system/tests/modules/plugin_test/plugin_test.module
+++ b/core/modules/system/tests/modules/plugin_test/plugin_test.module
@@ -14,3 +14,31 @@ function plugin_test_plugin_test_alter(&$definitions) {
   }
   $definitions['user_login']['altered_single'] = TRUE;
 }
+
+function plugin_test_menu() {
+  $items = array();
+  $items['plugin_definition_test'] = array(
+    'access callback' => TRUE,
+    'page callback' => 'plugin_test_definitions',
+  );
+  return $items;
+}
+
+function plugin_test_definitions() {
+  $manager = new Drupal\plugin_test\Plugin\CachedMockBlockManager();
+  $output = array();
+  foreach($manager->getDefinitions() as $plugin_id => $definition) {
+    $results = db_select('locales_source', 'ls')
+      ->fields('ls')
+      ->condition('source', $definition['label'])
+      ->execute();
+    foreach ($results as $result) {
+      drupal_set_message('<pre>' . var_export($result->lid, TRUE) . '</pre>');
+    }
+    $output[$plugin_id] = array(
+      '#type' => 'markup',
+      '#markup' => $definition['label'],
+    );
+  }
+  return $output;
+}
\ No newline at end of file
