diff --git a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
index 85a6e3f4c46d7395b37d71f54dfe5d8af7122749..ebb20e4df733686397ed10b071e1f6409e34925c 100644
--- a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
+++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php
@@ -52,6 +52,17 @@ protected function formatPlural($count, $singular, $plural, array $args = array(
     return $this->getStringTranslation()->formatPlural($count, $singular, $plural, $args, $options);
   }
 
+  /**
+   * Formats a translated string containing a count of items.
+   *
+   * See the
+   * \Drupal\Core\StringTranslation\TranslationInterface::formatPluralTranslated()
+   * documentation for details.
+   */
+  protected function formatPluralTranslated($count, $translated, array $args = array(), array $options = array()) {
+    return $this->getStringTranslation()->formatPluralTranslated($count, $translated, $args, $options);
+  }
+
   /**
    * Gets the string translation service.
    *
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
index bc560cfd5ee49d0b40374552f5c420b1e1b47c3d..3e866bb02b97388d1be39405aa38447f59f1e3a7 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php
@@ -41,7 +41,7 @@ public function translate($string, array $args = array(), array $options = array
    *
    * This function ensures that the string is pluralized correctly. Since t() is
    * called by this function, make sure not to pass already-localized strings to
-   * it.
+   * it. See formatPluralTranslated() for that.
    *
    * For example:
    * @code
@@ -70,19 +70,54 @@ public function translate($string, array $args = array(), array $options = array
    *   An associative array of replacements to make after translation. Instances
    *   of any key in this array are replaced with the corresponding value.
    *   Based on the first character of the key, the value is escaped and/or
-   *   themed. See format_string(). Note that you do not need to include @count
-   *   in this array; this replacement is done automatically for the plural case.
+   *   themed. See \Drupal\Component\Utility\String::format(). Note that you do
+   *   not need to include @count in this array; this replacement is done
+   *   automatically for the plural cases.
    * @param array $options
    *   An associative array of additional options. See t() for allowed keys.
    *
    * @return string
    *   A translated string.
    *
-   * @see self::translate
-   * @see \Drupal\Component\Utility\String
+   * @see self::translate()
    * @see t()
-   * @see format_string()
+   * @see \Drupal\Component\Utility\SafeMarkup::format()
+   * @see self::formatPluralTranslated
    */
   public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array());
 
+  /**
+   * Formats an already translated string containing a count of items.
+   *
+   * This function ensures that the string is pluralized correctly. As opposed
+   * to the formatPlural() method, this method is designed to be invoked with
+   * a string already translated (such as with configuration translation).
+   *
+   * @param int $count
+   *   The item count to display.
+   * @param string $translation
+   *   The string containing the translation of a singular/plural pair. It may
+   *   contain any number of possible variants (depending on the language
+   *   translated to) separated by the value of the LOCALE_PLURAL_DELIMITER
+   *   constant.
+   * @param array $args
+   *   Associative array of replacements to make in the translation. Instances
+   *   of any key in this array are replaced with the corresponding value.
+   *   Based on the first character of the key, the value is escaped and/or
+   *   themed. See \Drupal\Component\Utility\String::format(). Note that you do
+   *   not need to include @count in this array; this replacement is done
+   *   automatically for the plural cases.
+   * @param array $options
+   *   An associative array of additional options. The 'context' key is not
+   *   supported because the passed string is already translated. Use the
+   *   'langcode' key to ensure the proper plural logic is used.
+   *
+   * @return string
+   *   The correct substring for the given $count with $args replaced.
+   *
+   * @see self::formatPlural()
+   * @see \Drupal\Component\Utility\SafeMarkup::format()
+   */
+  public function formatPluralTranslated($count, $translation, array $args = array(), array $options = array());
+
 }
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
index 46012acd535482756908d78d264d18b09fbcf765..edb391ce50e624d928bcf927dc22863b540636fd 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
@@ -129,6 +129,30 @@ public function getStringTranslation($langcode, $string, $context) {
    * {@inheritdoc}
    */
   public function translate($string, array $args = array(), array $options = array()) {
+    $string = $this->doTranslate($string, $options);
+    if (empty($args)) {
+      return SafeMarkup::set($string);
+    }
+    else {
+      return SafeMarkup::format($string, $args);
+    }
+  }
+
+  /**
+   * Translates a string to the current language or to a given language.
+   *
+   * @param string $string
+   *   A string containing the English string to translate.
+   * @param array $options
+   *   An associative array of additional options, with the following elements:
+   *   - 'langcode': The language code to translate to a language other than
+   *      what is used to display the page.
+   *   - 'context': The context the source string belongs to.
+   *
+   * @return string
+   *   The translated string.
+   */
+  protected function doTranslate($string, array $options = array()) {
     // Merge in defaults.
     if (empty($options['langcode'])) {
       $options['langcode'] = $this->defaultLangcode;
@@ -137,30 +161,27 @@ public function translate($string, array $args = array(), array $options = array
       $options['context'] = '';
     }
     $translation = $this->getStringTranslation($options['langcode'], $string, $options['context']);
-    $string = $translation === FALSE ? $string : $translation;
-
-    if (empty($args)) {
-      return SafeMarkup::set($string);
-    }
-    else {
-      return SafeMarkup::format($string, $args);
-    }
+    return $translation === FALSE ? $string : $translation;
   }
 
   /**
    * {@inheritdoc}
    */
   public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) {
-    $args['@count'] = $count;
-    // Join both forms to search a translation.
     $translatable_string = implode(LOCALE_PLURAL_DELIMITER, array($singular, $plural));
-    // Translate as usual.
-    $translated_strings = $this->translate($translatable_string, $args, $options);
-    // Split joined translation strings into array.
-    $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translated_strings);
+    $translated_strings = $this->doTranslate($translatable_string, $options);
+    return $this->formatPluralTranslated($count, $translated_strings, $args, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formatPluralTranslated($count, $translation, array $args = array(), array $options = array()) {
+    $args['@count'] = $count;
+    $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translation);
 
     if ($count == 1) {
-      return SafeMarkup::set($translated_array[0]);
+      return SafeMarkup::format($translated_array[0], $args);
     }
 
     // Get the plural index through the gettext formula.
@@ -182,7 +203,8 @@ public function formatPlural($count, $singular, $plural, array $args = array(),
         $return = $translated_array[1];
       }
     }
-    return SafeMarkup::set($return);
+
+    return SafeMarkup::format($return, $args);
   }
 
   /**
diff --git a/core/modules/locale/src/Tests/LocalePluralFormatTest.php b/core/modules/locale/src/Tests/LocalePluralFormatTest.php
index e6b51f1745063ed429f96fcf59fdf8ee41331d49..bb8674a1657c6db1e30cc3d0e7cbe4b47bc40988 100644
--- a/core/modules/locale/src/Tests/LocalePluralFormatTest.php
+++ b/core/modules/locale/src/Tests/LocalePluralFormatTest.php
@@ -131,6 +131,11 @@ public function testGetPluralFormat() {
         $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index;
         $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]);
         $this->assertIdentical(\Drupal::translation()->formatPlural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string);
+        // DO NOT use translation to pass into formatPluralTranslated() this
+        // way. It is designed to be used with *already* translated text like
+        // settings from configuration. We use PHP translation here just because
+        // we have the expected result data in that format.
+        $this->assertIdentical(\Drupal::translation()->formatPluralTranslated($count, \Drupal::translation()->translate('1 hour' . LOCALE_PLURAL_DELIMITER . '@count hours', array(), array('langcode' => $langcode)), array(), array('langcode' => $langcode)), $expected_plural_string, 'Translated plural lookup of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string);
       }
     }
   }