diff --git components/select.inc components/select.inc
index e6074b9..e80a9d5 100644
--- components/select.inc
+++ components/select.inc
@@ -254,6 +254,15 @@ function _webform_edit_validate_options($element, &$form_state) {
 }
 
 /**
+ * Implementation of _webform_translate_component().
+ */
+function _webform_translate_select($component, $filter = TRUE, $update = FALSE) {
+  $options = _webform_select_options($component, !$component['extra']['aslist'], $filter);
+  $component['extra']['options_array'] = _webform_select_options_translate($component, $options, $update);
+  return $component;
+}
+
+/**
  * Implementation of _webform_render_component().
  */
 function _webform_render_select($component, $value = NULL, $filter = TRUE) {
@@ -271,7 +280,7 @@ function _webform_render_select($component, $value = NULL, $filter = TRUE) {
 
   // Convert the user-entered options list into an array.
   $default_value = $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'];
-  $options = _webform_select_options($component, !$component['extra']['aslist'], $filter);
+  $options = empty($component['extra']['options_array']) ? _webform_select_options($component, !$component['extra']['aslist'], $filter) : $component['extra']['options_array'];
 
   if ($component['extra']['optrand']) {
     _webform_shuffle_options($options);
@@ -757,6 +766,35 @@ function _webform_select_options($component, $flat = FALSE, $filter = TRUE) {
 }
 
 /**
+ * TODO
+ */
+function _webform_select_options_translate($component, $options, $update = FALSE) {
+  if (!webform_tt()) {
+    return FALSE;
+  }
+
+  $toptions = array();
+  $group_index = 0;
+
+  foreach ($options as $key => $value) {
+    if (is_array($value)) {
+      $group = $key;
+      $group = webform_tt("webform:component:{$component['cid']}:group:$group_index", $group, NULL, $update);
+      $group_index++;
+
+      foreach ($value as $key => $value) {
+        $toptions[$group][$key] = webform_tt("webform:component:{$component['cid']}:option:$key", $value, NULL, $update);
+      }
+    }
+    else {
+      $toptions[$key] = webform_tt("webform:component:{$component['cid']}:option:$key", $value, NULL, $update);
+    }
+  }
+
+  return $toptions;
+}
+
+/**
  * Load Webform select option info from 3rd party modules.
  */
 function _webform_select_options_info() {
diff --git components/textfield.inc components/textfield.inc
index 1512baa..e25e327 100644
--- components/textfield.inc
+++ components/textfield.inc
@@ -118,6 +118,21 @@ function _webform_edit_textfield($component) {
 }
 
 /**
+ * Implementation of _webform_translate_component().
+ */
+function _webform_translate_textfield($component, $filter = TRUE, $update = FALSE) {
+  if (!empty($component['value'])) {
+    $component['value'] = webform_tt("webform:component:{$component['cid']}:value", $component['value'], NULL, $update);
+  }
+  foreach (array('field_prefix', 'field_suffix') as $field) {
+    if (!empty($component['extra'][$field])) {
+      $component['extra'][$field] = webform_tt("webform:component:{$component['cid']}:$field", $component['extra'][$field], NULL, $update);
+    }
+  }
+  return $component;
+}
+
+/**
  * Implementation of _webform_render_component().
  */
 function _webform_render_textfield($component, $value = NULL, $filter = TRUE) {
diff --git includes/webform.components.inc includes/webform.components.inc
index 09c8081..4a60c11 100644
--- includes/webform.components.inc
+++ includes/webform.components.inc
@@ -603,6 +603,13 @@ function webform_component_edit_form_submit($form, &$form_state) {
     $cid = webform_component_insert($form_state['values']);
   }
 
+  // Create the translation sources for the component.
+  webform_component_translate($form_state['values'], TRUE, TRUE);
+  // TODO
+  if (webform_translation_supported_type($node)) {
+    webform_component_translation_sync($node, $form_state['values'], isset($cid));
+  }
+
   // Since Webform components have been updated but the node itself has not
   // been saved, it is necessary to explicitly clear the cache to make sure
   // the updated webform is visible to anonymous users.
@@ -746,6 +753,34 @@ function webform_component_clone(&$node, &$component) {
 }
 
 /**
+ * Translate the given component.
+ * TODO
+ */
+function webform_component_translate($component, $filter = TRUE, $update = FALSE) {
+  if (webform_tt()) {
+    $tcomponent = webform_component_invoke($component['type'], 'translate', $component, $filter, $update);
+    if (!isset($tcomponent)) {
+      $tcomponent = $component; 
+    }
+    $tcomponent['name'] = webform_tt("webform:component:{$component['cid']}:name", $component['name'], NULL, $update);
+    if (!empty($tcomponent['extra']['description'])) {
+      $tcomponent['extra']['description'] = webform_tt("webform:component:{$component['cid']}:description", $component['extra']['description'], NULL, $update);
+    }
+  }
+  else {
+    $tcomponent = $component;
+  }
+  return $tcomponent;
+}
+
+/**
+ * TODO
+ */
+function webform_component_translation_sync($node, $component, $insert = FALSE) {
+  webform_translation_sync($node, $component, 'webform_component', $insert);
+}
+
+/**
  * Check if a component has a particular feature.
  */
 function webform_component_feature($type, $feature) {
diff --git includes/webform.emails.inc includes/webform.emails.inc
index 224342c..2d5be84 100644
--- includes/webform.emails.inc
+++ includes/webform.emails.inc
@@ -400,10 +400,12 @@ function webform_email_edit_form_validate($form, &$form_state) {
  * Submit handler for webform_email_edit_form().
  */
 function webform_email_edit_form_submit($form, &$form_state) {
+  $node = $form_state['values']['node'];
+
   // Merge the e-mail, name, address, and subject options into single values.
   $email = array(
     'eid' => $form_state['values']['eid'],
-    'nid' => $form_state['values']['node']->nid,
+    'nid' => $node->nid,
   );
 
   foreach (array('email', 'from_name', 'from_address', 'subject') as $field) {
@@ -437,19 +439,31 @@ function webform_email_edit_form_submit($form, &$form_state) {
   // We actually maintain an *exclusion* list, so any new components will
   // default to being included in the %email_values token until unchecked.
   $included = array_keys(array_filter((array) $form_state['values']['components']));
-  $excluded = array_diff(array_keys($form_state['values']['node']->webform['components']), $included);
+  $excluded = array_diff(array_keys($node->webform['components']), $included);
   $email['excluded_components'] = $excluded;
 
   if (empty($form_state['values']['eid'])) {
     drupal_set_message(t('Email settings added.'));
-    $cid = webform_email_insert($email);
+    $eid = webform_email_insert($email);
   }
   else {
     drupal_set_message(t('Email settings updated.'));
     webform_email_update($email);
   }
 
-  $form_state['redirect'] = array('node/' . $form_state['values']['node']->nid . '/webform/emails');
+  // TODO
+  if (webform_translation_supported_type($node)) {
+    webform_email_translation_sync($node, $email, isset($eid));
+  }
+
+  $form_state['redirect'] = array('node/' . $node->nid . '/webform/emails');
+}
+
+/**
+ * TODO
+ */
+function webform_email_translation_sync($node, $email, $insert = FALSE) {
+  webform_translation_sync($node, $email, 'webform_email', $insert);
 }
 
 /**
diff --git includes/webform.pages.inc includes/webform.pages.inc
index 8585d59..bf13634 100644
--- includes/webform.pages.inc
+++ includes/webform.pages.inc
@@ -270,6 +270,11 @@ function webform_configure_form_submit($form, &$form_state) {
 
   node_save($node);
 
+  // TODO
+  if (webform_translation_supported_type($node)) {
+    webform_node_translation_sync($node);
+  }
+
   drupal_set_message(t('The form settings have been updated.'));
 }
 
diff --git includes/webform.report.inc includes/webform.report.inc
index 3be3da0..edf619d 100644
--- includes/webform.report.inc
+++ includes/webform.report.inc
@@ -17,6 +17,11 @@ module_load_include('inc', 'webform', 'includes/webform.submissions');
 function webform_results_submissions($node, $user_filter, $pager_count) {
   global $user;
 
+  $nid = $node->nid;
+  if (webform_translation_supported_type($node)) {
+    $node = node_load($node->tnid);
+  }
+
   if (isset($_GET['results']) && is_numeric($_GET['results'])) {
     $pager_count = $_GET['results'];
   }
@@ -76,6 +81,11 @@ function webform_results_submissions($node, $user_filter, $pager_count) {
     $rows[] = $row;
   }
 
+  // Restore the original node if no submission is found.
+  if (empty($rows) && webform_translation_supported_type($node)) {
+    $node = node_load($nid);
+  }
+
   $element['#theme'] = 'webform_results_submissions';
   $element['#node'] = $node;
   $element['#submissions'] = $submissions;
@@ -173,6 +183,10 @@ function template_preprocess_webform_results_submissions(&$vars) {
  * Create a table containing all submitted values for a webform node.
  */
 function webform_results_table($node, $pager_count = 0) {
+  if (webform_translation_supported_type($node)) {
+    $node = node_load($node->tnid);
+  }
+
   if (isset($_GET['results']) && is_numeric($_GET['results'])) {
     $pager_count = $_GET['results'];
   }
@@ -290,8 +304,8 @@ function webform_results_clear_form($form_state, $node) {
 }
 
 function webform_results_clear_form_submit($form, &$form_state) {
-  webform_results_clear($form_state['values']['nid']);
   $node = node_load($form_state['values']['nid']);
+  webform_results_clear(webform_translation_supported_type($node) ? $node->tnid : $node->nid);
   $title = $node->title;
 
   $message = t('Webform %title entries cleared.', array('%title' => $title));
@@ -307,6 +321,10 @@ function webform_results_download_form(&$form_state, $node) {
   module_load_include('inc', 'webform', 'includes/webform.export');
   module_load_include('inc', 'webform', 'includes/webform.components');
 
+  if (webform_translation_supported_type($node)) {
+    $node = node_load($node->tnid);
+  }
+
   $form = array();
 
   $form['node'] = array(
@@ -632,6 +650,10 @@ function webform_results_download($node, $format = 'delimiter', $options = array
  *   "Other" values within a select list.
  */
 function webform_results_analysis($node, $sids = array(), $analysis_component = NULL) {
+  if (webform_translation_supported_type($node)) {
+    $node = node_load($node->tnid);
+  }
+
   if (!is_array($sids)) {
     $sids = array();
   }
diff --git webform.module webform.module
index 9403f01..9d88ba3 100644
--- webform.module
+++ webform.module
@@ -1084,18 +1084,7 @@ function webform_node_load($node) {
   $result = db_query('SELECT * FROM {webform_component} WHERE nid = %d ORDER BY weight, name', $node->nid);
   while ($c = db_fetch_array($result)) {
     $component =& $additions['webform']['components'][$c['cid']];
-    $component['nid'] = $node->nid;
-    $component['cid'] = $c['cid'];
-    $component['form_key'] = $c['form_key'] ? $c['form_key'] : $c['cid'];
-    $component['name'] = t($c['name']);
-    $component['type'] = $c['type'];
-    $component['value'] = $c['value'];
-    $component['extra'] = unserialize($c['extra']);
-    $component['mandatory'] = $c['mandatory'];
-    $component['pid'] = $c['pid'];
-    $component['weight'] = $c['weight'];
-
-    webform_component_defaults($component);
+    webform_component_init($component, $c);
   }
 
   // Organize the components into a fieldset-based order.
@@ -1109,6 +1098,24 @@ function webform_node_load($node) {
 }
 
 /**
+ * TODO
+ */
+function webform_component_init(&$component, $data) {
+  $component['nid'] = $data['nid'];
+  $component['cid'] = $data['cid'];
+  $component['form_key'] = $data['form_key'] ? $data['form_key'] : $data['cid'];
+  $component['name'] = $data['name'];
+  $component['type'] = $data['type'];
+  $component['value'] = $data['value'];
+  $component['extra'] = unserialize($data['extra']);
+  $component['mandatory'] = $data['mandatory'];
+  $component['pid'] = $data['pid'];
+  $component['weight'] = $data['weight'];
+
+  webform_component_defaults($component);
+}
+
+/**
  * Implementation of hook_link().
  * Always add a "view form" link.
  */
@@ -1758,6 +1765,9 @@ function _webform_client_form_rule_check($node, $component, $page_num, $form_sta
 function _webform_client_form_add_component($node, $component, $component_value, &$parent_fieldset, &$form, $form_state, $submission, $format = 'form', $page_num = 0, $filter = TRUE) {
   $cid = $component['cid'];
 
+  // Translate the current component.
+  $component = webform_component_translate($component, $filter);
+
   // Load with submission information if necessary.
   if ($format != 'form') {
     // This component is display only.
@@ -2030,7 +2040,13 @@ function webform_client_form_submit($form, &$form_state) {
     return;
   }
 
-  $node = $form['#node'];
+  $node = node_load($form_state['values']['details']['nid']);
+  $nid = $form_state['values']['details']['nid'];
+  $node = node_load($nid);
+ 
+  if (webform_translation_supported_type($node)) {
+    $node = node_load($node->tnid);
+  }
 
   // Check if user is submitting as a draft.
   $is_draft = $form_state['values']['op'] == t('Save Draft');
@@ -2210,7 +2226,7 @@ function webform_client_form_submit($form, &$form_state) {
     $redirect = NULL;
   }
   elseif ($redirect_url == '<confirmation>') {
-    $redirect = array('node/' . $node->nid . '/done', 'sid=' . $sid);
+    $redirect = array('node/' . $nid . '/done', 'sid=' . $sid);
   }
   elseif (valid_url($redirect_url, TRUE)) {
     $redirect = $redirect_url;
@@ -3099,11 +3115,48 @@ function webform_set_breadcrumb($node, $submission = NULL) {
 }
 
 /**
+ * Implementation of hook_locale().
+ */
+function webform_locale($op = 'groups', $group = NULL) {
+  switch ($op) {
+    case 'groups':
+      return array('webform' => t('Webform'));
+    case 'info':
+      $info['webform']['refresh callback'] = 'webform_locale_refresh';
+      $info['webform']['format'] = FALSE;
+      return $info;
+  }
+}
+
+/**
+ * Refresh locale strings.
+ */
+function webform_locale_refresh() {
+  module_load_include('inc', 'webform', 'includes/webform.components');
+
+  $result = db_query('SELECT * FROM {webform_component}');
+  while ($c = db_fetch_array($result)) {
+    $component = array();
+    webform_component_init($component, $c);
+    webform_component_translate($component, TRUE, TRUE);
+  }
+
+  return TRUE;
+}
+
+/**
  * Wrapper function for tt() if i18nstrings enabled.
  */
-function webform_tt($name, $string, $langcode = NULL, $update = FALSE) {
-  if (function_exists('tt')) {
-    return tt($name, $string, $langcode, $update);
+function webform_tt($name = NULL, $string = NULL, $langcode = NULL, $update = FALSE) {
+  $translate = function_exists('i18nstrings');
+  if (empty($name)) {
+    return $translate;
+  }
+  elseif ($translate) {
+    if ($update) {
+      i18nstrings_update($name, $string);
+    }
+    return i18nstrings($name, $string, $langcode);
   }
   else {
     return $string;
@@ -3111,6 +3164,52 @@ function webform_tt($name, $string, $langcode = NULL, $update = FALSE) {
 }
 
 /**
+ * TODO
+ */
+function webform_translation_supported_type($node) {
+  // TODO: content type option
+  return webform_tt();
+}
+
+/**
+ * TODO
+ */
+function webform_translation_sync($node, $data, $store_callback, $insert = FALSE) {
+  if ($translations = translation_node_get_translations($node->tnid)) {
+    unset($translations[$node->language]);
+    $store_callback .= '_'. ($insert ? 'insert' : 'update');
+    $count = 0;
+
+    foreach ($translations as $langcode => $translation) {
+      $data['nid'] = $translation->nid;
+      $store_callback($data);
+      $count++;
+    }
+
+    drupal_set_message(format_plural($count, 'One webform translation has been synchronized.', 'All @count webform translations have been synchronized.'));
+  }
+}
+
+/**
+ * TODO
+ */
+function webform_node_translation_sync($node) {
+  if ($translations = translation_node_get_translations($node->tnid)) {
+    unset($translations[$node->language]);
+    $count = 0;
+
+    foreach ($translations as $langcode => $translation) {
+      $translation = node_load($translation->nid);
+      $translation->webform = $node->webform;
+      node_save($translation);
+      $count++;
+    }
+
+    drupal_set_message(format_plural($count, 'One webform translation has been synchronized.', 'All @count webform translations have been synchronized.'));
+  }
+}
+
+/**
  * Implementation of hook_views_api().
  */
 function webform_views_api() {
