Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.542
diff -u -p -r1.542 book.module
--- modules/book/book.module	6 May 2010 05:59:31 -0000	1.542
+++ modules/book/book.module	20 May 2010 03:43:44 -0000
@@ -403,7 +403,7 @@ function book_get_books() {
 function book_form_alter(&$form, &$form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
     // Add elements to the node form.
-    $node = $form['#node'];
+    $node = $form_state['node'];
 
     $access = user_access('administer book outlines');
     if (!$access) {
@@ -415,15 +415,13 @@ function book_form_alter(&$form, &$form_
 
     if ($access) {
       _book_add_form_elements($form, $form_state, $node);
+      // Since the "Book" dropdown can't trigger a form submission when
+      // JavaScript is disabled, add a submit button to do that. book.css hides
+      // this button when JavaScript is enabled.
       $form['book']['pick-book'] = array(
         '#type' => 'submit',
         '#value' => t('Change book (update list of parents)'),
-         // Submit the node form so the parent select options get updated.
-         // This is typically only used when JS is disabled. Since the parent options
-         // won't be changed via AJAX, a button is provided in the node form to submit
-         // the form and generate options in the parent select corresponding to the
-         // selected book. This is similar to what happens during a node preview.
-        '#submit' => array('node_form_submit_build_node'),
+        '#submit' => array('book_pick_book_nojs_submit'),
         '#weight' => 20,
       );
     }
@@ -431,6 +429,22 @@ function book_form_alter(&$form, &$form_
 }
 
 /**
+ * Submit handler to change a node's book.
+ *
+ * This handler is run when JavaScript is disabled. It triggers the form to
+ * rebuild so that the "Parent item" options are changed to reflect the newly
+ * selected book. When JavaScript is enabled, the submit button that triggers
+ * this handler is hidden, and the "Book" dropdown directly triggers the
+ * book_form_update() AJAX callback instead.
+ *
+ * @see book_form_update()
+ */
+function book_pick_book_nojs_submit($form, &$form_state) {
+  $form_state['node']->book = $form_state['values']['book'];
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
  * Build the parent selection form element for the node form or outline tab.
  *
  * This function is also called when generating a new set of options during the
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.875
diff -u -p -r1.875 comment.module
--- modules/comment/comment.module	10 May 2010 20:12:21 -0000	1.875
+++ modules/comment/comment.module	20 May 2010 03:43:44 -0000
@@ -1138,7 +1138,7 @@ function comment_form_node_type_form_alt
  */
 function comment_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
-    $node = $form['#node'];
+    $node = $form_state['node'];
     $form['comment_settings'] = array(
       '#type' => 'fieldset',
       '#access' => user_access('administer comments'),
Index: modules/field/field.form.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.form.inc,v
retrieving revision 1.48
diff -u -p -r1.48 field.form.inc
--- modules/field/field.form.inc	30 Apr 2010 08:07:54 -0000	1.48
+++ modules/field/field.form.inc	20 May 2010 03:43:45 -0000
@@ -368,17 +368,22 @@ function field_default_form_errors($enti
  * to return just the changed part of the form.
  */
 function field_add_more_submit($form, &$form_state) {
-  // Set the form to rebuild and run submit handlers.
+  // @todo Legacy entity forms assume that #builder_function is called from all
+  //   button-level submit handlers that trigger a rebuild. This is poor
+  //   encapsulation and can lead to security vulnerabilities when used in
+  //   conjunction with #limit_validation_errors. Node forms have been fixed,
+  //   but some entity forms still rely on this. Remove this once all entity
+  //   forms have been fixed: http://drupal.org/node/735800.
   if (isset($form['#builder_function']) && function_exists($form['#builder_function'])) {
-    $entity = $form['#builder_function']($form, $form_state);
-
-    // Make the changes we want to the form state.
-    $field_name = $form_state['clicked_button']['#field_name'];
-    $langcode = $form_state['clicked_button']['#language'];
-    if ($form_state['values'][$field_name . '_add_more']) {
-      $form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name][$langcode]);
-    }
+    $form['#builder_function']($form, $form_state);
+  }
+  // Make the changes we want to the form state and trigger a rebuild.
+  $field_name = $form_state['clicked_button']['#field_name'];
+  $langcode = $form_state['clicked_button']['#language'];
+  if ($form_state['values'][$field_name . '_add_more']) {
+    $form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name][$langcode]);
   }
+  $form_state['rebuild'] = TRUE;
 }
 
 /**
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.293
diff -u -p -r1.293 locale.module
--- modules/locale/locale.module	12 May 2010 08:26:14 -0000	1.293
+++ modules/locale/locale.module	20 May 2010 03:43:46 -0000
@@ -389,16 +389,16 @@ function locale_form_alter(&$form, &$for
     }
   }
   if (!empty($form['#node_edit_form'])) {
-    if (isset($form['#node']->type) && locale_multilingual_node_type($form['#node']->type)) {
+    if (isset($form_state['node']->type) && locale_multilingual_node_type($form_state['node']->type)) {
       $form['language'] = array(
         '#type' => 'select',
         '#title' => t('Language'),
-        '#default_value' => (isset($form['#node']->language) ? $form['#node']->language : ''),
+        '#default_value' => (isset($form_state['node']->language) ? $form_state['node']->language : ''),
         '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
       );
     }
     // Node type without language selector: assign the default for new nodes
-    elseif (!isset($form['#node']->nid)) {
+    elseif (!isset($form_state['node']->nid)) {
       $default = language_default();
       $form['language'] = array(
         '#type' => 'value',
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.229
diff -u -p -r1.229 menu.module
--- modules/menu/menu.module	7 Mar 2010 07:55:14 -0000	1.229
+++ modules/menu/menu.module	20 May 2010 03:43:46 -0000
@@ -589,14 +589,13 @@ function menu_form_alter(&$form, $form_s
   if (!empty($form['#node_edit_form'])) {
     // Generate a list of possible parents.
     // @todo This must be handled in a #process handler.
-    $type = $form['#node']->type;
+    $type = $form_state['node']->type;
     $options = menu_parent_options(menu_get_menus(), $type);
     // If no possible parent menu items were found, there is nothing to display.
     if (empty($options)) {
       return;
     }
-    $link = $form['#node']->menu;
-    $form['#submit'][] = 'menu_node_form_submit';
+    $link = $form_state['node']->menu;
 
     $form['menu'] = array(
       '#type' => 'fieldset',
@@ -661,15 +660,13 @@ function menu_form_alter(&$form, $form_s
 }
 
 /**
- * Submit handler for node form.
- *
- * @see menu_form_alter()
+ * Implementation of hook_node_submit().
  */
-function menu_node_form_submit($form, &$form_state) {
+function menu_node_submit($node, $form, &$form_state) {
   // Decompose the selected menu parent option into 'menu_name' and 'plid', if
   // the form used the default parent selection widget.
   if (!empty($form_state['values']['menu']['parent'])) {
-    list($form_state['values']['menu']['menu_name'], $form_state['values']['menu']['plid']) = explode(':', $form_state['values']['menu']['parent']);
+    list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
   }
 }
 
Index: modules/node/node.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.api.php,v
retrieving revision 1.67
diff -u -p -r1.67 node.api.php
--- modules/node/node.api.php	5 May 2010 06:55:25 -0000	1.67
+++ modules/node/node.api.php	20 May 2010 03:43:46 -0000
@@ -666,13 +666,19 @@ function hook_node_update_index($node) {
  * the node at the validate stage, you can use form_set_value().
  *
  * @param $node
- *   The node being validated.
+ *   The node being validated. This is an object representation of
+ *   $form_state['values'] only. It does not contain node properties from
+ *   node_load() or node_object_prepare() that do not have corresponding entries
+ *   in $form_state['values']. $form_state['node'] can be used to access the
+ *   node properties not being edited by the form.
  * @param $form
  *   The form being used to edit the node.
+ * @param $form_state
+ *   The form state array.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_validate($node, $form) {
+function hook_node_validate($node, $form, &$form_state) {
   if (isset($node->end) && isset($node->start)) {
     if ($node->start > $node->end) {
       form_set_error('time', t('An event may not end before it starts.'));
@@ -681,6 +687,37 @@ function hook_node_validate($node, $form
 }
 
 /**
+ * Update the node object based on submitted form values.
+ *
+ * This hook is called when the "Save" or "Preview" button of a node editing
+ * form is clicked. It may also be called during other button-clicks if the
+ * submit handler for that button requires an updated node object.
+ *
+ * Modules may use this hook to extract their data from $form_state and set it
+ * on the $node object. Note that every key/value pair in $form_state['values']
+ * is automatically added as a corresponding property/value pair in $node, so
+ * modules only need to implement this hook to do something different than that.
+ *
+ * @param $node
+ *   The node being built from data in $form_state.
+ * @param $form
+ *   The form being used to edit the node.
+ * @param $form_state
+ *   The form state array.
+ *
+ * @see node_form_submit_update_node()
+ *
+ * @ingroup node_api_hooks
+ */
+function hook_node_submit($node, $form, $form_state) {
+  // Decompose the selected menu parent option into 'menu_name' and 'plid', if
+  // the form used the default parent selection widget.
+  if (!empty($form_state['values']['menu']['parent'])) {
+    list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
+  }
+}
+
+/**
  * Act on a node that is being assembled before rendering.
  *
  * The module may add elements to $node->content prior to rendering. This hook
@@ -1104,10 +1141,12 @@ function hook_update($node) {
  *   The node being validated.
  * @param $form
  *   The form being used to edit the node.
+ * @param $form_state
+ *   The form state array.
  *
  * @ingroup node_api_hooks
  */
-function hook_validate($node, &$form) {
+function hook_validate($node, $form, &$form_state) {
   if (isset($node->end) && isset($node->start)) {
     if ($node->start > $node->end) {
       form_set_error('time', t('An event may not end before it starts.'));
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1273
diff -u -p -r1.1273 node.module
--- modules/node/node.module	17 May 2010 07:43:36 -0000	1.1273
+++ modules/node/node.module	20 May 2010 03:43:46 -0000
@@ -907,7 +907,7 @@ function node_object_prepare($node) {
 /**
  * Perform validation checks on the given node.
  */
-function node_validate($node, $form = array()) {
+function node_validate($node, $form = array(), &$form_state = NULL) {
   $type = node_type_get_type($node);
 
   if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
@@ -927,15 +927,24 @@ function node_validate($node, $form = ar
     form_set_error('date', t('You have to specify a valid date.'));
   }
 
-  // Do node-type-specific validation checks.
-  node_invoke($node, 'validate', $form);
-  module_invoke_all('node_validate', $node, $form);
+  // Invoke node-type specific validation, field validation, and
+  // hook_node_validate(). Can't use node_invoke() or module_invoke_all(),
+  // because the invoked functions need to receive $form_state by reference.
+  $function = node_type_get_base($node) . '_validate';
+  if (function_exists($function)) {
+    $function($node, $form, $form_state);
+  }
+  field_attach_form_validate('node', $node, $form, $form_state);
+  foreach (module_implements('node_validate') as $module) {
+    $function = $module . '_node_validate';
+    $function($node, $form, $form_state);
+  }
 }
 
 /**
- * Prepare node for saving by populating author and creation date.
+ * Prepare a node for saving or previewing after its editing form has been submitted.
  */
-function node_submit($node) {
+function node_submit($node, $form = array(), &$form_state = NULL) {
   global $user;
 
   // A user might assign the node author by entering a user name in the node
@@ -952,6 +961,23 @@ function node_submit($node) {
   $node->created = !empty($node->date) ? strtotime($node->date) : REQUEST_TIME;
   $node->validated = TRUE;
 
+  // Invoke node-type specific and field-level submit handlers, and
+  // hook_node_submit(). Can't use node_invoke() or module_invoke_all(),
+  // because the invoked functions need to receive $form_state by reference.
+  // Support legacy modules that call node_submit() without passing $form and
+  // $form_state and that do not expect the extra hooks to be called.
+  if (isset($form_state)) {
+    $function = node_type_get_base($node) . '_submit';
+    if (function_exists($function)) {
+      $function($node, $form, $form_state);
+    }
+    field_attach_submit('node', $node, $form, $form_state);
+    foreach (module_implements('node_submit') as $module) {
+      $function = $module . '_node_submit';
+      $function($node, $form, $form_state);
+    }
+  }
+
   return $node;
 }
 
Index: modules/node/node.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v
retrieving revision 1.126
diff -u -p -r1.126 node.pages.inc
--- modules/node/node.pages.inc	10 May 2010 06:34:39 -0000	1.126
+++ modules/node/node.pages.inc	20 May 2010 03:43:46 -0000
@@ -75,13 +75,21 @@ function node_add($type) {
   return $output;
 }
 
+/**
+ * Validate the node add/edit form.
+ */
 function node_form_validate($form, &$form_state) {
+  // @todo node_submit() and the hooks that it calls receive the full node
+  //   as the $node parameter. For consistency and to enable advanced form
+  //   workflows and validation, it would be ideal for the same to be true for
+  //   node_validate(). However, there are various obstacles to this, and until
+  //   they're resolved, we pass a pseudo node object that only contains the
+  //   data being edited. See http://drupal.org/node/367006#comment-2601522.
   $node = (object) $form_state['values'];
-  node_validate($node, $form);
 
-  // Field validation. Requires access to $form_state, so this cannot be
-  // done in node_validate() as it currently exists.
-  field_attach_form_validate('node', $node, $form, $form_state);
+  // This performs default validation, field validation, and calls
+  // hook_node_validate().
+  node_validate($node, $form, $form_state);
 }
 
 /**
@@ -89,14 +97,17 @@ function node_form_validate($form, &$for
  */
 function node_form($form, &$form_state, $node) {
   global $user;
-  // This form has its own multistep persistence.
-  if ($form_state['rebuild']) {
-    $form_state['input'] = array();
-  }
 
+  // If the form is being rebuilt after a submit handler updated
+  // $form_state['node'], use that. Otherwise, initialize $form_state['node']
+  // with the node object passed as a build argument.
   if (isset($form_state['node'])) {
-    $node = (object) ($form_state['node'] + (array) $node);
+    $node = $form_state['node'];
   }
+  else {
+    $form_state['node'] = $node;
+  }
+
   if (isset($form_state['node_preview'])) {
     $form['#prefix'] = $form_state['node_preview'];
   }
@@ -141,7 +152,8 @@ function node_form($form, &$form_state, 
     $form['title']['#weight'] = -5;
   }
 
-  $form['#node'] = $node;
+  // @todo Legacy support. Remove in Drupal 8.
+  $form['#node'] = $form_state['node'];
 
   $form['additional_settings'] = array(
     '#type' => 'vertical_tabs',
@@ -278,7 +290,6 @@ function node_form($form, &$form_state, 
   }
   $form['#validate'][] = 'node_form_validate';
 
-  $form['#builder_function'] = 'node_form_submit_build_node';
   field_attach_form('node', $node, $form, $form_state, $node->language);
 
   return $form;
@@ -293,14 +304,15 @@ function node_form_delete_submit($form, 
     $destination = drupal_get_destination();
     unset($_GET['destination']);
   }
-  $node = $form['#node'];
+  $node = $form_state['node'];
   $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
 }
 
 
 function node_form_build_preview($form, &$form_state) {
-  $node = node_form_submit_build_node($form, $form_state);
-  $form_state['node_preview'] = node_preview($node);
+  node_form_submit_update_node($form, $form_state);
+  $form_state['node_preview'] = node_preview($form_state['node']);
+  $form_state['rebuild'] = TRUE;
 }
 
 /**
@@ -382,7 +394,8 @@ function theme_node_preview($variables) 
 }
 
 function node_form_submit($form, &$form_state) {
-  $node = node_form_submit_build_node($form, $form_state);
+  node_form_submit_update_node($form, $form_state);
+  $node = $form_state['node'];
   $insert = empty($node->nid);
   node_save($node);
   $node_link = l(t('view'), 'node/' . $node->nid);
@@ -398,7 +411,6 @@ function node_form_submit($form, &$form_
     drupal_set_message(t('@type %title has been updated.', $t_args));
   }
   if ($node->nid) {
-    unset($form_state['rebuild']);
     $form_state['values']['nid'] = $node->nid;
     $form_state['nid'] = $node->nid;
     $form_state['redirect'] = 'node/' . $node->nid;
@@ -407,26 +419,58 @@ function node_form_submit($form, &$form_
     // In the unlikely case something went wrong on save, the node will be
     // rebuilt and node form redisplayed the same way as in preview.
     drupal_set_message(t('The post could not be saved.'), 'error');
+    $form_state['rebuild'] = TRUE;
   }
   // Clear the page and block caches.
   cache_clear_all();
 }
 
 /**
- * Build a node by processing submitted form values and prepare for a form rebuild.
+ * Update the node object represented by the form.
+ *
+ * This function is called by submit handlers of buttons on a node editing form
+ * that require the node object represented by the form to be updated based on
+ * the submitted form values. For example, the submit handler of the "Save"
+ * button requires an updated node object to save to the database, and the
+ * submit handler of the "Preview" button requires an updated node object to
+ * preview. Other modules may add additional buttons with submit handlers that
+ * similarly require an updated node object.
+ *
+ * This function invokes submit handlers that assume a fully validated form, so
+ * do not call this function from button-level submit handlers of buttons that
+ * use #limit_validation_errors. Such submit handlers need to either update the
+ * node object themselves with data that has been validated (see
+ * poll_more_choices_submit()) or not update the node object at all if the
+ * form can be successfully rebuilt using the Form APIs default mechanism of
+ * retaining user input during a rebuild (see field_add_more_submit()).
+ *
+ * @param $form
+ *   The form being submitted.
+ * @param $form_state
+ *   The form state array. $form_state['node'] contains the node object that
+ *   needs to be updated.
  */
-function node_form_submit_build_node($form, &$form_state) {
-  // Unset any button-level handlers, execute all the form-level submit
-  // functions to process the form values into an updated node.
+function node_form_submit_update_node($form, &$form_state) {
+  // @todo Legacy support for modules that use a form-level submit handler to
+  //   extend the node being built. For the node to be built properly during a
+  //   multistep workflow, we must call these handlers even when this function
+  //   is called from a button-level submit handler (e.g.,
+  //   node_form_build_preview()). Module authors are encouraged to convert to
+  //   using hook_node_submit(). Remove this in Drupal 8.
   unset($form_state['submit_handlers']);
   form_execute_handlers('submit', $form, $form_state);
-  $node = node_submit((object) $form_state['values']);
 
-  field_attach_submit('node', $node, $form, $form_state);
+  // The node may contain properties not being edited by the form, and these
+  // must not be wiped. For anything that is being edited by the form, update
+  // the node with the new values.
+  $node = $form_state['node'];
+  foreach ($form_state['values'] as $key => $value) {
+    $node->$key = $value;
+  }
 
-  $form_state['node'] = (array) $node;
-  $form_state['rebuild'] = TRUE;
-  return $node;
+  // This invokes all the necessary hooks to allow modules to customize the node
+  // beyond the simple mapping done above.
+  node_submit($node, $form, $form_state);
 }
 
 /**
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.183
diff -u -p -r1.183 path.module
--- modules/path/path.module	13 Feb 2010 21:41:58 -0000	1.183
+++ modules/path/path.module	20 May 2010 03:43:47 -0000
@@ -99,10 +99,10 @@ function path_menu() {
 function path_form_alter(&$form, $form_state, $form_id) {
   if (!empty($form['#node_edit_form'])) {
     $path = array();
-    if (!empty($form['#node']->nid)) {
-      $conditions = array('source' => 'node/' . $form['#node']->nid);
-      if ($form['#node']->language != LANGUAGE_NONE) {
-        $conditions['language'] = $form['#node']->language;
+    if (!empty($form_state['node']->nid)) {
+      $conditions = array('source' => 'node/' . $form_state['node']->nid);
+      if ($form_state['node']->language != LANGUAGE_NONE) {
+        $conditions['language'] = $form_state['node']->language;
       }
       $path = path_load($conditions);
       if ($path === FALSE) {
@@ -111,9 +111,9 @@ function path_form_alter(&$form, $form_s
     }
     $path += array(
       'pid' => NULL,
-      'source' => isset($form['#node']->nid) ? 'node/' . $form['#node']->nid : NULL,
+      'source' => isset($form_state['node']->nid) ? 'node/' . $form_state['node']->nid : NULL,
       'alias' => '',
-      'language' => isset($form['#node']->language) ? $form['#node']->language : LANGUAGE_NONE,
+      'language' => isset($form_state['node']->language) ? $form_state['node']->language : LANGUAGE_NONE,
     );
 
     $form['path'] = array(
Index: modules/poll/poll.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v
retrieving revision 1.348
diff -u -p -r1.348 poll.module
--- modules/poll/poll.module	9 May 2010 13:37:32 -0000	1.348
+++ modules/poll/poll.module	20 May 2010 03:43:47 -0000
@@ -352,15 +352,18 @@ function poll_form($node, &$form_state) 
  * return just the changed part of the form.
  */
 function poll_more_choices_submit($form, &$form_state) {
-  include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'node') . '/node.pages.inc';
-  // Set the form to rebuild and run submit handlers.
-  node_form_submit_build_node($form, $form_state);
-
   // Make the changes we want to the form state.
   if ($form_state['values']['poll_more']) {
     $n = $_GET['q'] == 'system/ajax' ? 1 : 5;
     $form_state['choice_count'] = count($form_state['values']['choice']) + $n;
   }
+  // Renumber the choices. This invalidates the corresponding key/value
+  // associations in $form_state['input'], so clear that out. This requires
+  // poll_form() to rebuild the choices with the values in
+  // $form_state['node']->choice, which it does.
+  $form_state['node']->choice = array_values($form_state['values']['choice']);
+  unset($form_state['input']['choice']);
+  $form_state['rebuild'] = TRUE;
 }
 
 function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) {
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.167
diff -u -p -r1.167 system.api.php
--- modules/system/system.api.php	7 May 2010 12:59:07 -0000	1.167
+++ modules/system/system.api.php	20 May 2010 03:43:48 -0000
@@ -1255,7 +1255,7 @@ function hook_page_alter(&$page) {
  * Perform alterations before a form is rendered.
  *
  * One popular use of this hook is to add form elements to the node form. When
- * altering a node form, the node object can be accessed at $form['#node'].
+ * altering a node form, the node object can be accessed at $form_state['node'].
  *
  * Note that instead of hook_form_alter(), which is called for all forms, you
  * can also use hook_form_FORM_ID_alter() to alter a specific form. For each
Index: modules/translation/translation.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/translation/translation.module,v
retrieving revision 1.79
diff -u -p -r1.79 translation.module
--- modules/translation/translation.module	16 Apr 2010 13:52:23 -0000	1.79
+++ modules/translation/translation.module	20 May 2010 03:43:48 -0000
@@ -124,8 +124,8 @@ function translation_form_node_type_form
  *   is about to be created.
  */
 function translation_form_alter(&$form, &$form_state, $form_id) {
-  if (!empty($form['#node_edit_form']) && translation_supported_type($form['#node']->type)) {
-    $node = $form['#node'];
+  if (!empty($form['#node_edit_form']) && translation_supported_type($form_state['node']->type)) {
+    $node = $form_state['node'];
     if (!empty($node->translation_source)) {
       // We are creating a translation. Add values and lock language field.
       $form['translation_source'] = array('#type' => 'value', '#value' => $node->translation_source);
@@ -315,10 +315,12 @@ function translation_node_update($node) 
  *
  * Ensure that duplicate translations can not be created for the same source.
  */
-function translation_node_validate($node, $form) {
+function translation_node_validate($node, $form, $form_state) {
   // Only act on translatable nodes with a tnid or translation_source.
-  if (translation_supported_type($node->type) && (!empty($node->tnid) || !empty($form['#node']->translation_source->nid))) {
-    $tnid = !empty($node->tnid) ? $node->tnid : $form['#node']->translation_source->nid;
+  // Use $form_state['node'] instead of $node for information about the node not
+  // being edited by this form.
+  if (translation_supported_type($node->type) && (!empty($node->tnid) || !empty($form_state['node']->translation_source->nid))) {
+    $tnid = !empty($node->tnid) ? $node->tnid : $form_state['node']->translation_source->nid;
     $translations = translation_node_get_translations($tnid);
     if (isset($translations[$node->language]) && $translations[$node->language]->nid != $node->nid ) {
       form_set_error('language', t('There is already a translation in this language.'));
