diff --git a/include/class.format.php b/include/class.format.php
index d0e4ba203ecac6ff329045fa43be9d1c51bc307e..fbbddb6317ab0e5797cacc0a61196b41413c8d33 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -269,12 +269,16 @@ class Format {
     }
 
     function htmlencode($var) {
+        static $phpversion = null;
 
         if (is_array($var))
             return array_map(array('Format', 'htmlencode'), $var);
 
+        if (!isset($phpversion))
+            $phpversion = phpversion();
+
         $flags = ENT_COMPAT;
-        if (phpversion() >= '5.4.0')
+        if ($phpversion >= '5.4.0')
             $flags |= ENT_HTML401;
 
         try {
diff --git a/include/class.translation.php b/include/class.translation.php
index 06d25b05f839ecfa1682a29a4d894c872d84c6cc..cc21848a31e9153f8940c939a48d624bed36d461 100644
--- a/include/class.translation.php
+++ b/include/class.translation.php
@@ -304,7 +304,7 @@ class gettext_reader {
     $expr .= ';';
     $res = '';
     $p = 0;
-    for ($i = 0; $i < strlen($expr); $i++) {
+    for ($i = 0, $k = strlen($expr); $i < $k; $i++) {
       $ch = $expr[$i];
       switch ($ch) {
       case '?':
@@ -372,17 +372,23 @@ class gettext_reader {
    * @return int array index of the right plural form
    */
   function select_string($n) {
-    $string = $this->get_plural_forms();
-    $string = str_replace('nplurals',"\$total",$string);
-    $string = str_replace("n",$n,$string);
-    $string = str_replace('plural',"\$plural",$string);
-
-    $total = 0;
-    $plural = 0;
-
-    eval("$string");
-    if ($plural >= $total) $plural = $total - 1;
-    return $plural;
+      // Expression reads
+      // nplurals=X; plural= n != 1
+      if (!isset($this->plural_expression)) {
+          $matches = array();
+          if (!preg_match('`nplurals\s*=\s*(\d+)\s*;\s*plural\s*=\s*(.+$)`',
+                  $this->get_plural_forms(), $matches))
+              return 1;
+
+          $this->plural_expression = create_function('$n',
+              sprintf('return %s;', str_replace('n', '($n)', $matches[2])));
+          $this->plural_total = (int) $matches[1];
+      }
+      $func = $this->plural_expression;
+      $plural = $func($n);
+      return ($plural > $this->plural_total)
+          ? $this->plural_total - 1
+          : $plural;
   }
 
   /**
@@ -531,7 +537,7 @@ class FileReader {
  * source gettext library implementation which should be roughly the same
  * performance as the libc gettext library.
  */
-class Translation extends gettext_reader {
+class Translation extends gettext_reader implements Serializable {
 
     var $charset;
 
@@ -644,6 +650,30 @@ class Translation extends gettext_reader {
         else
             fwrite($stream, $contents);
     }
+
+    static function resurrect($key) {
+        if (!function_exists('apc_fetch'))
+            return false;
+
+        $success = true;
+        if (($translation = apc_fetch($key, $success)) && $success)
+            return $translation;
+    }
+    function cache($key) {
+        if (function_exists('apc_add'))
+            apc_add($key, $this);
+    }
+
+
+    function serialize() {
+        return serialize(array($this->charset, $this->encode, $this->cache_translations));
+    }
+    function unserialize($what) {
+        list($this->charset, $this->encode, $this->cache_translations)
+            = unserialize($what);
+        $this->short_circuit = ! $this->enable_cache
+            = 0 < count($this->cache_translations);
+    }
 }
 
 if (!defined('LC_MESSAGES')) {
@@ -695,6 +725,12 @@ class TextDomain {
             $subpath = self::$LC_CATEGORIES[$category] .
                 '/'.$this->domain.'.mo.php';
 
+            // APC short-circuit (if supported)
+            $key = sha1($locale .':lang:'. $subpath);
+            if ($T = Translation::resurrect($key)) {
+                return $this->l10n[$locale] = $T;
+            }
+
             $locale_names = self::get_list_of_locales($locale);
             $input = null;
             foreach ($locale_names as $T) {
@@ -712,7 +748,8 @@ class TextDomain {
                 }
             }
             // TODO: Handle charset hint from the environment
-            $this->l10n[$locale] = new Translation($input);
+            $this->l10n[$locale] = $T = new Translation($input);
+            $T->cache($key);
         }
         return $this->l10n[$locale];
     }