diff --git a/includes/rules.core.inc b/includes/rules.core.inc
index 4c6a356..be1ab59 100644
--- a/includes/rules.core.inc
+++ b/includes/rules.core.inc
@@ -453,6 +453,23 @@ abstract class RulesPlugin extends RulesExtendable {
   }
 
   /**
+   * Iterate over all elements nested below the current element.
+   *
+   * This helper can be used to recursively iterate over all elements of a
+   * configuration. To iterate over the children only, just regulary iterate
+   * over the object.
+   *
+   * @param $mode
+   *   (optional) The iteration mode used. See
+   *   RecursiveIteratorIterator::construct(). Defaults to SELF_FIRST.
+   *
+   * @return RecursiveIteratorIterator
+   */
+  public function elements($mode = RecursiveIteratorIterator::SELF_FIRST) {
+    return new RecursiveIteratorIterator($this, $mode);
+  }
+
+  /**
    * Do a deep clone.
    */
   public function __clone() {
@@ -840,6 +857,9 @@ abstract class RulesPlugin extends RulesExtendable {
     if (!empty($this->settings[$name . ':process'])) {
       // For processing, make sure the data is unwrapped now.
       $return = rules_unwrap_data(array($arg), array($info));
+      // @todo for Drupal 8: Refactor to add the parameter name as separate
+      // parameter to process().
+      $info['#name'] = $name;
       return isset($return[0]) ? $this->settings[$name . ':process']->process($return[0], $info, $state, $this) : NULL;
     }
     // Support passing already sanitized values.
diff --git a/includes/rules.processor.inc b/includes/rules.processor.inc
index d3a285c..741d9cb 100644
--- a/includes/rules.processor.inc
+++ b/includes/rules.processor.inc
@@ -235,31 +235,37 @@ abstract class RulesDataInputEvaluator extends RulesDataProcessor {
   protected function __construct($setting, $param_info, $var_info = array(), $processor = NULL) {
     $this->setting = TRUE;
     $this->processor = $processor;
-    $this->prepare($setting, $var_info);
+    $this->prepare($setting, $var_info, $param_info);
   }
 
   /**
    * Overridden to generate evaluator $options and invoke evaluate().
    */
   public function process($value, $info, RulesState $state, RulesPlugin $element, $options = NULL) {
-    if (!isset($options)) {
-      $cache = rules_get_cache();
-      $languages = language_list();
-      $info += array(
-        'cleaning callback' => isset($cache['data info'][$info['type']]['cleaning callback']) ? $cache['data info'][$info['type']]['cleaning callback'] : FALSE,
-        'sanitize' => FALSE,
-      );
-      $options = array_filter(array(
-        'language' => isset($element->settings['language']) && isset($languages[$element->settings['language']]) ? $languages[$element->settings['language']] : NULL,
-        'callback' => $info['cleaning callback'],
-        'sanitize' => $info['sanitize'],
-      ));
-    }
+    $options = isset($options) ? $options : $this->getEvaluatorOptions($info, $state, $element);
     $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element, $options) : $value;
     return $this->evaluate($value, $options, $state);
   }
 
   /**
+   * Generates the evaluator $options.
+   */
+  protected function getEvaluatorOptions($info, $state, $element) {
+    $cache = rules_get_cache();
+    $languages = language_list();
+    $info += array(
+      'cleaning callback' => isset($cache['data info'][$info['type']]['cleaning callback']) ? $cache['data info'][$info['type']]['cleaning callback'] : FALSE,
+      'sanitize' => FALSE,
+    );
+    $options = array_filter(array(
+      'language' => isset($element->settings['language']) && isset($languages[$element->settings['language']]) ? $languages[$element->settings['language']] : NULL,
+      'callback' => $info['cleaning callback'],
+      'sanitize' => $info['sanitize'],
+    ));
+    return $options;
+  }
+
+  /**
    * Overriden to prepare input evaluator processors. The setting is expected
    * to be the input value to be evaluated later on and is replaced by the
    * suiting processor.
@@ -311,6 +317,9 @@ abstract class RulesDataInputEvaluator extends RulesDataProcessor {
    *   The text to evaluate later on.
    * @param $variables
    *   An array of info about available variables.
+   * @param $param_info
+   *   (optional) An array of information about the handled parameter value.
+   *   For backward compatibility, this parameter is not required.
    */
   abstract public function prepare($text, $variables);
 
diff --git a/modules/system.rules.inc b/modules/system.rules.inc
index f9cf195..db1ffc5 100644
--- a/modules/system.rules.inc
+++ b/modules/system.rules.inc
@@ -104,6 +104,7 @@ function rules_system_action_info() {
           'type' => 'text',
           'label' => t('Message'),
           'sanitize' => TRUE,
+          'translatable' => TRUE,
         ),
         'type' => array(
           'type' => 'token',
diff --git a/rules.api.php b/rules.api.php
index 807b9db..a728ae9 100644
--- a/rules.api.php
+++ b/rules.api.php
@@ -96,6 +96,10 @@
  *     already sanitized argument. If enabled, any user specified value won't be
  *     sanitized itself, but replacements applied by input evaluators are as
  *     well as values retrieved from selected data sources.
+ *   - translatable: (optional) Allows translating provided argument values for
+ *     the parameter via i18n String translation. This is applicable only for
+ *     textual parameters, i.e. parameters of type 'text', 'token', 'list<text>'
+ *     and 'list<token>'.
  *   - cleaning callback: (optional) A callback that input evaluators may use
  *     to clean inserted replacements; e.g. this is used by the token evaluator.
  *   - wrapped: (optional) Set this to TRUE in case the data should be passed
diff --git a/rules.module b/rules.module
index b99ce96..be68562 100644
--- a/rules.module
+++ b/rules.module
@@ -578,6 +578,7 @@ function rules_entity_info() {
         'name' => 'name',
         'label' => 'label',
       ),
+      'module' => 'rules',
       'static cache' => TRUE,
       'bundles' => array(),
       'configuration' => TRUE,
diff --git a/rules_i18n/rules_i18n.i18n.inc b/rules_i18n/rules_i18n.i18n.inc
new file mode 100644
index 0000000..bb9a9ed
--- /dev/null
+++ b/rules_i18n/rules_i18n.i18n.inc
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Internationalization integration based upon the entity API i18n stuff.
+ */
+
+/**
+ * Rules i18n integration controller.
+ */
+class RulesI18nStringController extends EntityDefaultI18nStringController {
+
+  /**
+   * Overriden to customize i18n object info.
+   *
+   * @see EntityDefaultI18nStringController::hook_object_info()
+   */
+  public function hook_object_info() {
+    $info = parent::hook_object_info();
+    $info['rules_config']['class'] = 'RulesI18nStringObjectWrapper';
+    return $info;
+  }
+
+  /**
+   * Overriden to customize the used menu wildcard.
+   */
+  protected function menuWildcard() {
+    return '%rules_config';
+  }
+}
+
+/**
+ * Custom I18n String object wrapper, which register custom properties per config.
+ */
+class RulesI18nStringObjectWrapper extends i18n_string_object_wrapper {
+
+  /**
+   * Get translatable properties
+   */
+  protected function build_properties() {
+    $strings = parent::build_properties();
+    $properties = array();
+    $this->buildElementProperties($this->object, $properties);
+
+    // Add in translations for all elements.
+    foreach ($this->object->elements() as $element) {
+      $this->buildElementProperties($element, $properties);
+    }
+    $strings[$this->get_textgroup()]['rules_config'][$this->object->name] = $properties;
+    return $strings;
+  }
+
+  /**
+   * Adds in translatable properties of the given element.
+   */
+  protected function buildElementProperties($element, &$properties) {
+
+    foreach ($element->pluginParameterInfo() as $name => $info) {
+      // Add in all directly provided input variables.
+      if (!empty($info['translatable']) && isset($element->settings[$name])) {
+        $properties[$element->elementId() . ':' . $name] = array(
+          'title' => t('@label @id @name', array('@label' => $element->label(), '@id' => $element->elementId(), '@name' => $name)),
+          'string' => $element->settings[$name],
+        );
+      }
+    }
+  }
+}
diff --git a/rules_i18n/rules_i18n.info b/rules_i18n/rules_i18n.info
new file mode 100644
index 0000000..37401d0
--- /dev/null
+++ b/rules_i18n/rules_i18n.info
@@ -0,0 +1,8 @@
+name = Rules translation
+description = Allows translating rules.
+dependencies[] = rules
+dependencies[] = i18n_string
+package = Multilingual - Internationalization
+core = 7.x
+files[] = rules_i18n.i18n.inc
+files[] = rules_i18n.rules.inc
\ No newline at end of file
diff --git a/rules_i18n/rules_i18n.module b/rules_i18n/rules_i18n.module
new file mode 100644
index 0000000..a80171e
--- /dev/null
+++ b/rules_i18n/rules_i18n.module
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Rules i18n integration.
+ */
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function rules_i18n_entity_info_alter(&$info) {
+  // Enable i18n support via the entity API.
+  $info['rules_config']['i18n controller class'] = 'RulesI18nStringController';
+}
+
+/**
+ * Implements hook_rules_config_insert().
+ */
+function rules_i18n_rules_config_insert($rules_config) {
+  i18n_string_object_update('rules_config', $rules_config);
+}
+
+/**
+ * Implements hook_rules_config_update().
+ */
+function rules_i18n_rules_config_update($rules_config) {
+  // Account for name changes.
+  if ($rules_config->original->name != $rules_config->name) {
+    i18n_string_update_context("rules:rules_config:{$rules_config->original->name}:*", "rules:rules_config:{$rules_config->name}:*");
+  }
+
+  // We need to remove the strings of any disappeared properties, i.e. strings
+  // from translatable parameters of deleted actions.
+
+  // i18n_object() uses a static cache per config, so bypass it to wrap the
+  // original entity.
+  $old_i18n_object = new RulesI18nStringObjectWrapper('rules_config', $rules_config->original);
+  $old_strings = $old_i18n_object->get_strings(array('empty' => TRUE));
+
+  // Note: For the strings to have updated values, the updated entity needs to
+  // be handled last due to i18n's cache.
+  $strings = i18n_object('rules_config', $rules_config)->get_strings(array('empty' => TRUE));
+
+  foreach (array_diff_key($old_strings, $strings) as $name => $string) {
+    $string->remove(array('empty' => TRUE));
+  }
+  // Now update the remaining strings.
+  foreach ($strings as $string) {
+    $string->update(array('empty' => TRUE, 'update' => TRUE));
+  }
+}
+
+/**
+ * Implements hook_rules_config_delete().
+ */
+function rules_i18n_rules_config_delete($rules_config) {
+  i18n_string_object_remove('rules_config', $rules_config);
+}
+
+/**
+ * Implements hook_theme().
+ */
+function rules_i18n_theme() {
+  return array(
+    'rules_i18n_parameter_help' => array(
+      'variables' => array('text' => '', 'heading' => ''),
+    ),
+  );
+}
+
+/**
+ * Theme function for displaying i18n help for paramters.
+ */
+function theme_rules_i18n_parameter_help($variables) {
+  $text = $variables['text'];
+  $heading = $variables['heading'];
+  return "<p class=\"rules-i18n-help\"><strong>$heading:</strong> $text</p>";
+}
diff --git a/rules_i18n/rules_i18n.rules.inc b/rules_i18n/rules_i18n.rules.inc
new file mode 100644
index 0000000..045aa28
--- /dev/null
+++ b/rules_i18n/rules_i18n.rules.inc
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Internationalization rules integration.
+ */
+
+/**
+ * Implements hook_rules_evaluator_info().
+ */
+function rules_i18n_rules_evaluator_info() {
+  return array(
+    'i18n' => array(
+      'class' => 'RulesI18nStringEvaluator',
+      'type' => array('text', 'list<text>', 'token', 'list<token>'),
+      'weight' => -10,
+     ),
+  );
+}
+
+/**
+ * A class implementing a rules input evaluator processing tokens.
+ */
+class RulesI18nStringEvaluator extends RulesDataInputEvaluator {
+
+  public function prepare($text, $var_info, $param_info = NULL) {
+    if (!empty($param_info['translatable'])) {
+      $this->setting = TRUE;
+    }
+    else {
+      // Else, skip this evaluator.
+      $this->setting = NULL;
+    }
+  }
+
+  /**
+   * Prepare the i18n-context string.
+   *
+   * We have to use process() here instead of evaluate() because we need more
+   * context than evaluate() provides.
+   */
+  public function process($value, $info, RulesState $state, RulesPlugin $element, $options = NULL) {
+    $options = isset($options) ? $options : $this->getEvaluatorOptions($info, $state, $element);
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element, $options) : $value;
+    if (isset($element->root()->name)) {
+      $config_name = $element->root()->name;
+      $id = $element->elementId();
+      $name = $info['#name'];
+      $options['i18n context'] = "rules:rules_config:$config_name:$id:$name";
+      return $this->evaluate($value, $options, $state);
+    }
+    return $this->value;
+  }
+
+  /**
+   * Translate the value.
+   *
+   * If the element provides a language parameter, we are using this target
+   * language provided via $options['language'].
+   */
+  public function evaluate($value, $options, RulesState $state) {
+    $langcode = isset($options['language']) ? $options['language']->language : NULL;
+    return entity_i18n_string($options['i18n context'], $value, $langcode);
+  }
+
+  public static function help($var_info) {
+    $render = array(
+      '#theme' => 'rules_i18n_parameter_help',
+      '#text' => t('The provided value can be translated via String translation.'),
+      '#heading' => t('Internationalization'),
+    );
+    return $render;
+  }
+}
diff --git a/tests/rules.test b/tests/rules.test
index da0c8f5..000d9c1 100644
--- a/tests/rules.test
+++ b/tests/rules.test
@@ -70,6 +70,7 @@ class RulesTestCase extends DrupalWebTestCase {
     $it = new RecursiveIteratorIterator($rule->conditions());
     $this->assertEqual(iterator_count($it), 6, 'Iterated over all conditions');
     $this->assertEqual(iterator_count($rule->actions()), 1, 'Iterated over all actions');
+    $this->assertEqual(iterator_count($rule->elements()), 10, 'Iterated over all rule elements.');
 
     // Test getting dependencies and the integrity check.
     $rule->integrityCheck();
diff --git a/ui/ui.core.inc b/ui/ui.core.inc
index bc69ac4..3cf8c5b 100644
--- a/ui/ui.core.inc
+++ b/ui/ui.core.inc
@@ -887,7 +887,7 @@ class RulesContainerPluginUI extends RulesPluginUI {
     $form['elements']['#attributes']['class'][] = 'rules-container-plugin';
 
     // Recurse over all element childrens or use the provided iterator.
-    $iterator = isset($iterator) ? $iterator : new RecursiveIteratorIterator($this->element, RecursiveIteratorIterator::SELF_FIRST);
+    $iterator = isset($iterator) ? $iterator : $this->element->elements();
     $root_depth = $this->element->depth();
     foreach ($iterator as $key => $child) {
       $id = $child->elementId();
