diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index b361dba6b3e66c00d4949b81d76c4817f8fb7ab3..5f3dab9f86814b583c991716202100c27752b870 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -1,7 +1,7 @@
 services:
   plugin.manager.block:
     class: Drupal\block\Plugin\Type\BlockManager
-    arguments: ['@container.namespaces', '@cache.block', '@language_manager', '@module_handler']
+    arguments: ['@container.namespaces', '@cache.block', '@language_manager', '@module_handler', '@string_translation']
   cache.block:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index ead5531436695f478f274e49fcaf4cd59662aed5..9c30cfba81d3864823cf982bab6a32d496db6bd6 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\StringTranslation\TranslationInterface;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -21,6 +22,20 @@
  */
 class BlockManager extends DefaultPluginManager {
 
+  /**
+   * An array of all available modules and their data.
+   *
+   * @var array
+   */
+  protected $moduleData;
+
+  /**
+   * The translation manager.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface
+   */
+  protected $translationManager;
+
   /**
    * Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
    *
@@ -33,12 +48,16 @@ class BlockManager extends DefaultPluginManager {
    *   The language manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
+   *   The translation manager.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, TranslationInterface $translation_manager) {
     $annotation_namespaces = array('Drupal\block\Annotation' => $namespaces['Drupal\block']);
     parent::__construct('Plugin/Block', $namespaces, $annotation_namespaces, 'Drupal\block\Annotation\Block');
+
     $this->alterInfo($module_handler, 'block');
     $this->setCacheBackend($cache_backend, $language_manager, 'block_plugins');
+    $this->translationManager = $translation_manager;
   }
 
   /**
@@ -48,10 +67,45 @@ public function processDefinition(&$definition, $plugin_id) {
     parent::processDefinition($definition, $plugin_id);
 
     // Ensure that every block has a category.
-    $definition += array(
-      'module' => $definition['provider'],
-      'category' => $definition['provider'],
-    );
+    if (!isset($definition['category'])) {
+      $definition['category'] = $this->getModuleName($definition['provider']);
+    }
+    // @todo Remove any usage of 'module' from block code.
+    if (!isset($definition['module'])) {
+      $definition['module'] = $definition['provider'];
+    }
+  }
+
+  /**
+   * Gets the name of the module.
+   *
+   * @param string $module
+   *   The machine name of a module.
+   *
+   * @return string
+   *   The human-readable module name if it exists, otherwise the
+   *   machine-readable module name.
+   */
+  protected function getModuleName($module) {
+    // Gather module data.
+    if (!isset($this->moduleData)) {
+      $this->moduleData = system_get_info('module');
+    }
+    // If the module exists, return its human-readable name.
+    if (isset($this->moduleData[$module])) {
+      return $this->t($this->moduleData[$module]['name']);
+    }
+    // Otherwise, return the machine name.
+    return $module;
+  }
+
+  /**
+   * Translates a string to the current language or to a given language.
+   *
+   * See the t() documentation for details.
+   */
+  protected function t($string, array $args = array(), array $options = array()) {
+    return $this->translationManager->translate($string, $args, $options);
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
index c6bf3247030b4107456e9356ad5aba4709808527..92f137bdc092605160c6f6407ea6b8d4bc5871f0 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -17,7 +17,7 @@
  * @Block(
  *   id = "system_menu_block",
  *   admin_label = @Translation("Menu"),
- *   category = "menu",
+ *   category = @Translation("Menu"),
  *   derivative = "Drupal\system\Plugin\Derivative\SystemMenuBlock"
  * )
  */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 39886f4bbd73b142e92e55010e7d57611d364f80..10bc48d3822812c1477dc9078dcf1405633618f6 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2370,7 +2370,9 @@ function system_get_info($type, $name = NULL) {
   if ($type == 'module') {
     $data = system_rebuild_module_data();
     foreach (Drupal::moduleHandler()->getModuleList() as $module => $filename) {
-      $info[$module] = $data[$module]->info;
+      if (isset($data[$module])) {
+        $info[$module] = $data[$module]->info;
+      }
     }
   }
   else {