Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.56
diff -u -d -F^\s*function -r1.56 install.php
--- install.php	2 Jun 2007 11:06:39 -0000	1.56
+++ install.php	3 Jun 2007 08:50:03 -0000
@@ -892,6 +892,8 @@ function install_configure_form() {
   );
 
   drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
+  // We add these strings as settings because JavaScript translation does not
+  // work on install time.
   drupal_add_js(array('cleanURL' => array('success' => st('Your server has been successfully tested to support this feature.'), 'failure' => st('Your system configuration does not currently support this feature. The <a href="http://drupal.org/node/15365">handbook page on Clean URLs</a> has additional troubleshooting information.'), 'testing' => st('Testing clean URLs...'))), 'setting');
   drupal_add_js('
 // Global Killswitch
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.650
diff -u -d -F^\s*function -r1.650 common.inc
--- includes/common.inc	1 Jun 2007 09:49:11 -0000	1.650
+++ includes/common.inc	3 Jun 2007 08:50:05 -0000
@@ -1686,13 +1686,14 @@ function drupal_clear_css_cache() {
  *   feature has been turned on under the performance section?
  * @return
  *   If the first parameter is NULL, the JavaScript array that has been built so
- *   far for $scope is returned.
+ *   far for $scope is returned. If the first three parameters are NULL,
+ *   an array with all scopes is returned.
  */
 function drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE, $preprocess = TRUE) {
   static $javascript = array();
 
   // Add jquery.js and drupal.js the first time a Javascript file is added.
-  if ($data && empty($javascript)) {
+  if (isset($data) && empty($javascript)) {
     $javascript['header'] = array(
       'core' => array(
         'misc/jquery.js' => array('cache' => TRUE, 'defer' => FALSE, 'preprocess' => TRUE),
@@ -1701,11 +1702,11 @@ function drupal_add_js($data = NULL, $ty
       'module' => array(), 'theme' => array(), 'setting' => array(), 'inline' => array(),
     );
   }
-  if (!isset($javascript[$scope])) {
+  if (isset($scope) && !isset($javascript[$scope])) {
     $javascript[$scope] = array('core' => array(), 'module' => array(), 'theme' => array(), 'setting' => array(), 'inline' => array());
   }
 
-  if (!isset($javascript[$scope][$type])) {
+  if (isset($type) && isset($scope) && !isset($javascript[$scope][$type])) {
     $javascript[$scope][$type] = array();
   }
 
@@ -1723,7 +1724,12 @@ function drupal_add_js($data = NULL, $ty
     }
   }
 
-  return $javascript[$scope];
+  if (isset($scope)) {
+    return $javascript[$scope];
+  }
+  else {
+    return $javascript;
+  }
 }
 
 /**
@@ -1743,6 +1749,10 @@ function drupal_add_js($data = NULL, $ty
  *   All JavaScript code segments and includes for the scope as HTML tags.
  */
 function drupal_get_js($scope = 'header', $javascript = NULL) { 
+  if (function_exists('locale_inc_callback')) {
+    locale_inc_callback('_locale_update_js_files');
+  }
+
   if (!isset($javascript)) {
     $javascript = drupal_add_js(NULL, NULL, $scope);
   }
@@ -2062,6 +2072,7 @@ function _packer_backreferences($match, 
  */
 function drupal_clear_js_cache() {
   file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+  variable_set('javascript_parsed', '');
 }
 
 /**
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.201
diff -u -d -F^\s*function -r1.201 form.inc
--- includes/form.inc	31 May 2007 12:36:18 -0000	1.201
+++ includes/form.inc	3 Jun 2007 08:50:06 -0000
@@ -1549,7 +1549,6 @@ function theme_textarea($element) {
   if (!empty($element['#teaser'])) {
     drupal_add_js('misc/teaser.js');
     // Note: arrays are merged in drupal_get_js().
-    drupal_add_js(array('teaserButton' => array(t('Join summary'), t('Split summary at cursor'))), 'setting');
     drupal_add_js(array('teaserCheckbox' => array($element['#id'] => $element['#teaser_checkbox'])), 'setting');
     drupal_add_js(array('teaser' => array($element['#id'] => $element['#teaser'])), 'setting');
     $class[] = 'teaser';
Index: includes/locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.132
diff -u -d -F^\s*function -r1.132 locale.inc
--- includes/locale.inc	30 May 2007 08:08:57 -0000	1.132
+++ includes/locale.inc	3 Jun 2007 08:50:07 -0000
@@ -6,6 +6,8 @@
  *   Administration functions for locale.module.
  */
 
+define('LOCALE_JS_STRING', '\'(?:\\\\\'|[^\'])*\'|"(?:\\\\"|[^"])*"');
+
 /**
  * @defgroup locale-language-overview Language overview functionality
  * @{
@@ -792,7 +794,11 @@ function locale_translate_edit_form_subm
     else {
       db_query("INSERT INTO {locales_target} (lid, translation, language) VALUES (%d, '%s', '%s')", $lid, $value, $key);
     }
+
+    // Refresh the JS file for this language.
+    _locale_rebuild_js($key);
   }
+
   drupal_set_message(t('The string has been saved.'));
 
   // Refresh the locale cache.
@@ -814,8 +820,12 @@ function locale_translate_edit_form_subm
  * Delete a language string.
  */
 function locale_translate_delete($lid) {
+  $langcode = db_result(db_query('SELECT language FROM {locales_source} WHERE lid = %d', $lid));
   db_query('DELETE FROM {locales_source} WHERE lid = %d', $lid);
   db_query('DELETE FROM {locales_target} WHERE lid = %d', $lid);
+  if ($langcode) {
+    _locale_rebuild_js($langcode);
+  }
   locale_refresh_cache();
   drupal_set_message(t('The string has been removed.'));
   drupal_goto('admin/build/translate/search');
@@ -1553,6 +1563,102 @@ function _locale_import_parse_quoted($st
  */
 
 /**
+ * This function checks all JavaScript files currently added via drupal_add_js()
+ * and invokes parsing if they have not yet been parsed for Drupal.t() calls.
+ */
+function _locale_update_js_files() {
+  $parsed = variable_get('javascript_parsed', array());
+
+  // The first three parameters are NULL in order to get an array with all
+  // scopes. This is necessary to prevent recreation of JS translation files
+  // when new files are added for example in the footer.
+  $javascript = drupal_add_js(NULL, NULL, NULL);
+  $files = FALSE;
+
+  foreach ($javascript as $scope) {
+    foreach ($scope as $type => $data) {
+      if ($type != 'setting' && $type != 'inline') {
+        foreach ($data as $path => $info) {
+          $files = TRUE;
+          if (!in_array($path, $parsed)) {
+            _locale_parse_js_file($path);
+            watchdog('locale', 'Parsed JavaScript file %file.', array('%file' => $path));
+            $parsed[] = $path;
+          }
+        }
+      }
+    }
+  }
+
+  // Update the parsed files storage array.
+  variable_set('javascript_parsed', $parsed);
+  _locale_rebuild_js();
+
+  // Add the translation JavaScript file to the page.
+  global $language;
+  if ($files && !empty($language->javascript)) {
+    drupal_add_js(file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js'), 'core');
+  }
+}
+
+/**
+ * Parses a JavaScript file, extracts strings wrapped in Drupal.t() and inserts
+ * them into the database.
+ */
+function _locale_parse_js_file($location) {
+  global $language;
+
+  // Load the JavaScript file.
+  $file = file_get_contents($location);
+
+  // Match all calls to Drupal.t() in an array.
+  // Note: \s also matches newlines with the 's' modifier.
+  preg_match_all('~[^\w]Drupal\s*\.\s*t\s*\(\s*('. LOCALE_JS_STRING .')\s*[,\)]~s', $file, $t_matches);
+
+  // Match all Drupal.formatPlural() calls in another array.
+  preg_match_all('~[^\w]Drupal\s*\.\s*formatPlural\s*\(\s*.+?\s*,\s*('. LOCALE_JS_STRING .')\s*,\s*((?:(?:\'(?:\\\\\'|[^\'])*@count(?:\\\\\'|[^\'])*\'|"(?:\\\\"|[^"])*@count(?:\\\\"|[^"])*")(?:\s*\+\s*)?)+)\s*[,\)]~s', $file, $plural_matches);
+
+  // Copy the single strings into the plural strings array for easier processing.
+  $plural_matches[1] = array_merge($plural_matches[1], $t_matches[1]);
+
+  // Loop through all matches and process them.
+  foreach ($plural_matches[1] as $key => $string) {
+    $strings = array($string);
+
+    // If there is also a plural version of this string, add it to the strings array.
+    if (isset($plural_matches[2][$key])) {
+      $strings[] = $plural_matches[2][$key];
+    }
+
+    foreach ($strings as $key => $string) {
+      // Remove the quotes and string concatenations from the string.
+      $string = implode('', preg_split('~(?<!\\\\)[\'"]\s*\+\s*[\'"]~s', substr($string, 1, -1)));
+
+      $result = db_query("SELECT lid, location FROM {locales_source} WHERE source = '%s' AND textgroup = 'default'", $string);
+      if ($source = db_fetch_object($result)) {
+        // We already have this source string and now have to add the location
+        // to the location column, if this file is not yet present in there.
+        $locations = preg_split('~\s*;\s*~', $source->location);
+
+        if (!in_array($location, $locations)) {
+          $locations[] = $location;
+          $locations = implode('; ', $locations);
+
+          // Save the new locations string to the database.
+          db_query("UPDATE {locales_source} SET location = '%s' WHERE lid = %d", $locations, $source->lid);
+        }
+      }
+      else {
+        // We don't have the source string yet, thus we insert it into the database.
+        db_query("INSERT INTO {locales_source} (location, source, textgroup) VALUES ('%s', '%s', 'default')", $location, $string);
+        $lid = db_result(db_query("SELECT lid FROM {locales_source} WHERE source = '%s' AND textgroup = 'default'", $string));
+        db_query("INSERT INTO {locales_target} (lid, language, translation) VALUES (%d, '%s', '')", $lid, $language->language);
+      }
+    }
+  }
+}
+
+/**
  * @defgroup locale-api-export Translation (template) export API.
  * @{
  */
@@ -1869,6 +1975,128 @@ function _locale_translate_seek_query() 
 }
 
 /**
+ * (Re-)Creates the JavaScript translation file for a language.
+ *
+ * @param $language
+ *   The language, the translation file should be (re)created for.
+ */
+function _locale_rebuild_js($langcode = NULL) {
+  if (!isset($langcode)) {
+    global $language;
+  }
+  else {
+    // Get information about the locale.
+    $languages = language_list();
+    $language = $languages[$langcode];
+  }
+
+  // Construct the array for JavaScript translations.
+  // We sort on plural so that we have all plural forms before singular forms.
+  $result = db_query("SELECT s.lid, s.source, t.plid, t.plural, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE t.language = '%s' AND s.location LIKE '%%.js%%' AND s.textgroup = 'default' ORDER BY t.plural DESC", $language->language);
+
+  $translations = $plurals = array();
+  while ($data = db_fetch_object($result)) {
+    // Only add this to the translations array when there is actually a translation.
+    if (!empty($data->translation)) {
+      if ($data->plural) {
+        // When the translation is a plural form, first add it to another array and
+        // wait for the singular (parent) translation.
+        if (!isset($plurals[$data->plid])) {
+          $plurals[$data->plid] = array($data->plural => $data->translation);
+        }
+        else {
+          $plurals[$data->plid] += array($data->plural => $data->translation);
+        }
+      }
+      elseif (isset($plurals[$data->lid])) {
+        // There are plural translations for this translation, so get them from
+        // the plurals array and add them to the final translations array.
+        $translations[$data->source] = array($data->plural => $data->translation) + $plurals[$data->lid];
+        unset($plurals[$data->lid]);
+      }
+      else {
+        // There are no plural forms for this translation, so just add it to
+        // the translations array.
+        $translations[$data->source] = $data->translation;
+      }
+    }
+  }
+
+  // Only operate when there are translations.
+  if (!empty($translations)) {
+    // Construct the JavaScript file.
+    $data = "Drupal.locale = { ";
+
+    if (!empty($language->formula)) {
+      $data .= "'pluralFormula': function(\$n) { return Number({$language->formula}); }, ";
+    }
+
+    $data .= "'strings': ". drupal_to_js($translations) ." };";
+
+    // Construct the directory where JS translation files are stored.
+    // There is (on purpose) no front end to edit that variable.
+    $dir = file_create_path(variable_get('locale_js_directory', 'languages'));
+
+    // Only create a new file if the content has changed.
+    $data_hash = md5($data);
+    if ($language->javascript != $data_hash) {
+      if (!empty($language->javascript)) {
+        // We are recreating the new file, so delete the old one.
+        file_delete(file_create_path($dir .'/'. $language->language .'_'. $language->javascript .'.js'));
+        $language->javascript = '';
+      }
+      else {
+        // The directory might not exist when there has not been a translation
+        // file before, so create it.
+        file_check_directory($dir, TRUE);
+      }
+
+      // The file name of the new JavaScript translation file.
+      $dest = $dir .'/'. $language->language .'_'. $data_hash .'.js';
+      $path = file_save_data($data, $dest);
+
+      // Save the new JavaScript hash.
+      db_query("UPDATE {languages} SET javascript = '%s' WHERE language = '%s'", $path ? $data_hash : '', $language->language);
+
+      // Update the global $language object.
+      $language->javascript = $path ? $data_hash : '';
+
+      // Update the default language variable if the default language has been altered.
+      // This is necessary to keep the variable consistent with the database
+      // version of the language and to prevent checking against an outdated hash.
+      $default_langcode = language_default('language');
+      if ($default_langcode == $language->language) {
+        $default = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $default_langcode));
+        variable_set('language_default', $default);
+      }
+
+      // Only report updated or creation when there is actually a file created.
+      if ($path) {
+        // There has already been a translation file before.
+        if (!empty($language->javascript)) {
+          watchdog('locale', t('Updated JavaScript translation file for the language %language.', array('%language' => t($language->name))));
+        }
+        else {
+          watchdog('locale', t('Created JavaScript translation file for the language %language.', array('%language' => t($language->name))));
+        }
+      }
+      else {
+        watchdog('locale', t('An error occured during creation of the JavaScript translation file for the language %language.', array('%language' => t($language->name))));
+      }
+    }
+  }
+
+  // There are no strings for JavaScript translation. However, if there is a file,
+  // delete it and reset the database.
+  elseif (!empty($language->javascript)) {
+    // Delete the old JavaScript file
+    file_delete(file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js'));
+    db_query("UPDATE {languages} SET javascript = '' WHERE language = '%s'", $language->language);
+    watchdog('locale', t('Deleted JavaScript translation file for the locale %language.', array('%language' => t($language->name))));
+  }
+}
+
+/**
  * List languages in search result table
  */
 function _locale_translate_language_list($translation) {
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.357
diff -u -d -F^\s*function -r1.357 theme.inc
--- includes/theme.inc	31 May 2007 12:14:04 -0000	1.357
+++ includes/theme.inc	3 Jun 2007 08:50:08 -0000
@@ -115,6 +115,21 @@ function _init_theme($theme, $base_theme
     }
   }
 
+  // Add the default script
+  if (!empty($theme->script)) {
+    drupal_add_js($theme->script, 'theme');
+  }
+  else {
+    // If we don't have a script of our own, look for the first
+    // base to have one and use its.
+    foreach ($base_theme as $base) {
+      if (!empty($base->script)) {
+        drupal_add_js($base->script, 'theme');
+        break;
+      }
+    }
+  }
+
   $theme_engine = NULL;
 
   // Initialize the theme.
@@ -341,9 +356,12 @@ function list_themes($refresh = FALSE) {
     while ($theme = db_fetch_object($result)) {
       if (file_exists($theme->filename)) {
         $theme->info = unserialize($theme->info);
-        if (isset($theme->info['stylesheet'])) {
+        if (!empty($theme->info['stylesheet']) && file_exists($theme->info['stylesheet'])) {
           $theme->stylesheet = $theme->info['stylesheet'];
         }
+        if (!empty($theme->info['script']) && file_exists($theme->info['script'])) {
+          $theme->script = $theme->info['script'];
+        }
         if (isset($theme->info['engine'])) {
           $theme->engine = $theme->info['engine'];
         }
@@ -1164,7 +1182,6 @@ function theme_table($header, $rows, $at
  * Returns a header cell for tables that have a select all functionality.
  */
 function theme_table_select_header_cell() {
-  drupal_add_js(array('tableSelect' => array('selectAll' => t('Select all rows in this table'), 'selectNone' => t('Deselect all rows in this table'))), 'setting');
   drupal_add_js('misc/tableselect.js');
 
   return array('class' => 'select-all');
Index: misc/autocomplete.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/autocomplete.js,v
retrieving revision 1.18
diff -u -d -F^\s*function -r1.18 autocomplete.js
--- misc/autocomplete.js	1 Jun 2007 09:05:45 -0000	1.18
+++ misc/autocomplete.js	3 Jun 2007 08:50:08 -0000
@@ -282,7 +282,7 @@
         }
       },
       error: function (xmlhttp) {
-        alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri);
+        alert(Drupal.t("An HTTP error @status occured. \n@uri", { '@status': xmlhttp.status, '@uri': db.uri }));
       }
     });
   }, this.delay);
Index: misc/drupal.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.js,v
retrieving revision 1.32
diff -u -d -F^\s*function -r1.32 drupal.js
--- misc/drupal.js	1 Jun 2007 09:05:45 -0000	1.32
+++ misc/drupal.js	3 Jun 2007 08:50:08 -0000
@@ -1,6 +1,6 @@
 // $Id: drupal.js,v 1.32 2007/06/01 09:05:45 unconed Exp $
 
-var Drupal = Drupal || {};
+var Drupal = Drupal || { 'settings': {}, 'themes': {}, 'locale': {} };
 
 /**
  * Set the variable that indicates if JavaScript behaviors should be applied
@@ -22,6 +22,142 @@
 };
 
 /**
+ * Encode special characters in a plain-text string for display as HTML.
+ */
+Drupal.checkPlain = function(str) {
+  str = String(str);
+  var replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
+  for (var character in replace) {
+    str = str.replace(character, replace[character]);
+  }
+  return str;
+};
+
+/**
+ * Translate strings to the page language or a given language.
+ *
+ * See the documentation of the server-side t() function for further details.
+ *
+ * @param str
+ *   A string containing the English string to translate.
+ * @param args
+ *   An object of replacements pairs to make after translation. Incidences
+ *   of any key in this array are replaced with the corresponding value.
+ *   Based on the first character of the key, the value is escaped and/or themed:
+ *    - !variable: inserted as is
+ *    - @variable: escape plain text to HTML (Drupal.checkPlain)
+ *    - %variable: escape text and theme as a placeholder for user-submitted
+ *      content (checkPlain + Drupal.theme('placeholder'))
+ * @return
+ *   The translated string.
+ */
+Drupal.t = function(str, args) {
+  // Fetch the localized version of the string.
+  if (Drupal.locale.strings && Drupal.locale.strings[str]) {
+    str = Drupal.locale.strings[str];
+  }
+
+  if (args) {
+    // Transform arguments before inserting them
+    for (var key in args) {
+      switch (key[0]) {
+        // Escaped only
+        case '@':
+          args[key] = Drupal.checkPlain(args[key]);
+        break;
+        // Pass-through
+        case '!':
+          break;
+        // Escaped and placeholder
+        case '%':
+        default:
+          args[key] = Drupal.theme('placeholder', args[key]);
+          break;
+      }
+      str = str.replace(key, args[key]);
+    }
+  }
+  return str;
+};
+
+/**
+ * Format a string containing a count of items.
+ *
+ * This function ensures that the string is pluralized correctly. Since Drupal.t() is
+ * called by this function, make sure not to pass already-localized strings to it.
+ *
+ * See the documentation of the server-side format_plural() function for further details.
+ *
+ * @param count
+ *   The item count to display.
+ * @param singular
+ *   The string for the singular case. Please make sure it is clear this is
+ *   singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
+ *   Do not use @count in the singular string.
+ * @param plural
+ *   The string for the plural case. Please make sure it is clear this is plural,
+ *   to ease translation. Use @count in place of the item count, as in "@count
+ *   new comments".
+ * @param args
+ *   An object of replacements pairs to make after translation. Incidences
+ *   of any key in this array are replaced with the corresponding value.
+ *   Based on the first character of the key, the value is escaped and/or themed:
+ *    - !variable: inserted as is
+ *    - @variable: escape plain text to HTML (Drupal.checkPlain)
+ *    - %variable: escape text and theme as a placeholder for user-submitted
+ *      content (checkPlain + Drupal.theme('placeholder'))
+ *   Note that you do not need to include @count in this array.
+ *   This replacement is done automatically for the plural case.
+ * @return
+ *   A translated string.
+ */
+Drupal.formatPlural = function(count, singular, plural, args) {
+  var args = ars || {};
+  args['@count'] = count;
+  // Determine the index of the plural form.
+  var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
+
+  if (index == 0) {
+    return Drupal.t(singular, args);
+  }
+  else if (index == 1) {
+    return Drupal.t(plural, args);
+  }
+  else {
+    args['@count['+ index +']'] = args['@count'];
+    delete args['@count'];
+    return Drupal.t(plural.replace('@count', '@count['+ index +']'));
+  }
+};
+
+/**
+ * Generate the themed representation of a Drupal object.
+ *
+ * All requests for themed output must go through this function. It examines
+ * the request and routes it to the appropriate theme function. If the current
+ * theme does not provide an override function, the generic theme function is
+ * called.
+ *
+ * For example, to retrieve the HTML that is output by theme_placeholder(text),
+ * call Drupal.theme('placeholder', text).
+ *
+ * @param func
+ *   The name of the theme function to call.
+ * @param ...
+ *   Additional arguments to pass along to the theme function.
+ * @return
+ *   Any data the theme function returns. This could be a plain HTML string,
+ *   but also a complex object.
+ */
+Drupal.theme = function(func) {
+  for (var i = 1, args = []; i < arguments.length; i++) {
+    args.push(arguments[i]);
+  }
+
+  return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
+};
+
+/**
  * Redirects a button's form submission to a hidden iframe and displays the result
  * in a given wrapper. The iframe should contain a call to
  * window.parent.iframeHandler() after submission.
@@ -126,7 +262,7 @@
  */
 Drupal.parseJson = function (data) {
   if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) {
-    return { status: 0, data: data.length ? data : 'Unspecified error' };
+    return { status: 0, data: data.length ? data : Drupal.t('Unspecified error') };
   }
   return eval('(' + data + ');');
 };
@@ -227,3 +363,21 @@
   // 'js enabled' cookie
   document.cookie = 'has_js=1';
 }
+
+/**
+ * The default themes.
+ */
+Drupal.theme.prototype = {
+
+  /**
+   * Formats text for emphasized display in a placeholder inside a sentence.
+   *
+   * @param str
+   *   The text to format (plain-text).
+   * @return
+   *   The formatted text (html).
+   */
+  placeholder: function(str) {
+    return '<em>' + Drupal.checkPlain(str) + '</em>';
+  }
+};
Index: misc/progress.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/progress.js,v
retrieving revision 1.16
diff -u -d -F^\s*function -r1.16 progress.js
--- misc/progress.js	1 Jun 2007 09:05:45 -0000	1.16
+++ misc/progress.js	3 Jun 2007 08:50:08 -0000
@@ -86,7 +86,7 @@
         pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
       },
       error: function (xmlhttp) {
-        pb.displayError('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
+        pb.displayError(Drupal.t("An HTTP error @status occured. \n@uri", { '@status': xmlhttp.status, '@uri': pb.uri }));
       }
     });
   }
Index: misc/tableselect.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/tableselect.js,v
retrieving revision 1.2
diff -u -d -F^\s*function -r1.2 tableselect.js
--- misc/tableselect.js	1 Jun 2007 09:05:45 -0000	1.2
+++ misc/tableselect.js	3 Jun 2007 08:50:08 -0000
@@ -2,10 +2,11 @@
 
 Drupal.tableSelect = function() {
   // Keep track of the table, which checkbox is checked and alias the settings.
-  var table = this, selectAll, checkboxes, lastChecked, settings = Drupal.settings.tableSelect;
+  var table = this, selectAll, checkboxes, lastChecked;
+  var strings = { 'selectAll': Drupal.t('Select all rows in this table'), 'selectNone': Drupal.t('Deselect all rows in this table') };
 
   // Store the select all checkbox in a variable as we need it quite often.
-  selectAll = $('<input type="checkbox" class="form-checkbox" />').attr('title', settings.selectAll).click(function() {
+  selectAll = $('<input type="checkbox" class="form-checkbox" />').attr('title', strings.selectAll).click(function() {
     // Loop through all checkboxes and set their state to the select all checkbox' state.
     checkboxes.each(function() {
       this.checked = selectAll[0].checked;
@@ -13,7 +14,7 @@
       $(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
     });
     // Update the title and the state of the check all box.
-    selectAll.attr('title', selectAll[0].checked ? settings.selectNone : settings.selectAll);
+    selectAll.attr('title', selectAll[0].checked ? strings.selectNone : strings.selectAll);
   });
 
   // Find all <th> with class select-all, and insert the check all checkbox.
@@ -35,7 +36,7 @@
     // If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
     selectAll[0].checked = (checkboxes.length == $(checkboxes).filter(':checked').length);
     // Set the title to the current action.
-    selectAll.attr('title', selectAll[0].checked ? settings.selectNone : settings.selectAll);
+    selectAll.attr('title', selectAll[0].checked ? strings.selectNone : strings.selectAll);
 
     // Keep track of the last checked checkbox.
     lastChecked = e.target;
Index: misc/teaser.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/teaser.js,v
retrieving revision 1.4
diff -u -d -F^\s*function -r1.4 teaser.js
--- misc/teaser.js	1 Jun 2007 09:05:45 -0000	1.4
+++ misc/teaser.js	3 Jun 2007 08:50:08 -0000
@@ -29,7 +29,7 @@     function join_teaser() {
       $(teaser).attr('disabled', 'disabled');
       $(teaser).parent().slideUp('fast');
       // Change label
-      $(this).val(Drupal.settings.teaserButton[1]);
+      $(this).val(Drupal.t('Split summary at cursor'));
       // Show separate teaser checkbox
       $(checkbox).hide();
     }
@@ -48,7 +48,7 @@     function split_teaser() {
       $(teaser).attr('disabled', '');
       $(teaser).parent().slideDown('fast');
       // Change label
-      $(this).val(Drupal.settings.teaserButton[0]);
+      $(this).val(Drupal.t('Join summary'));
       // Show separate teaser checkbox
       $(checkbox).show();
     }
@@ -64,11 +64,11 @@     function split_teaser() {
       teaser[0].value = trim(text[0]);
       body[0].value = trim(text[1]);
       $(teaser).attr('disabled', '');
-      $('input', button).val(Drupal.settings.teaserButton[0]).toggle(join_teaser, split_teaser);
+      $('input', button).val(Drupal.t('Join summary')).toggle(join_teaser, split_teaser);
     }
     else {
       $(teaser).hide();
-      $('input', button).val(Drupal.settings.teaserButton[1]).toggle(split_teaser, join_teaser);
+      $('input', button).val(Drupal.t('Split summary at cursor')).toggle(split_teaser, join_teaser);
       $(checkbox).hide();
     }
 
Index: misc/upload.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/upload.js,v
retrieving revision 1.12
diff -u -d -F^\s*function -r1.12 upload.js
--- misc/upload.js	1 Jun 2007 09:05:45 -0000	1.12
+++ misc/upload.js	3 Jun 2007 08:50:08 -0000
@@ -33,7 +33,7 @@
 Drupal.jsUpload.prototype.onsubmit = function () {
   // Insert progressbar and stretch to take the same space.
   this.progress = new Drupal.progressBar('uploadprogress');
-  this.progress.setProgress(-1, 'Uploading file');
+  this.progress.setProgress(-1, Drupal.t('Uploading file'));
 
   var hide = this.hide;
   var el = this.progress.element;
@@ -98,7 +98,7 @@
  * Handler for the form redirection error.
  */
 Drupal.jsUpload.prototype.onerror = function (error) {
-  alert('An error occurred:\n\n'+ error);
+  alert(Drupal.t('An error occurred:\n\n@error', { '@error': error }));
   // Remove progressbar
   $(this.progress.element).remove();
   this.progress = null;
Index: modules/locale/locale.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.install,v
retrieving revision 1.11
diff -u -d -F^\s*function -r1.11 locale.install
--- modules/locale/locale.install	25 May 2007 15:47:56 -0000	1.11
+++ modules/locale/locale.install	3 Jun 2007 08:50:08 -0000
@@ -12,7 +12,7 @@ function locale_install() {
   // Create tables.
   drupal_install_schema('locale');
 
-  db_query("INSERT INTO {languages} (language, name, native, direction, enabled, weight) VALUES ('en', 'English', 'English', '0', '1', '0')");
+  db_query("INSERT INTO {languages} (language, name, native, direction, enabled, weight, javascript) VALUES ('en', 'English', 'English', '0', '1', '0', '')");
 }
 
 /**
@@ -39,6 +39,7 @@ function locale_update_6001() {
         domain varchar(128) NOT NULL default '',
         prefix varchar(128) NOT NULL default '',
         weight int NOT NULL default '0',
+        javascript varchar(32) NOT NULL default '',
         PRIMARY KEY (language)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
       break;
@@ -54,6 +55,7 @@ function locale_update_6001() {
         domain varchar(128) NOT NULL default '',
         prefix varchar(128) NOT NULL default '',
         weight int NOT NULL default '0',
+        javascript varchar(32) NOT NULL default '',
         PRIMARY KEY (language)
       )");
       break;
@@ -92,6 +94,15 @@ function locale_update_6002() {
 }
 
 /**
+ * Adds a column to store the filename of the JavaScript translation file.
+ */
+function locale_update_6003() {
+  $ret = array();
+  db_add_field($rest, 'languages', 'javascript', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''));
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.x-to-6.x"
  */
 
@@ -99,6 +110,14 @@ function locale_update_6002() {
  * Implementation of hook_uninstall().
  */
 function locale_uninstall() {
+  // Delete all JavaScript translation files
+  $files = db_query('SELECT javascript FROM {languages}');
+  while ($file = db_fetch_object($files)) {
+    if (!empty($file)) {
+      file_delete(file_create_path($file->javascript));
+    }
+  }
+
   // Remove tables.
   drupal_uninstall_schema('locale');
 }
Index: modules/locale/locale.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.schema,v
retrieving revision 1.1
diff -u -d -F^\s*function -r1.1 locale.schema
--- modules/locale/locale.schema	25 May 2007 12:46:44 -0000	1.1
+++ modules/locale/locale.schema	3 Jun 2007 08:50:08 -0000
@@ -4,16 +4,17 @@
 function locale_schema() {
   $schema['languages'] = array(
     'fields' => array(
-      'language'  => array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''),
-      'name'      => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
-      'native'    => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
-      'direction' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'enabled'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'plurals'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'formula'   => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
-      'domain'    => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
-      'prefix'    => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
-      'weight'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0)
+      'language'   => array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''),
+      'name'       => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
+      'native'     => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
+      'direction'  => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'enabled'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'plurals'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'formula'    => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+      'domain'     => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+      'prefix'     => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+      'weight'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'javascript' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
     ),
     'primary key' => array('language'),
   );
Index: modules/system/system.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.js,v
retrieving revision 1.7
diff -u -d -F^\s*function -r1.7 system.js
--- modules/system/system.js	1 Jun 2007 09:05:45 -0000	1.7
+++ modules/system/system.js	3 Jun 2007 08:50:09 -0000
@@ -9,18 +9,18 @@
  */
 Drupal.cleanURLsSettingsCheck = function() {
   var url = location.pathname +"admin/settings/clean-urls";
-  $("#clean-url .description span").html('<div id="testing">'+ Drupal.settings.cleanURL.testing +"</div>");
+  $("#clean-url .description span").html('<div id="testing">'+ Drupal.t('Testing clean URLs...') +"</div>");
   $("#clean-url p").hide();
   $.ajax({url: location.protocol +"//"+ location.host + url, type: "GET", data: " ", complete: function(response) {
     $("#testing").toggle();
     if (response.status == 200) {
       // Check was successful.
       $("#clean-url input.form-radio").attr("disabled", "");
-      $("#clean-url .description span").append('<div class="ok">'+ Drupal.settings.cleanURL.success +"</div>");
+      $("#clean-url .description span").append('<div class="ok">'+ Drupal.t('Your server has been successfully tested to support this feature.') +"</div>");
     }
     else {
       // Check failed.
-      $("#clean-url .description span").append('<div class="warning">'+ Drupal.settings.cleanURL.failure +"</div>");
+      $("#clean-url .description span").append('<div class="warning">'+ Drupal.t('Your system configuration does not currently support this feature. The <a href="http://drupal.org/node/15365">handbook page on Clean URLs</a> has additional troubleshooting information.') +"</div>");
     }
   }});
 };
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.487
diff -u -d -F^\s*function -r1.487 system.module
--- modules/system/system.module	1 Jun 2007 09:37:16 -0000	1.487
+++ modules/system/system.module	3 Jun 2007 08:50:10 -0000
@@ -607,7 +607,6 @@ function system_clean_url_settings() {
 
   if (!variable_get('clean_url', 0)) {
     if (strpos(request_uri(), '?q=') !== FALSE) {
-      drupal_add_js(array('cleanURL' => array('success' => t('Your server has been successfully tested to support this feature.'), 'failure' => t('Your system configuration does not currently support this feature. The <a href="http://drupal.org/node/15365">handbook page on Clean URLs</a> has additional troubleshooting information.'), 'testing' => t('Testing clean URLs...'))), 'setting');
       drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
       drupal_add_js('
 // Global Killswitch
@@ -1052,6 +1051,7 @@ function system_theme_default() {
       'slogan'
     ),
     'stylesheet' => 'style.css',
+    'script' => 'script.js',
     'screenshot' => 'screenshot.png',
   );
 }
@@ -1105,6 +1105,10 @@ function system_theme_data() {
     if (!empty($themes[$key]->info['stylesheet'])) {
       $themes[$key]->info['stylesheet'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['stylesheet'];
     }
+    // Give the script proper path information.
+    if (!empty($themes[$key]->info['script'])) {
+      $themes[$key]->info['script'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['script'];
+    }
     // Give the screenshot proper path information.
     if (!empty($themes[$key]->info['screenshot'])) {
       $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
