diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 3453b2a..86abf4d 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1487,7 +1487,6 @@ function bootstrap_hooks() {
  * @ingroup sanitization
  */
 function t($string, array $args = array(), array $options = array()) {
-  static $custom_strings;
 
   // Merge in default.
   if (empty($options['langcode'])) {
@@ -1497,19 +1496,24 @@ function t($string, array $args = array(), array $options = array()) {
     $options['context'] = '';
   }
 
-  // First, check for an array of customized strings. If present, use the array
-  // *instead of* database lookups. This is a high performance way to provide a
-  // handful of string replacements. See settings.php for examples.
-  // Cache the $custom_strings variable to improve performance.
-  if (!isset($custom_strings[$options['langcode']])) {
-    $custom_strings[$options['langcode']] = variable_get('locale_custom_strings_' . $options['langcode'], array());
+  try {
+    $translation = drupal_container()->get('string.translation')->translate($options['langcode'], $string, $options['context']);
+    $string = $translation === FALSE ? $string : $translation;
   }
-  // Custom strings work for English too, even if locale module is disabled.
-  if (isset($custom_strings[$options['langcode']][$options['context']][$string])) {
-    $string = $custom_strings[$options['langcode']][$options['context']][$string];
+  catch (Exception $e) {
+    // Register a foo translation service just in case a translation is
+    // attempted before language initialization. This one will cache strings
+    // if we want to see them later.
+    // Add basic translation system using files if this is an installation.
+    if (drupal_installation_attempted()) {
+      drupal_container()->register('string.translation', 'Drupal\Core\Translation\FileTranslation');
+    }
+    else {
+      drupal_container()->register('string.translation', 'Drupal\Core\Translation\StaticTranslation');
+    }
   }
   // Translate with locale module if enabled.
-  elseif ($options['langcode'] != LANGUAGE_SYSTEM && ($options['langcode'] != 'en' || variable_get('locale_translate_english', FALSE)) && function_exists('locale')) {
+  if ($options['langcode'] != LANGUAGE_SYSTEM && ($options['langcode'] != 'en' || variable_get('locale_translate_english', FALSE)) && function_exists('locale')) {
     $string = locale($string, $options['context'], $options['langcode']);
   }
   if (empty($args)) {
@@ -2642,13 +2646,9 @@ function drupal_installation_attempted() {
  * @ingroup sanitization
  */
 function get_t() {
-  static $t;
-  // This is not converted to drupal_static because there is no point in
-  // resetting this as it can not change in the course of a request.
-  if (!isset($t)) {
-    $t = drupal_installation_attempted() ? 'st' : 't';
-  }
-  return $t;
+  // Use always t() which will work nicely on any situation.
+  // @todo Remove all this logic, maybe keep st() to mark installer strings.
+  return 't';
 }
 
 /**
diff --git a/core/includes/install.inc b/core/includes/install.inc
index db92987..5c38ecd 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Core\Database\Database;
-use Drupal\locale\Gettext;
+use Drupal\Core\Translation\FileTranslation;
 
 /**
  * Requirement severity -- Informational message only.
@@ -729,48 +729,8 @@ function drupal_requirements_url($severity) {
  * @ingroup sanitization
  */
 function st($string, array $args = array(), array $options = array()) {
-  static $strings = NULL;
-  global $install_state;
-
-  if (empty($options['context'])) {
-    $options['context'] = '';
-  }
-
-  if (!isset($strings)) {
-    $strings = array();
-    if (isset($install_state['parameters']['langcode'])) {
-      // If the given langcode was selected, there should be at least one .po
-      // file with its name in the pattern drupal-$version.$langcode.po.
-      // This might or might not be the entire filename. It is also possible
-      // that multiple files end with the same suffix, even if unlikely.
-      $files = install_find_translation_files($install_state['parameters']['langcode']);
-      if (!empty($files)) {
-        // Register locale classes with the classloader. Locale module is not
-        // yet enabled at this stage, so this is not happening automatically.
-        drupal_classloader_register('locale', drupal_get_path('module', 'locale'));
-        $strings = Gettext::filesToArray($install_state['parameters']['langcode'], $files);
-      }
-    }
-  }
-
-  require_once DRUPAL_ROOT . '/core/includes/theme.inc';
-  // Transform arguments before inserting them
-  foreach ($args as $key => $value) {
-    switch ($key[0]) {
-      // Escaped only
-      case '@':
-        $args[$key] = check_plain($value);
-        break;
-      // Escaped and placeholder
-      case '%':
-      default:
-        $args[$key] = '<em>' . check_plain($value) . '</em>';
-        break;
-      // Pass-through
-      case '!':
-    }
-  }
-  return strtr((!empty($strings[$options['context']][$string]) ? $strings[$options['context']][$string] : $string), $args);
+  // @todo Remove or keep as a t wrapper to mark config strings..?
+  return t($string, $args, $options);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Translation/CustomStrings.php b/core/lib/Drupal/Core/Translation/CustomStrings.php
new file mode 100644
index 0000000..e9fb81a
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/CustomStrings.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\CustomStrings.
+ */
+
+namespace Drupal\Core\Translation;
+
+/**
+ * String translator using overrides from variables.
+ *
+ * This is a high performance way to provide a handful of string replacements.
+ * See settings.php for examples.
+ */
+class CustomStrings extends StaticTranslation {
+
+  /**
+   * Overrides Drupal\Core\Language\StaticTranslation::loadLanguage().
+   */
+  protected function loadLanguage($langcode) {
+    return variable_get('locale_custom_strings_' . $langcode, array());
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Translation/FileTranslation.php b/core/lib/Drupal/Core/Translation/FileTranslation.php
new file mode 100644
index 0000000..1a6c2ba
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/FileTranslation.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\FileTranslation.
+ */
+
+namespace Drupal\Core\Translation;
+
+use Drupal\locale\Gettext;
+
+/**
+ * File based string translation.
+ *
+ * Translates a string when some systems are not available.
+ *
+ * Used during the install process, when database, theme, and localization
+ * system is possibly not yet available.
+ *
+ * Use t() if your code will never run during the Drupal installation phase.
+ * Use st() if your code will only run during installation and never any other
+ * time. Use get_t() if your code could run in either circumstance.
+ */
+class FileTranslation extends StaticTranslation {
+
+  /**
+   * Overrides Drupal\Core\Language\StaticTranslation::__construct().
+   */
+  public function __construct($translations = array()) {
+    parent::__construct($translations);
+    // Register locale classes with the classloader. Locale module is not
+    // yet enabled at this stage, so this is not happening automatically.
+    drupal_classloader_register('locale', drupal_get_path('module', 'locale'));
+  }
+
+  /**
+   * Overrides Drupal\Core\Language\StaticTranslation::loadLanguage().
+   */
+  protected function loadLanguage($langcode) {
+    // If the given langcode was selected, there should be at least one .po
+    // file with its name in the pattern drupal-$version.$langcode.po.
+    // This might or might not be the entire filename. It is also possible
+    // that multiple files end with the same suffix, even if unlikely.
+    $files = install_find_translation_files($langcode);
+    if (!empty($files)) {
+      return Gettext::filesToArray($langcode, $files);
+    }
+    else {
+      return array();
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Translation/LocaleTranslation.php b/core/lib/Drupal/Core/Translation/LocaleTranslation.php
new file mode 100644
index 0000000..31cfb91
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/LocaleTranslation.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\LocaleTRanslation.
+ */
+
+namespace Drupal\Core\Translation;
+
+use Drupal\locale\StringStorageInterface;
+use Drupal\locale\LocaleLookup;
+
+/**
+ * String translator using the locale module
+ *
+ *
+ * This is a high performance way to provide a handful of string replacements.
+ * See settings.php for examples.
+ */
+class LocaleTranslation implements TranslationInterface {
+
+  /**
+   * Storage for strings.
+   *
+   * @var Drupal\locale\StringStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Cached translations
+   *
+   * @var array
+   *   Array of Drupal\locale\LocaleLookup objects indexed by language code
+   *   and context.
+   */
+  protected $translations;
+
+  /**
+   * Constructs a translator from any number of translators
+   *
+   * The order of the translators in the array will be the order in which they
+   * will be tried for a translation.
+   *
+   * @param array $translations
+   *   Array of override strings indexed by language and context
+   */
+  public function __construct($storage) {
+    $this->storage = $storage;
+  }
+
+  /**
+   * Implements Drupal\Core\Language\TranslationInterface::translate()
+   */
+  public function translate($langcode, $string, $context, $location = NULL) {
+    // Strings are cached by langcode, context and roles, using instances of the
+    // LocaleLookup class to handle string lookup and caching.
+    if (!isset($this->translations[$langcode][$context])) {
+      $this->translations[$langcode][$context] = new LocaleLookup($langcode, $context, $this->storage);
+    }
+    $translation = $this->translations[$langcode][$context][$string];
+    return $translation === TRUE ? FALSE : $translation;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Translation/StaticTranslation.php b/core/lib/Drupal/Core/Translation/StaticTranslation.php
new file mode 100644
index 0000000..bef283f
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/StaticTranslation.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\StaticTranslation.
+ */
+
+namespace Drupal\Core\Translation;
+
+/**
+ * String translator with a static cache for translations.
+ *
+ * This is a high performance way to provide a handful of string replacements.
+ */
+class StaticTranslation implements TranslationInterface {
+
+  /**
+   * String translations
+   *
+   * @var array
+   *   Array of cached translations indexed by language and context.
+   */
+  protected $translations;
+
+  /**
+   * Constructs a translator from an array of translations.
+   *
+   * @param array $translations
+   *   Array of override strings indexed by language and context
+   */
+  public function __construct($translations = array()) {
+    $this->translations = $translations;
+  }
+
+  /**
+   * Implements Drupal\Core\Language\TranslationInterface::translate()
+   */
+  public function translate($langcode, $string, $context, $location = NULL) {
+    if (!isset($this->translations[$langcode])) {
+      $this->translations[$langcode] = $this->loadLanguage($langcode);
+    }
+    if (isset($this->translations[$langcode][$context][$string])) {
+      return $this->translations[$langcode][$context][$string];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Add translations for new language.
+   */
+  protected function loadLanguage($langcode) {
+    return array();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Translation/TranslationFallback.php b/core/lib/Drupal/Core/Translation/TranslationFallback.php
new file mode 100644
index 0000000..c66d1bc
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/TranslationFallback.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Translation\TranslationFallback.
+ */
+
+namespace Drupal\Core\Translation;
+
+/**
+ * String translator with a fallback system.
+ */
+class TranslationFallback implements TranslationInterface {
+
+
+  /**
+   * Main translator.
+   *
+   * @var array
+   *   Array of Drupal\Core\Language\TranslationInterface objects
+   */
+  protected $translators;
+
+
+  /**
+   * Constructs a translator from any number of translators
+   *
+   * The order of the translators in the array will be the order in which they
+   * will be tried for a translation.
+   *
+   * @param $translator1, $translator2
+   *   Multiple containing Drupal\Core\Language\TranslationInterface objects.
+   */
+  public function __construct() {
+    $this->translators = func_get_args();
+  }
+
+  /**
+   * Implements Drupal\Core\Translation\TranslationInterface::translate()
+   */
+  public function translate($langcode, $string, $context, $location = NULL) {
+    foreach ($this->translators as $translator) {
+      $translation = $translator->translate($langcode, $string, $context, $location);
+      if ($translation !== FALSE) {
+        return $translation;
+      }
+    }
+    // No translator got a translation.
+    return FALSE;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Translation/TranslationInterface.php b/core/lib/Drupal/Core/Translation/TranslationInterface.php
new file mode 100644
index 0000000..bbc0a5d
--- /dev/null
+++ b/core/lib/Drupal/Core/Translation/TranslationInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\TranslationInterface.
+ */
+
+namespace Drupal\Core\Translation;
+
+/**
+ * Interface for objects capable of string translation.
+ */
+interface TranslationInterface {
+
+  /**
+   * Translates English string to given language.
+   *
+   * @param $langcode
+   *   Language code to translate to.
+   * @param string $string
+   *   The source string
+   * @param array $context
+   *   The string context
+   *
+   * @return string|FALSE
+   *   Translated string if there is a translation, FALSE if not.
+   */
+  public function translate($langcode, $string, $context, $location = NULL);
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleBundle.php b/core/modules/locale/lib/Drupal/locale/LocaleBundle.php
new file mode 100644
index 0000000..4f0d9d5
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleBundle.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\LocaleBundle.
+ */
+
+namespace Drupal\locale;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Scope;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+use Drupal\Core\Database\Database;
+
+/**
+ * Bundle class for locale services.
+ *
+ * Ths is where we register locale services that should run when the module is
+ * enabled. For now only the locale storage that will be used for translations.
+ */
+class LocaleBundle extends Bundle
+{
+  public function build(ContainerBuilder $container) {
+    // Register storage and translation service.
+    $container->register('locale.storage', 'Drupal\locale\StringDatabaseStorage')
+      ->addArgument(new Reference('database'))
+      ->addArgument(array('target' => 'default'));
+    $container->register('locale.translation', 'Drupal\locale\LocaleTranslation')
+      ->addArgument(new Reference('locale.storage'));
+    // Do not replace existing default translation but add this as fallback.
+    $container->register('string.translation', 'Drupal\Core\Translation\TranslationFallback')
+      ->addArgument(new Reference('translation.default'))
+      ->addArgument(new Reference('locale.translation'));
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php b/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php
new file mode 100644
index 0000000..117c54f
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Language\LocaleTRanslation.
+ */
+
+namespace Drupal\Core\Translation;
+
+use Drupal\Core\Translation\TranslationInterface;
+use Drupal\locale\StringStorageInterface;
+use Drupal\locale\LocaleLookup;
+
+
+/**
+ * String translator using the locale module
+ *
+ *
+ * This is a high performance way to provide a handful of string replacements.
+ * See settings.php for examples.
+ */
+class LocaleTranslation implements TranslationInterface {
+
+  /**
+   * Storage for strings.
+   *
+   * @var Drupal\locale\StringStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Cached translations
+   *
+   * @var array
+   *   Array of Drupal\locale\LocaleLookup objects indexed by language code
+   *   and context.
+   */
+  protected $translations;
+
+  /**
+   * Constructs a translator from any number of translators
+   *
+   * The order of the translators in the array will be the order in which they
+   * will be tried for a translation.
+   *
+   * @param array $translations
+   *   Array of override strings indexed by language and context
+   */
+  public function __construct($storage) {
+    $this->storage = $storage;
+  }
+
+  /**
+   * Implements Drupal\Core\Translation\TranslationInterface::translate()
+   */
+  public function translate($langcode, $string, $context, $location = NULL) {
+    // If the language is not suitable for locale module, just return.
+    if ($langcode == LANGUAGE_SYSTEM || $langcode == 'en' && !variable_get('locale_translate_english', FALSE)) {
+      return FALSE;
+    }
+    // Strings are cached by langcode, context and roles, using instances of the
+    // LocaleLookup class to handle string lookup and caching.
+    if (!isset($this->translations[$langcode][$context])) {
+      $this->translations[$langcode][$context] = new LocaleLookup($langcode, $context, $this->storage);
+    }
+    $translation = $this->translations[$langcode][$context][$string];
+    return $translation === TRUE ? FALSE : $translation;
+  }
+
+}
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 3d3ce1f..7339634 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -291,58 +291,6 @@ function locale_translatable_language_list() {
 }
 
 /**
- * Provides interface translation services.
- *
- * This function is called from t() to translate a string if needed.
- *
- * @param $string
- *   A string to look up translation for. If omitted, all the
- *   cached strings will be returned in all languages already
- *   used on the page.
- * @param $context
- *   The context of this string.
- * @param $langcode
- *   Language code to use for the lookup.
- */
-function locale($string = NULL, $context = NULL, $langcode = NULL) {
-  $language_interface = language(LANGUAGE_TYPE_INTERFACE);
-
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['locale'] = &drupal_static(__FUNCTION__, array('cache' => array(), 'exists' => NULL));
-  }
-  $locale_t = &$drupal_static_fast['locale']['cache'];
-  $locale_exists = &$drupal_static_fast['locale']['exists'];
-
-  // Check whether Locale module is actually installed and operational.
-  // The mere existence of locale() does not imply that Locale module is
-  // actually enabled and its database tables are installed. Since PHP code
-  // cannot be unloaded, this is typically the case in the environment that
-  // is executing a test.
-  if (!isset($locale_exists)) {
-    $locale_exists = function_exists('module_exists') && module_exists('locale');
-  }
-  if (!$locale_exists) {
-    return $string;
-  }
-
-  if (!isset($string)) {
-    // Return all cached strings if no string was specified
-    return $locale_t;
-  }
-
-  $langcode = isset($langcode) ? $langcode : $language_interface->langcode;
-
-  // Strings are cached by langcode, context and roles, using instances of the
-  // LocaleLookup class to handle string lookup and caching.
-  if (!isset($locale_t[$langcode][$context]) && isset($language_interface)) {
-    $locale_t[$langcode][$context] = new LocaleLookup($langcode, $context, locale_storage());
-  }
-  return ($locale_t[$langcode][$context][$string] === TRUE ? $string : $locale_t[$langcode][$context][$string]);
-}
-
-/**
  * Reset static variables used by locale().
  */
 function locale_reset() {
