diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 9f9665c..39e7d9d 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -343,59 +343,68 @@ function locale($string = NULL, $langcode = NULL, $reset = FALSE) {
 
   $langcode = isset($langcode) ? $langcode : $language->language;
 
-  // Store database cached translations in a static var.
-  if (!isset($locale_t[$langcode])) {
-    $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, 'cache')) {
-        $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, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION);
-        while ($data = db_fetch_object($result)) {
-          $locale_t[$langcode][$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 and user roles, using instances of the
+  // LocaleLookup class to handle string lookup and caching.
+  if (!isset($locale_t[$langcode]) && isset($language)) {
+    $locale_t[$langcode] = new LocaleLookup($langcode);
+  } 
 
-  // If we have the translation cached, skip checking the database
-  if (!isset($locale_t[$langcode][$string])) {
+  return ($locale_t[$langcode][$string] === TRUE ? $string : $locale_t[$langcode][$string]);
+}
 
-    // We do not have this translation cached, so get it from the DB.
-    $translation = db_fetch_object(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 = '%s' WHERE s.source = '%s' AND s.textgroup = 'default'", $langcode, $string));
-    if ($translation) {
-      // We have the source string at least.
-      // Cache translation string or TRUE if no translation exists.
-      $locale_t[$langcode][$string] = (empty($translation->translation) ? TRUE : $translation->translation);
+/**
+ * Extends CacheArray to allow for dynamic building of the locale cache.
+ */
+class LocaleLookup extends DrupalCacheArray {
+
+  /**
+   * A language code.
+   * @var string
+   */
+  protected $langcode;
+
+  /**
+   * Constructs a LocaleCache object.
+   */
+  public function __construct($langcode) {
+    $this->langcode = $langcode;
+
+    // Add the current user's role IDs to the cache key, this ensures that, for
+    // example, strings for admin menu items and settings forms are not cached
+    // for anonymous users.
+    $rids = implode(':', array_keys($GLOBALS['user']->roles));
+    parent::__construct("locale:$langcode:$rids", 'cache');
+  }
 
+  /**
+   * Overrides DrupalCacheArray::resolveCacheMiss().
+   */
+  protected function resolveCacheMiss($offset) {
+    $translation = db_fetch_object(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 = '%s' WHERE s.source = '%s' AND s.textgroup = 'default'", $this->langcode, $offset));
+    if ($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_query("UPDATE {locales_source} SET version = '%s' WHERE lid = %d", VERSION, $translation->lid);
-        cache_clear_all('locale:', 'cache', TRUE);
+        // This is the first use of this string under current Drupal version.
+        // Update the {locales_source} table to indicate the string is current.
+        db_query("UPDATE {locales_source} SET version = '%s' WHERE lid = %d", VERSION, $translation->lid);
       }
+      $value = !empty($translation->translation) ? $translation->translation : TRUE;
     }
     else {
-      // We don't have the source string, cache this as untranslated.
+      // We don't have the source string, update the {locales_source} table to
+      // indicate the string is not translated.
       db_query("INSERT INTO {locales_source} (location, source, textgroup, version) VALUES ('%s', '%s', 'default', '%s')", request_uri(), $string, VERSION);
-      $locale_t[$langcode][$string] = TRUE;
-      // Clear locale cache so this string can be added in a later request.
-      cache_clear_all('locale:', 'cache', TRUE);
+        $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;
   }
-
-  return ($locale_t[$langcode][$string] === TRUE ? $string : $locale_t[$langcode][$string]);
 }
 
 /**
