Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.930
diff -u -r1.930 common.inc
--- includes/common.inc	4 Jul 2009 18:26:42 -0000	1.930
+++ includes/common.inc	7 Jul 2009 16:21:12 -0000
@@ -1894,6 +1894,12 @@
     $timezones[$timezone] = timezone_open($timezone);
   }
 
+  // Use the default langcode if none is set.
+  global $language;
+  if (empty($langcode)) {
+    $langcode = isset($language->language) ? $language->language : 'en';
+  }
+
   switch ($type) {
     case 'small':
       $format = variable_get('date_format_short', 'm/d/Y - H:i');
@@ -1909,39 +1915,66 @@
       $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
   }
 
-  $max = strlen($format);
-  $date = '';
   // Create a DateTime object from the timestamp.
   $date_time = date_create('@' . $timestamp);
   // Set the time zone for the DateTime object.
   date_timezone_set($date_time, $timezones[$timezone]);
 
-  for ($i = 0; $i < $max; $i++) {
-    $c = $format[$i];
-    if (strpos('AaeDlMT', $c) !== FALSE) {
-      $date .= t(date_format($date_time, $c), array(), array('langcode' => $langcode));
-    }
-    elseif ($c == 'F') {
-      // Special treatment for long month names: May is both an abbreviation
-      // and a full month name in English, but other languages have
-      // different abbreviations.
-      $date .= t(date_format($date_time, $c), array(), array('context' => 'Long month name', 'langcode' => $langcode));
-    }
-    elseif (strpos('BcdGgHhIijLmNnOoPSstUuWwYyZz', $c) !== FALSE) {
-      $date .= date_format($date_time, $c);
-    }
-    elseif ($c == 'r') {
-      $date .= format_date($timestamp, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode);
+  if ($langcode != 'en') {
+    // Encode markers that should be translated. 'A' becomes '\xEF\AA\xFF'.
+    // xEF and xFF are invalid UTF-8 sequences, and we assume they are not in the
+    // input string.
+    // Paired backslashes are isolated to prevent errors in read-ahead evaluation.
+    // The read-ahead expression ensures that A matches, but not \A.
+    $format = preg_replace(array('/\\\\\\\\/', '/(?<!\\\\)([AaeDlMTF])/'), array("\xEF\\\\\\\\\xFF", "\xEF\\\\\$1\$1\xFF"), $format);
+
+    // Call date_format().
+    $format = date_format($date_time, $format);
+
+    // Pass the langcode to _format_date_callback().
+    _format_date_callback(NULL, $langcode);
+
+    // Translate the marked sequences.
+    return preg_replace_callback('/\xEF([AaeDlMTF]?)(.*?)\xFF/', '_format_date_callback', $format);
+  }
+  else {
+    return date_format($date_time, $format);
+  }
+}
+
+/**
+ * Callback function for preg_replace_callback().
+ */
+function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
+  // We cache translations of months (12 possible values) and week days
+  // (7 possible values) in order to avoid a rather costly call to t().
+  static $cache, $langcode;
+
+  if (!isset($matches)) {
+    $langcode = $new_langcode;
+    return;
+  }
+
+  $code = $matches[1];
+  $string = $matches[2];
+
+  if (!isset($cache[$langcode][$code][$string])) {
+    $options = array(
+      'langcode' => $langcode,
+    );
+
+    if ($code == 'F') {
+      $options['context'] = 'Long month name';
     }
-    elseif ($c == '\\') {
-      $date .= $format[++$i];
+
+    if ($code == '') {
+      $cache[$langcode][$code][$string] = $string;
     }
     else {
-      $date .= $c;
+      $cache[$langcode][$code][$string] = t($string, array(), $options);
     }
   }
-
-  return $date;
+  return $cache[$langcode][$code][$string];
 }
 
 /**
