diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 56e5f43..66043b5 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException;
 use Symfony\Component\HttpFoundation\Request;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Language\Translator;
 
 /**
  * @file
@@ -1437,7 +1438,7 @@ function bootstrap_hooks() {
  * @see format_string()
  * @ingroup sanitization
  */
-function t($string, array $args = array(), array $options = array()) {
+function _t($string, array $args = array(), array $options = array()) {
   static $custom_strings;
 
   // Merge in default.
@@ -1471,6 +1472,19 @@ function t($string, array $args = array(), array $options = array()) {
   }
 }
 
+function t($string, array $args = array(), array $options = array()) {
+  $translations = &drupal_static(__FUNCTION__, array());
+  if (empty($options['langcode'])) {
+    $options['langcode'] = language(LANGUAGE_TYPE_INTERFACE)->langcode;
+  }
+  $key = serialize(array(func_get_args()));
+  if (!isset($translations[$key])) {
+    $translations[$key] = new Translator($string, $args, $options);
+  }
+
+  return $translations[$key];
+}
+
 /**
  * Replaces placeholders with sanitized values in a string.
  *
diff --git a/core/includes/form.inc b/core/includes/form.inc
index a142e69..4ca5cbe 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -2570,7 +2570,7 @@ function _form_options_flatten($array) {
   $return = &drupal_static(__FUNCTION__);
 
   foreach ($array as $key => $value) {
-    if (is_object($value)) {
+    if (is_object($value) && property_exists($value, 'option')) {
       _form_options_flatten($value->option);
     }
     elseif (is_array($value)) {
@@ -2701,7 +2701,7 @@ function form_select_options($element, $choices = NULL) {
       $options .= form_select_options($element, $choice);
       $options .= '</optgroup>';
     }
-    elseif (is_object($choice)) {
+    elseif (is_object($choice) && property_exists($choice, 'option')) {
       $options .= form_select_options($element, $choice->option);
     }
     else {
diff --git a/core/lib/Drupal/Core/Language/Translator.php b/core/lib/Drupal/Core/Language/Translator.php
new file mode 100644
index 0000000..55a260b
--- /dev/null
+++ b/core/lib/Drupal/Core/Language/Translator.php
@@ -0,0 +1,46 @@
+<?php
+namespace Drupal\Core\Language;
+
+class Translator implements \ArrayAccess {
+  public $string;
+  public $args;
+  public $options;
+  public $translation = FALSE;
+
+  public function offsetExists ($offset) { return FALSE; }
+  public function offsetGet ($offset) { return NULL; }
+  public function offsetSet ($offset, $value) {}
+  public function offsetUnset ($offset) {}
+
+  public function __construct($string, array $args = array(), array $options = array()) {
+    $this->string = $string;
+    $this->args = $args;
+    $this->options = $options;
+  }
+
+  public function printed() {
+    return $this->translation != FALSE;
+  }
+
+  public function render() {
+    foreach ($this->args as $key => &$value) {
+      if ($value instanceof Translator) {
+        $value = $value->render();
+      }
+    }
+    unset($key, $value);
+    $ret = _t($this->string, $this->args, $this->options);
+    if (!isset($ret)) {
+      $ret = '';
+    }
+    return $ret;
+  }
+
+  public function __toString() {
+    if (!$this->translation) {
+      $this->translation = $this->render();
+    }
+    $ret = $this->translation;
+    return $ret;
+  }
+}
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 25139e6..832a359 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -10,6 +10,7 @@ namespace Drupal\simpletest;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\ConnectionNotDefinedException;
+use Drupal\Core\Language\Translator;
 use PDO;
 use stdClass;
 use DOMDocument;
@@ -1178,7 +1179,7 @@ abstract class WebTestBase extends TestBase {
         $edit = $edit_save;
         $post = array();
         $upload = array();
-        $submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
+        $submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : (string) $submit, $form);
         $action = isset($form['action']) ? $this->getAbsoluteUrl((string) $form['action']) : $this->getUrl();
         if ($ajax) {
           $action = $this->getAbsoluteUrl(!empty($submit['path']) ? $submit['path'] : 'system/ajax');
@@ -1654,6 +1655,9 @@ abstract class WebTestBase extends TestBase {
   protected function buildXPathQuery($xpath, array $args = array()) {
     // Replace placeholders.
     foreach ($args as $placeholder => $value) {
+      if ($value instanceof Translator) {
+        $value = (string) $value;
+      }
       // XPath 1.0 doesn't support a way to escape single or double quotes in a
       // string literal. We split double quotes out of the string, and encode
       // them separately.
@@ -2068,7 +2072,7 @@ abstract class WebTestBase extends TestBase {
     if (!$message) {
       $message = t('Raw "@raw" found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) !== FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) !== FALSE, $message, $group);
   }
 
   /**
@@ -2088,7 +2092,7 @@ abstract class WebTestBase extends TestBase {
     if (!$message) {
       $message = t('Raw "@raw" not found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) === FALSE, $message, $group);
   }
 
   /**
@@ -2150,7 +2154,7 @@ abstract class WebTestBase extends TestBase {
     if (!$message) {
       $message = !$not_exists ? t('"@text" found', array('@text' => $text)) : t('"@text" not found', array('@text' => $text));
     }
-    return $this->assert($not_exists == (strpos($this->plainTextContent, $text) === FALSE), $message, $group);
+    return $this->assert($not_exists == (strpos($this->plainTextContent, (string) $text) === FALSE), $message, $group);
   }
 
   /**
