diff --git a/core/modules/locale/lib/Drupal/locale/LocaleCache.php b/core/modules/locale/lib/Drupal/locale/LocaleCache.php
new file mode 100644
index 0000000..54d29a2
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/LocaleCache.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Definition of LocaleCache
+ */
+
+namespace Drupal\locale;
+
+use Drupal\Core\Utility\CacheArray;
+
+/**
+ * Extends CacheArray to allow for dynamic building of the locale cache.
+ */
+class LocaleCache extends CacheArray {
+
+  /**
+   * A language code.
+   * @var string
+   */
+  protected $langcode;
+
+  /**
+   * The msgctxt context.
+   * @var string
+   */
+  protected $context;
+
+  /**
+   * Constructs a LocaleCache object.
+   */
+  public function __construct($langcode, $context, $path_root) {
+    $this->langcode = $langcode;
+    $this->context = $context;
+    parent::__construct("locale:$langcode:$context:$path_root", 'cache');
+  }
+
+  /**
+   * Overrides DrupalCacheArray::resolveCacheMiss().
+   */
+  protected function resolveCacheMiss($offset) {
+    $translation = db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language WHERE s.source = :source AND s.context = :context", array(
+      ':language' => $this->langcode,
+      ':source' => $offset,
+      ':context' => $this->context,
+    ))->fetchObject();
+    if ($translation) {
+      if ($translation->version != VERSION) {
+        // This is the first use of this string under current Drupal version.
+        // Update the {locales_source} table to indicate the string is current.
+        db_update('locales_source')
+          ->fields(array('version' => VERSION))
+          ->condition('lid', $translation->lid)
+          ->execute();
+      }
+      $value = !empty($translation->translation) ? $translation->translation : TRUE;
+    }
+    else {
+      // We don't have the source string, update the {locales_source} table to
+      // indicate the string is not translated.
+      db_merge('locales_source')
+        ->insertFields(array(
+          'location' => request_uri(),
+          'version' => VERSION,
+        ))
+        ->key(array(
+          'source' => $offset,
+          'context' => $this->context,
+        ))
+        ->execute();
+        $value = TRUE;
+    }
+    $this->storage[$offset] = $value;
+    // Disabling the usage of string caching allows a module to watch for
+    // the exact list of strings used on a page. From a performance
+    // perspective that is a really bad idea, so we have no user
+    // interface for this. Be careful when turning this option off!
+    if (variable_get('locale_cache_strings', 1)) { 
+      $this->persist($offset);
+    }
+    return $value;
+  }
+}
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 35f8032..b31d724 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -11,6 +11,8 @@
  *   Gettext portable object files are supported.
  */
 
+use Drupal\locale\LocaleCache;
+
 /**
  * Regular expression pattern used to localize JavaScript strings.
  */
@@ -406,76 +408,11 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
 
   $langcode = isset($langcode) ? $langcode : $language_interface->langcode;
 
-  // Store database cached translations in a static variable. Only build the
-  // cache after $language_interface has been set to avoid an unnecessary cache
-  // rebuild.
-  if (!isset($locale_t[$langcode]) && isset($language_interface)) {
-    $locale_t[$langcode] = array();
-    // Disabling the usage of string caching allows a module to watch for
-    // the exact list of strings used on a page. From a performance
-    // perspective that is a really bad idea, so we have no user
-    // interface for this. Be careful when turning this option off!
-    if (variable_get('locale_cache_strings', 1) == 1) {
-      if ($cache = cache()->get('locale:' . $langcode)) {
-        $locale_t[$langcode] = $cache->data;
-      }
-      elseif (lock_acquire('locale_cache_' . $langcode)) {
-        // Refresh database stored cache of translations for given language.
-        // We only store short strings used in current version, to improve
-        // performance and consume less memory.
-        $result = db_query("SELECT s.source, s.context, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language WHERE s.version = :version AND LENGTH(s.source) < :length", array(':language' => $langcode, ':version' => VERSION, ':length' => variable_get('locale_cache_length', 75)));
-        foreach ($result as $data) {
-          $locale_t[$langcode][$data->context][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
-        }
-        cache()->set('locale:' . $langcode, $locale_t[$langcode]);
-        lock_release('locale_cache_' . $langcode);
-      }
-    }
+  // Strings are cached by langcode, context and system path root, using instances of the
+  // LocaleCache class to handle string lookup and caching.
+  if (!isset($locale_t[$langcode][$context]) && isset($language_interface)) {
+    $locale_t[$langcode][$context] = new LocaleCache($langcode, $context, arg(0));
   }
-
-  // If we have the translation cached, skip checking the database
-  if (!isset($locale_t[$langcode][$context][$string])) {
-
-    // We do not have this translation cached, so get it from the DB.
-    $translation = db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language WHERE s.source = :source AND s.context = :context", array(
-      ':language' => $langcode,
-      ':source' => $string,
-      ':context' => (string) $context,
-    ))->fetchObject();
-    if ($translation) {
-      // We have the source string at least.
-      // Cache translation string or TRUE if no translation exists.
-      $locale_t[$langcode][$context][$string] = (empty($translation->translation) ? TRUE : $translation->translation);
-
-      if ($translation->version != VERSION) {
-        // This is the first use of this string under current Drupal version. Save version
-        // and clear cache, to include the string into caching next time. Saved version is
-        // also a string-history information for later pruning of the tables.
-        db_update('locales_source')
-          ->fields(array('version' => VERSION))
-          ->condition('lid', $translation->lid)
-          ->execute();
-        cache()->deletePrefix('locale:');
-      }
-    }
-    else {
-      // We don't have the source string, cache this as untranslated.
-      db_merge('locales_source')
-        ->insertFields(array(
-          'location' => request_uri(),
-          'version' => VERSION,
-        ))
-        ->key(array(
-          'source' => $string,
-          'context' => (string) $context,
-        ))
-        ->execute();
-      $locale_t[$langcode][$context][$string] = TRUE;
-      // Clear locale cache so this string can be added in a later request.
-      cache()->deletePrefix('locale:');
-    }
-  }
-
   return ($locale_t[$langcode][$context][$string] === TRUE ? $string : $locale_t[$langcode][$context][$string]);
 }
 
