diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index 221b921..568e6c2 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -59,6 +59,7 @@ function aggregator_theme() {
     ),
     'aggregator_block_item' => array(
       'variables' => array('item' => NULL, 'feed' => 0),
+      'template' => 'aggregator-block-item',
     ),
     'aggregator_summary_items' => array(
       'variables' => array('summary_items' => NULL, 'source' => NULL),
@@ -68,6 +69,7 @@ function aggregator_theme() {
     'aggregator_summary_item' => array(
       'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
       'file' => 'aggregator.pages.inc',
+      'template' => 'aggregator-summary-item',
     ),
     'aggregator_item' => array(
       'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
@@ -77,10 +79,12 @@ function aggregator_theme() {
     'aggregator_page_opml' => array(
       'variables' => array('feeds' => NULL),
       'file' => 'aggregator.pages.inc',
+      'template' => 'aggregator-page-opml',
     ),
     'aggregator_page_rss' => array(
       'variables' => array('feeds' => NULL, 'category' => NULL),
       'file' => 'aggregator.pages.inc',
+      'template' => 'aggregator-page-rss',
     ),
   );
 }
@@ -511,18 +515,19 @@ function aggregator_category_load($cid) {
 }
 
 /**
- * Returns HTML for an individual feed item for display in the block.
+ * Prepares variables for individual feed item block templates.
  *
- * @param $variables
+ * Default template: aggregator-block-item.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - item: The item to be displayed.
  *   - feed: Not used.
- *
- * @ingroup themeable
  */
-function theme_aggregator_block_item($variables) {
+function template_preprocess_aggregator_block_item(&$variables) {
   // Display the external link to the item.
-  return '<a href="' . check_url($variables['item']->link) . '">' . check_plain($variables['item']->title) . "</a>\n";
+  $variables['url'] = check_url($variables['item']->link);
+  $variables['title'] = check_plain($variables['item']->title);
 }
 
 /**
diff --git a/core/modules/aggregator/aggregator.pages.inc b/core/modules/aggregator/aggregator.pages.inc
index 32509ce..ec3f5a7 100644
--- a/core/modules/aggregator/aggregator.pages.inc
+++ b/core/modules/aggregator/aggregator.pages.inc
@@ -7,6 +7,7 @@
 
 use Drupal\aggregator\Plugin\Core\Entity\Feed;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Language\Language;
 
 /**
  * Page callback: Displays all the items captured from the particular feed.
@@ -416,55 +417,81 @@ function aggregator_page_rss() {
   }
 
   $feeds = $result->fetchAll();
-  return theme('aggregator_page_rss', array('feeds' => $feeds, 'category' => $category));
+
+  print theme('aggregator_page_rss', array('feeds' => $feeds, 'category' => $category));
+  drupal_exit();
 }
 
 /**
- * Prints the RSS page for a feed.
+ * Prepares variables for a RSS feed page template.
  *
- * @param $variables
+ * Default template: aggregator-page-rss.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - feeds: An array of the feeds to theme.
  *   - category: A common category, if any, for all the feeds.
- *
- * @return void
- *
- * @ingroup themeable
  */
-function theme_aggregator_page_rss($variables) {
+function template_preprocess_aggregator_page_rss(&$variables) {
   $feeds = $variables['feeds'];
   $category = $variables['category'];
 
   drupal_add_http_header('Content-Type', 'application/rss+xml; charset=utf-8');
 
-  $items = '';
+  $items = array();
   $feed_length = config('system.rss')->get('items.view_mode');
   foreach ($feeds as $feed) {
-    switch ($feed_length) {
-      case 'teaser':
-        $summary = text_summary($feed->description, NULL, config('aggregator.settings')->get('items.teaser_length'));
-        if ($summary != $feed->description) {
-          $summary .= '<p><a href="' . check_url($feed->link) . '">' . t('read more') . "</a></p>\n";
-        }
+     switch ($feed_length) {
+       case 'teaser':
+          $summary = text_summary($feed->description, NULL, config('aggregator.settings')->get('items.teaser_length'));
+          if ($summary != $feed->description) {
+            $summary = array(
+              $summary,
+              array(
+                '#prefix' => '<p>',
+                '#suffix' => "</p>\n",
+                '#theme' => 'link',
+                '#path' => check_url($feed->link),
+                '#title' => t('read more'),
+              ),
+            );
+          }
         $feed->description = $summary;
         break;
       case 'title':
         $feed->description = '';
         break;
     }
-    $items .= format_rss_item($feed->ftitle . ': ' . $feed->title, $feed->link, $feed->description, array('pubDate' => date('r', $feed->timestamp)));
+    $items[] = format_rss_item($feed->ftitle . ': ' . $feed->title, $feed->link, $feed->description, array('pubDate' => date('r', $feed->timestamp)));
   }
 
   $site_name = config('system.site')->get('name');
   $url = url((isset($category) ? 'aggregator/categories/' . $category->cid : 'aggregator'), array('absolute' => TRUE));
   $description = isset($category) ? t('@site_name - aggregated feeds in category @title', array('@site_name' => $site_name, '@title' => $category->title)) : t('@site_name - aggregated feeds', array('@site_name' => $site_name));
 
-  $output  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
-  $output .= "<rss version=\"2.0\">\n";
-  $output .= format_rss_channel(t('@site_name aggregator', array('@site_name' => $site_name)), $url, $description, $items);
-  $output .= "</rss>\n";
-
-  print $output;
+  $variables['title'] = t('@site_name aggregator', array('@site_name' => $site_name));
+  $variables['link'] = check_url($url);
+  // The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
+  // We strip all HTML tags, but need to prevent double encoding from properly
+  // escaped source data (such as &amp becoming &amp;amp;).
+  $variables['description'] = check_plain(decode_entities(strip_tags($description)));
+  $variables['items'] = $items;
+
+  /**
+   * Use RSS language code if found, otherwise default to existing page language code
+   */
+  if (isset($category['langcode']))
+    $variables['langcode'] = check_plain($category['langcode']);
+  // Try to default to the site language code
+  elseif (!isset($variables['langcode']))
+    $variables['langcode'] = language(Language::TYPE_CONTENT)->langcode;
+
+  // Pass along any channel args to be rendered after the language code.
+  if (isset($category['args']) && is_array($category['args'])) {
+     $variables['args'] = format_xml_elements($category['args']);
+  } else {
+     $variables['args'] = '';
+  }
 }
 
 /**
@@ -488,37 +515,32 @@ function aggregator_page_opml($cid = NULL) {
   }
 
   $feeds = $result->fetchAll();
-  return theme('aggregator_page_opml', array('feeds' => $feeds));
+  print theme('aggregator_page_opml', array('feeds' => $feeds));
+  drupal_exit();
 }
 
 /**
- * Prints the OPML page for the feed.
+ * Prepares variables for an OPML feed page template.
+ *
+ * Default template: aggregator-page-opml.html.twig.
  *
  * @param array $variables
  *   An associative array containing:
  *   - feeds: An array of the feeds to theme.
- *
- * @ingroup themeable
  */
-function theme_aggregator_page_opml($variables) {
+function template_preprocess_aggregator_page_opml(&$variables) {
   $feeds = $variables['feeds'];
 
   drupal_add_http_header('Content-Type', 'text/xml; charset=utf-8');
 
-  $output  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
-  $output .= "<opml version=\"1.1\">\n";
-  $output .= "<head>\n";
-  $output .= '<title>' . check_plain(config('system.site')->get('name')) . "</title>\n";
-  $output .= '<dateModified>' . gmdate(DATE_RFC2822, REQUEST_TIME) . "</dateModified>\n";
-  $output .= "</head>\n";
-  $output .= "<body>\n";
-  foreach ($feeds as $feed) {
-    $output .= '<outline text="' . check_plain($feed->title) . '" xmlUrl="' . check_url($feed->url) . "\" />\n";
-  }
-  $output .= "</body>\n";
-  $output .= "</opml>\n";
+  $variables['title'] = check_plain(config('system.site')->get('name'));
+  $variables['date'] = gmdate(DATE_RFC2822, REQUEST_TIME);
+  $variables['feeds'] = array();
 
-  print $output;
+  foreach ($feeds as $key => $feed) {
+    $variables['feeds'][$key]['title'] = check_plain($feed->title);
+    $variables['feeds'][$key]['url'] = check_url($feed->url);
+  }
 }
 
 /**
@@ -558,12 +580,12 @@ function template_preprocess_aggregator_summary_items(&$variables) {
 function template_preprocess_aggregator_summary_item(&$variables) {
   $item = $variables['aggregator_item'];
 
-  $variables['item_url'] = l(check_plain($item->label()), check_url(url($item->link->value, array('absolute' => TRUE))), array(
+  $variables['url'] = l(check_plain($item->label()), check_url(url($item->link->value, array('absolute' => TRUE))), array(
     'attributes' => array(
       'class' => array('feed-item-url',),
     ),
   ));
-  $variables['item_age'] = theme('datetime', array(
+  $variables['age'] = theme('datetime', array(
     'attributes' => array(
       'datetime' => format_date($item->timestamp->value, 'html_datetime', '', 'UTC'),
       'class' => array('feed-item-age',),
diff --git a/core/modules/aggregator/templates/aggregator-block-item.html.twig b/core/modules/aggregator/templates/aggregator-block-item.html.twig
new file mode 100644
index 0000000..10bc490
--- /dev/null
+++ b/core/modules/aggregator/templates/aggregator-block-item.html.twig
@@ -0,0 +1,16 @@
+{#
+/**
+ * @file
+ * Default theme implementation for feed item for display in the block.
+ *
+ * Available variables:
+ * - url: URL to the feed item.
+ * - title: Title of the feed item.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_aggregator_block_item()
+ *
+ * @ingroup themeable
+ */
+#}
+<a href="{{ url }}">{{ title }}</a>
diff --git a/core/modules/aggregator/templates/aggregator-page-opml.html.twig b/core/modules/aggregator/templates/aggregator-page-opml.html.twig
new file mode 100644
index 0000000..8132624
--- /dev/null
+++ b/core/modules/aggregator/templates/aggregator-page-opml.html.twig
@@ -0,0 +1,30 @@
+{#
+/**
+ * @file
+ * Default theme implementation to present @todo.
+ *
+ * Available variables:
+ * - title: Title of the feed.
+ * - date: Last date feed was modified.
+ * - feeds: An associative array of feed items containing:
+ *   - feed.title: Title of the feed item.
+ *   - feed.url: URL to the feed item.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_aggregator_page_opml()
+ *
+ * @ingroup themeable
+ */
+#}
+<?xml version="1.0" encoding="utf-8"?>
+<opml version="1.1">
+  <head>
+    <title>{{ title }}</title>
+    <dateModified>{{ date }}</dateModified>
+  </head>
+<body>
+  {% for feed in feeds %}
+    <outline text="{{ feed.title }}" xmlUrl="{{ feed.url }}" />
+  {% endfor %}
+</body>
+</opml>
diff --git a/core/modules/aggregator/templates/aggregator-page-rss.html.twig b/core/modules/aggregator/templates/aggregator-page-rss.html.twig
new file mode 100644
index 0000000..9c121c5
--- /dev/null
+++ b/core/modules/aggregator/templates/aggregator-page-rss.html.twig
@@ -0,0 +1,32 @@
+{#
+/**
+ * @file
+ * Default theme implementation for an RSS feed page.
+ *
+ * Available variables:
+ * - title: RSS channel title.
+ * - link: RSS channel link.
+ * - description: RSS channel description.
+ * - language: RSS channel language code.
+ * - items: RSS feed items.
+ * - args: Any channel args to be rendered after the language code.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_aggregator_page_rss()
+ *
+ * @ingroup themeable
+ */
+#}
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0">
+  <channel>
+    <title>{{ title }}</title>
+    <link>{{ link }}</link>
+    <description>{{ description }}</description>
+    <language>{{ langcode }}</language>
+    {{ args }}
+    {% for item in items %}
+      {{ item }}
+    {% endfor %}
+  </channel>
+</rss>
diff --git a/core/modules/aggregator/templates/aggregator-summary-item.html.twig b/core/modules/aggregator/templates/aggregator-summary-item.html.twig
new file mode 100644
index 0000000..6e2d8b1
--- /dev/null
+++ b/core/modules/aggregator/templates/aggregator-summary-item.html.twig
@@ -0,0 +1,16 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a single feed in a list of feed items.
+ *
+ * Available variables:
+ * - link: Link to item.
+ * - age: Age of the item.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_aggregator_summary_item()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ url }} {{ age }}
