diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index e8233ce0e7aea9d0330262090ac8887009386922..5bd955824a34292b7014dc8023d4923b3a3bf821 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -175,17 +175,54 @@ function locale_user($type, $edit, &$user, $category = NULL) {
 /**
  * Implementation of hook_form_alter(). Adds language fields to forms.
  */
-function locale_form_alter($form_id, &$form) {
+function locale_form_alter(&$form, $form_id) {
   switch ($form_id) {
+
+    // Language field for paths
     case 'path_admin_edit':
       $form['language'] = array(
-        '#type' => 'radios',
+        '#type' => 'select',
         '#title' => t('Language'),
         '#options' => array('' => t('All languages')) + locale_language_list('name'),
-        '#default_value' => $form['#alias'] ? $form['#alias']['language'] : '',
-        '#weight' => -10
+        '#default_value' => $form['language']['#value'],
+        '#weight' => -10,
+        '#description' => t('Path aliases added for languages take precedence over path aliases added for all languages for the same Drupal path.'),
       );
       break;
+
+    // Language setting for content types
+    case 'node_type_form':
+      if (isset($form['identity']['type'])) {
+        $form['workflow']['language'] = array(
+          '#type' => 'radios',
+          '#title' => t('Multilingual support'),
+          '#default_value' => variable_get('language_'. $form['#node_type']->type, 0),
+          '#options' => array(t('Disabled'), t('Enabled')),
+          '#description' => t('Enable multilingual support for this content type. If enabled, a language selection field will be added to the editing form, allowing you to select from one of the <a href="!languages">enabled languages</a>. If disabled, new posts are saved with the default language. Existing content will not be affected by changing this option.', array('!languages' => url('admin/build/locale'))),
+        );
+      }
+      break;
+
+    // Language field for nodes
+    default:
+      if ($form['#id'] == 'node-form') {
+        if (variable_get('language_' . $form['#node']->type, 0)) {
+          $form['language'] = array(
+            '#type' => 'select',
+            '#title' => t('Language'),
+            '#default_value' => (isset($form['#node']->language) ? $form['#node']->language : ''),
+            '#options' => array('' => t('Language neutral')) + locale_language_list('name'),
+          );
+        }
+        // Node type without language selector: assign the default for new nodes
+        elseif (!isset($form['#node']->nid)) {
+          $default = language_default();
+          $form['language'] = array(
+            '#type' => 'value',
+            '#value' => $default->language
+          );
+        }
+      }
   }
 }
 
diff --git a/modules/node/node.module b/modules/node/node.module
index d178e53b218f24f42fef2199b8c9ad351281ada6..4b5acd9757b69de326e4cd39129415aba3e4ac16 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -575,10 +575,10 @@ function node_load($param = array(), $revision = NULL, $reset = NULL) {
   // No db_rewrite_sql is applied so as to get complete indexing for search.
   if ($revision) {
     array_unshift($arguments, $revision);
-    $node = db_fetch_object(db_query('SELECT n.nid, r.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = %d WHERE '. $cond, $arguments));
+    $node = db_fetch_object(db_query('SELECT n.nid, r.vid, n.type, n.status, n.language, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = %d WHERE '. $cond, $arguments));
   }
   else {
-    $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE '. $cond, $arguments));
+    $node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.language, n.created, n.changed, n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE '. $cond, $arguments));
   }
 
   if ($node && $node->nid) {
@@ -658,12 +658,12 @@ function node_save(&$node) {
   }
   $node_table_values = array('nid' => $node->nid, 'vid' => $node->vid,
                     'title' => $node->title, 'type' => $node->type, 'uid' => $node->uid,
-                    'status' => $node->status, 'created' => $node->created,
+                    'status' => $node->status, 'language' => $node->language, 'created' => $node->created,
                     'changed' => $node->changed, 'comment' => $node->comment,
                     'promote' => $node->promote, 'sticky' => $node->sticky);
   $node_table_types = array('nid' => '%d', 'vid' => '%d',
                     'title' => "'%s'", 'type' => "'%s'", 'uid' => '%d',
-                    'status' => '%d', 'created' => '%d',
+                    'status' => '%d', 'language' => "'%s'",'created' => '%d',
                     'changed' => '%d', 'comment' => '%d',
                     'promote' => '%d', 'sticky' => '%d');
 
@@ -1366,7 +1366,11 @@ function node_filters() {
   if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
     $filters['category'] = array('title' => t('category'), 'options' => $taxonomy);
   }
-
+  // Language filter if there is a list of languages
+  if ($languages = module_invoke('locale', 'language_list')) {
+    $languages = array('' => t('Language neutral')) + $languages;
+    $filters['language'] = array('title' => t('language'), 'options' => $languages);
+  }
   return $filters;
 }
 
@@ -1394,6 +1398,8 @@ function node_build_filter_query() {
         break;
       case 'type':
         $where[] = "n.type = '%s'";
+      case 'language':
+        $where[] = "n.language = '%s'";
     }
     $args[] = $value;
   }
@@ -1422,13 +1428,20 @@ function node_filter_form() {
       $value = module_invoke('taxonomy', 'get_term', $value);
       $value = $value->name;
     }
+    else if ($type == 'language') {
+      $value = empty($value) ? t('Language neutral') : module_invoke('locale', 'language_name', $value);
+    }
     else {
       $value = $filters[$type]['options'][$value];
     }
-    $string = ($i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>');
-    $form['filters']['current'][] = array('#value' => t($string, array('%a' => $filters[$type]['title'] , '%b' => $value)));
-    if ($type == 'type') {
-      // Remove the type option if it is already being filtered on.
+    if ($i++) {
+      $form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
+    }
+    else {
+      $form['filters']['current'][] = array('#value' => t('<strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
+    }
+    if (in_array($type, array('type', 'language'))) {
+      // Remove the option if it is already being filtered on.
       unset($filters['type']);
     }
   }
@@ -1570,6 +1583,10 @@ function node_admin_nodes() {
 
   $result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n '. $filter['join'] .' INNER JOIN {users} u ON n.uid = u.uid '. $filter['where'] .' ORDER BY n.changed DESC', 50, 0, NULL, $filter['args']);
 
+  // Enable language column if locale is enabled or if we have any node with language
+  $count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE language != ''"));
+  $multilanguage = (module_exists('locale') || $count);
+
   $form['options'] = array('#type' => 'fieldset',
     '#title' => t('Update options'),
     '#prefix' => '<div class="container-inline">',
@@ -1590,6 +1607,9 @@ function node_admin_nodes() {
     $form['name'][$node->nid] =  array('#value' => node_get_types('name', $node));
     $form['username'][$node->nid] = array('#value' => theme('username', $node));
     $form['status'][$node->nid] =  array('#value' =>  ($node->status ? t('published') : t('not published')));
+    if ($multilanguage) {
+      $form['language'][$node->nid] = array('#value' => empty($node->language) ? t('Language neutral') : module_invoke('locale', 'language_name', $node->language));
+    }
     $form['operations'][$node->nid] = array('#value' => l(t('edit'), 'node/'. $node->nid .'/edit', array('query' => $destination)));
   }
   $form['nodes'] = array('#type' => 'checkboxes', '#options' => $nodes);
@@ -1602,7 +1622,11 @@ function node_admin_nodes() {
  */
 function theme_node_admin_nodes($form) {
   // Overview table:
-  $header = array(theme('table_select_header_cell'), t('Title'), t('Type'), t('Author'), t('Status'), t('Operations'));
+  $header = array(theme('table_select_header_cell'), t('Title'), t('Type'), t('Author'), t('Status'));
+  if (isset($form['language'])) {
+    $header[] = t('Language');
+  }
+  $header[] = t('Operations');
   $output = '';
 
   $output .= drupal_render($form['options']);
@@ -1614,6 +1638,9 @@ function theme_node_admin_nodes($form) {
       $row[] = drupal_render($form['name'][$key]);
       $row[] = drupal_render($form['username'][$key]);
       $row[] = drupal_render($form['status'][$key]);
+      if (isset($form['language'])) {
+        $row[] = drupal_render($form['language'][$key]);
+      }
       $row[] = drupal_render($form['operations'][$key]);
       $rows[] = $row;
     }
@@ -1996,6 +2023,11 @@ function node_form($node, $form_values = NULL) {
   global $user;
 
   $node = (object)$node;
+  foreach (array('body', 'title', 'format') as $key) {
+    if (!isset($node->$key)) {
+      $node->$key = NULL;
+    }
+  }
   node_object_prepare($node);
 
   // Set the id of the top-level form tag
@@ -2005,19 +2037,12 @@ function node_form($node, $form_values = NULL) {
    * Basic node information.
    * These elements are just values so they are not even sent to the client.
    */
-  foreach (array('nid', 'vid', 'uid', 'created', 'type') as $key) {
+  foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language') as $key) {
     $form[$key] = array('#type' => 'value', '#value' => isset($node->$key) ? $node->$key : NULL);
   }
-  if (!isset($node->nid)) {
-    $node->body = NULL;
-    $node->title = NULL;
-  }
 
   // Changed must be sent to the client, for later overwrite error checking.
   $form['changed'] = array('#type' => 'hidden', '#default_value' => isset($node->changed) ? $node->changed : NULL);
-  if (!isset($node->format)) {
-    $node->format = NULL;
-  }
   // Get the node-specific bits.
   if ($extra = node_invoke($node, 'form', $form_values)) {
     $form = array_merge_recursive($form, $extra);
@@ -2188,7 +2213,7 @@ function node_add($type) {
   // If a node type has been specified, validate its existence.
   if (isset($types[$type]) && node_access('create', $type)) {
     // Initialize settings:
-    $node = array('uid' => $user->uid, 'name' => $user->name, 'type' => $type);
+    $node = array('uid' => $user->uid, 'name' => $user->name, 'type' => $type, 'language' => '');
 
     drupal_set_title(t('Submit @name', array('@name' => $types[$type]->name)));
     $output = drupal_get_form($type .'_node_form', $node);
diff --git a/modules/path/path.module b/modules/path/path.module
index b00f7b998cad817958aa23bef74406cc50e53258..5baa45a82300f4fc3f3da33ec08cfb2fb192a46d 100644
--- a/modules/path/path.module
+++ b/modules/path/path.module
@@ -184,7 +184,7 @@ function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = ''
 /**
  * Return a form for editing or creating an individual URL alias.
  */
-function path_form($edit = array('src' => '', 'dst' => '', 'pid' => NULL)) {
+function path_form($edit = array('src' => '', 'dst' => '', 'language' => '', 'pid' => NULL)) {
   $form['#submit']['path_form_submit'] = array();
   $form['#validate']['path_form_validate'] = array();
   $form['#theme'] = 'path_form';
@@ -208,6 +208,11 @@ function path_form($edit = array('src' => '', 'dst' => '', 'pid' => NULL)) {
     '#description' => t('Specify an alternative path by which this data can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
   );
+  // This will be a hidden value unless locale module is enabled
+  $form['language'] = array(
+    '#type' => 'value',
+    '#value' => $edit['language']
+  );
   if ($edit['pid']) {
     $form['pid'] = array('#type' => 'hidden', '#value' => $edit['pid']);
     $form['submit'] = array('#type' => 'submit', '#value' => t('Update alias'));
diff --git a/modules/system/system.install b/modules/system/system.install
index f6bd4da4220f1f976ad5fda91c4e5252ad9fd99c..b5f93887d710e12d070c1debf521a356bdb6de6c 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -367,6 +367,7 @@ function system_install() {
         nid int unsigned NOT NULL auto_increment,
         vid int unsigned NOT NULL default '0',
         type varchar(32) NOT NULL default '',
+        language varchar(12) NOT NULL default '',
         title varchar(128) NOT NULL default '',
         uid int NOT NULL default '0',
         status int NOT NULL default '1',
@@ -840,6 +841,7 @@ function system_install() {
         nid serial CHECK (nid >= 0),
         vid int_unsigned NOT NULL default '0',
         type varchar(32) NOT NULL default '',
+        language varchar(12) NOT NULL default '',
         title varchar(128) NOT NULL default '',
         uid int NOT NULL default '0',
         status int NOT NULL default '1',
@@ -3797,6 +3799,23 @@ function system_update_6010() {
   return $ret;
 }
 
+/**
+ * Add language support to nodes
+ */
+function system_update_6011() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+      db_add_column($ret, 'node', 'language', 'varchar(12)', array('default' => "''", 'not null' => TRUE));
+      break;
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {node} ADD language varchar(12) NOT NULL default ''");
+      break;
+  }
+  return $ret;
+}
+
 /**
  * @} End of "defgroup updates-5.x-to-6.x"
  * The next series of updates should start at 7000.
diff --git a/update.php b/update.php
index 51a4181b56a7d1a5a1d54d2983a32e97d903ae9f..c104b2308007977b4da33173de5a264cdf97076e 100644
--- a/update.php
+++ b/update.php
@@ -448,7 +448,6 @@ function update_do_updates() {
   if (!isset($update['module'])) {
     cache_clear_all('*', 'cache', TRUE);
     cache_clear_all('*', 'cache_page', TRUE);
-    cache_clear_all('*', 'cache_menu', TRUE);
     cache_clear_all('*', 'cache_filter', TRUE);
     drupal_clear_css_cache();
   }