diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 6d6de4ee57bfd49938b28e7c56bbe0ee09ec7ae7..c5054ad00b4c2aa3113aa7bfd800ffe55127a0a9 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -7,6 +7,11 @@ Drupal 6.0, xxxx-xx-xx (development version)
 - Drupal works with error reporting set to E_ALL.
 - Added scripts/drupal.sh to execute Drupal code from the command line. Useful to use Drupal as a framework to build command-line tools.
 - Used the Garland theme for the installation and maintenance pages.
+- Added generic language management functionality.
+    * Support for right to left scripts.
+    * Language detection based on parts of the URL.
+    * Browser based language detection.
+- Language dependent path aliases.
 
 Drupal 5.0, 2007-01-15
 ----------------------
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 3b3d1589fdcbc08146770de9adaded9ba14043f7..994763fb35280745fbc4be9538bd8434a912b176 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -995,5 +995,5 @@ function language_list($field = 'language', $reset = FALSE) {
  * Default language used on the site
  */
 function language_default() {
-  return variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'direction' => 0, 'native' => 'English'));
+  return variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0));
 }
diff --git a/includes/language.inc b/includes/language.inc
index d145fd7f74b6c465a2286b119b588a5984de79d5..0d87f6a2cfd19ba30d5770ab3b0cd8958fb00211 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -11,12 +11,12 @@
  */
 function language_initialize() {
   global $user;
-  
+
   $mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
   switch($mode) {
     case LANGUAGE_NEGOTIATION_NONE:
       return language_default();
-    
+
     case LANGUAGE_NEGOTIATION_DOMAIN:
       $languages = language_list();
       foreach($languages as $language) {
@@ -26,7 +26,7 @@ function language_initialize() {
         }
       }
       return language_default();
-    
+
     case LANGUAGE_NEGOTIATION_PATH_DEFAULT:
     case LANGUAGE_NEGOTIATION_PATH:
       $languages = language_list('prefix');
@@ -41,18 +41,18 @@ function language_initialize() {
       }
       break;
   }
-  
+
   // User language.
   $languages = language_list();
   if ($user->uid && isset($languages[$user->language])) {
     return $languages[$user->language];
   }
-  
+
   // Browser accept-language parsing.
   if ($language = language_from_browser()) {
     return $language;
   }
-  
+
   // Fall back on the default if everything else fails.
   return language_default();
 }
@@ -76,7 +76,7 @@ function language_from_browser() {
       }
     }
   }
- 
+
   // Order the codes by quality
   arsort($browser_langs);
 
@@ -121,12 +121,12 @@ function language_url_rewrite(&$path, &$options) {
         // Intentionally no break here.
 
       case LANGUAGE_NEGOTIATION_PATH:
-        if (isset($path_language->prefix) && $path_language->prefix) {        
+        if (isset($path_language->prefix) && $path_language->prefix) {
           // Get alias if not already aliased.
           if (!$options['alias']) {
             $path = drupal_get_path_alias($path, $path_language->language);
             $options['alias'] = TRUE;
-          }   
+          }
           $path = empty($path) ? $path_language->prefix : $path_language->prefix .'/'. $path;
         }
         break;
diff --git a/includes/locale.inc b/includes/locale.inc
index 825f438a083880963068565f412239adb001571f..dd13929731e79ebea0c721e25797bde420e8be10 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -185,7 +185,7 @@ function locale_custom_language_form() {
  * Editing screen for a particular language.
  *
  * @param $langcode
- *   Languauge code of the language to edit.
+ *   Language code of the language to edit.
  */
 function _locale_admin_manage_edit_screen($langcode) {
   if ($language = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $langcode))) {
@@ -239,14 +239,14 @@ function _locale_language_form(&$form, $language = NULL) {
       '#description' => t('This should be an <a href="@rfc4646">RFC 4646</a> compliant language identifier. Basic tags use a country code with an optional script or regional variant name, like "en", "en-US" and "zh-Hant".', array('@rfc4646' => 'http://www.ietf.org/rfc/rfc4646.txt')),
     );
   }
-  $form['langname'] = array('#type' => 'textfield',
+  $form['name'] = array('#type' => 'textfield',
     '#title' => t('Language name in English'),
     '#maxlength' => 64,
     '#default_value' => @$language->name,
     '#required' => TRUE,
     '#description' => t('Name of the language. Will be available for translation in all languages.'),
   );
-  $form['langnative'] = array('#type' => 'textfield',
+  $form['native'] = array('#type' => 'textfield',
     '#title' => t('Native language name'),
     '#maxlength' => 64,
     '#default_value' => @$language->native,
@@ -289,10 +289,10 @@ function _locale_admin_manage_add_screen() {
  */
 function locale_add_language_form_validate($form_id, $form_values) {
   if ($duplicate = db_num_rows(db_query("SELECT language FROM {languages} WHERE language = '%s'", $form_values['langcode'])) != 0) {
-    form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_values['langname'], '%code' => $form_values['langcode'])));
+    form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_values['name'], '%code' => $form_values['langcode'])));
   }
 
-  if (!isset($form_values['langname'])) {
+  if (!isset($form_values['name'])) {
     // Predefined language selection.
     $predefined = _locale_get_predefined_list();
     if (!isset($predefined[$form_values['langcode']])) {
@@ -309,9 +309,9 @@ function locale_add_language_form_validate($form_id, $form_values) {
  * Process the language addition form submission.
  */
 function locale_add_language_form_submit($form_id, $form_values) {
-  if (isset($form_values['langname'])) {
+  if (isset($form_values['name'])) {
     // Custom language form.
-    _locale_add_language($form_values['langcode'], $form_values['langname'], $form_values['langnative'], $form_values['direction'], $form_values['domain'], $form_values['prefix']);
+    _locale_add_language($form_values['langcode'], $form_values['name'], $form_values['native'], $form_values['direction'], $form_values['domain'], $form_values['prefix']);
   }
   else {
     // Predefined language selection.
@@ -346,14 +346,13 @@ function locale_edit_language_form_validate($form_id, $form_values) {
  * Process the language editing form submission.
  */
 function locale_edit_language_form_submit($form_id, $form_values) {
-  db_query("UPDATE {languages} SET name = '%s', native = '%s', domain = '%s', prefix = '%s', direction = %d WHERE language = '%s'", $form_values['langname'], $form_values['langnative'], $form_values['domain'], $form_values['prefix'], $form_values['direction'], $form_values['langcode']);
+  db_query("UPDATE {languages} SET name = '%s', native = '%s', domain = '%s', prefix = '%s', direction = %d WHERE language = '%s'", $form_values['name'], $form_values['native'], $form_values['domain'], $form_values['prefix'], $form_values['direction'], $form_values['langcode']);
   $default = language_default();
   if ($default->language == $form_values['langcode']) {
-    $default->name = $form_values['langname'];
-    $default->native = $form_values['langnative'];
-    $default->domain = $form_values['domain'];
-    $default->prefix = $form_values['prefix'];
-    $default->direction = $form_values['direction'];
+    $properties = array('name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight');
+    foreach($properties as $keyname) {
+      $default->$keyname = $form_values[$keyname];
+    }
     variable_set('language_default', $default);
   }
   return 'admin/build/locale';
@@ -397,23 +396,21 @@ function locale_configure_language_form_submit($form_id, $form_values) {
  * User interface for the translation import screen.
  */
 function _locale_admin_import() {
-  $languages = language_list();
-  $names = array();
-  foreach ($languages as $langcode => $language) {
-    $names[$langcode] = t($language->name);
-  }
   // English means the factory default strings,
   // we should not import into it.
-  unset($languages['en']);
+  $names = locale_language_list('name', TRUE);
+  unset($names['en']);
 
-  if (!count($languages)) {
+  if (!count($names)) {
     $languages = _locale_prepare_predefined_list();
+    $default = array_shift(array_keys($languages));
   }
   else {
     $languages = array(
-      t('Already added languages') => $languages,
+      t('Already added languages') => $names,
       t('Languages not yet added') => _locale_prepare_predefined_list()
     );
+    $default = array_shift(array_keys($names));
   }
 
   $form = array();
@@ -427,7 +424,8 @@ function _locale_admin_import() {
   );
   $form['import']['langcode'] = array('#type' => 'select',
     '#title' => t('Import into'),
-    '#options' => $names,
+    '#options' => $languages,
+    '#default_value' => $default,
     '#description' => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, then it will be added.'),
   );
   $form['import']['mode'] = array('#type' => 'radios',
@@ -445,33 +443,40 @@ function _locale_admin_import() {
  * Process the locale import form submission.
  */
 function _locale_admin_import_submit($form_id, $form_values) {
-  // Add language, if not yet supported
-  $languages = language_list('language', TRUE);
-  if (!isset($languages[$form_values['langcode']])) {
-    $predefined = _locale_get_predefined_list();
-    $lang = &$predefined[$form_values['langcode']];
-    _locale_add_language($form_values['langcode'], $lang[0], isset($lang[1]) ? $lang[1] : '', isset($lang[2]) ? $lang[2] : 0, '', '', FALSE);
-  }
+  // Ensure we have the file uploaded
+  if ($file = file_check_upload('file')) {
+
+    // Add language, if not yet supported
+    $languages = language_list('language', TRUE);
+    if (!isset($languages[$form_values['langcode']])) {
+      $predefined = _locale_get_predefined_list();
+      $lang = &$predefined[$form_values['langcode']];
+      _locale_add_language($form_values['langcode'], $lang[0], isset($lang[1]) ? $lang[1] : '', isset($lang[2]) ? $lang[2] : 0, '', '', FALSE);
+    }
 
-  // Now import strings into the language
-  $file = file_check_upload('file');
-  if ($ret = _locale_import_po($file, $form_values['langcode'], $form_values['mode']) == FALSE) {
-    $message = t('The translation import of %filename failed.', array('%filename' => $file->filename));
-    drupal_set_message($message, 'error');
-    watchdog('locale', $message, WATCHDOG_ERROR);
+    // Now import strings into the language
+    if ($ret = _locale_import_po($file, $form_values['langcode'], $form_values['mode']) == FALSE) {
+      $message = t('The translation import of %filename failed.', array('%filename' => $file->filename));
+      drupal_set_message($message, 'error');
+      watchdog('locale', $message, WATCHDOG_ERROR);
+    }
+  }
+  else {
+    drupal_set_message(t('File to import not found.'), 'error');
+    return 'admin/build/locale/string/import';
   }
 
   return 'admin/build/locale';
 }
 
-function _locale_export_po_form($languages) {
+function _locale_export_po_form($names) {
   $form['export'] = array('#type' => 'fieldset',
     '#title' => t('Export translation'),
     '#collapsible' => TRUE,
   );
   $form['export']['langcode'] = array('#type' => 'select',
     '#title' => t('Language name'),
-    '#options' => array_keys($languages),
+    '#options' => $names,
     '#description' => t('Select the language you would like to export in gettext Portable Object (.po) format.'),
   );
   $form['export']['submit'] = array('#type' => 'submit', '#value' => t('Export'));
@@ -496,17 +501,14 @@ function _locale_export_pot_form() {
  * User interface for the translation export screen
  */
 function _locale_admin_export_screen() {
-  $languages = language_list();
-  $names = array();
-  foreach ($languages as $langcode => $language) {
-    $names[$langcode] = t($language->name);
-  }
-  unset($languages['en']);
+  // Omit English from the exportable languages list
+  $names = locale_language_list('name', TRUE);
+  unset($names['en']);
 
   $output = '';
   // Offer language specific export if any language is set up
-  if (count($languages)) {
-    $output = drupal_get_form('_locale_export_po_form', $languages);
+  if (count($names)) {
+    $output = drupal_get_form('_locale_export_po_form', $names);
   }
 
   $output .= drupal_get_form('_locale_export_pot_form');
@@ -515,10 +517,11 @@ function _locale_admin_export_screen() {
 }
 
 /**
- * Process a locale export form submissions.
+ * Process a locale export form submission.
  */
 function _locale_export_po_form_submit($form_id, $form_values) {
-  _locale_export_po($form_values['langcode']);
+  // If template is required, language code is not given
+  _locale_export_po(isset($form_values['langcode']) ? $form_values['langcode'] : NULL);
 }
 
 // ---------------------------------------------------------------------------------
@@ -624,7 +627,7 @@ function _locale_string_edit($lid) {
 function _locale_string_edit_submit($form_id, $form_values) {
   $lid = $form_values['lid'];
   foreach ($form_values['translations'] as $key => $value) {
-    $trans = db_fetch_object(db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND languauge = '%s'", $lid, $key));
+    $trans = db_fetch_object(db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $key));
     if (isset($trans->translation)) {
       db_query("UPDATE {locales_target} SET translation = '%s' WHERE lid = %d AND language = '%s'", $value, $lid, $key);
     }
@@ -1297,13 +1300,15 @@ function _locale_import_parse_quoted($string) {
 /**
  * Exports a Portable Object (Template) file for a language
  *
- * @param $language Selects a language to generate the output for
+ * @param $language
+ *   Language code to generate the output for, or NULL if generating
+ *   translation template.
  */
-function _locale_export_po($language) {
+function _locale_export_po($language = NULL) {
   global $user;
   $header = '';
   // Get language specific strings, or all strings
-  if ($language) {
+  if (isset($language)) {
     $meta = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $language));
     $result = db_query("SELECT s.lid, s.source, s.location, t.translation, t.plid, t.plural FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE t.language = '%s' ORDER BY t.plid, t.plural", $language);
   }
@@ -1326,9 +1331,9 @@ function _locale_export_po($language) {
   }
 
   // Generating Portable Object file for a language
-  if ($language) {
+  if (isset($language)) {
     $filename = $language .'.po';
-    $header .= "# $meta->name translation of ". variable_get('site_name', 'Drupal') ."\n";
+    $header = "# $meta->name translation of ". variable_get('site_name', 'Drupal') ."\n";
     $header .= '# Copyright (c) '. date('Y') .' '. $user->name .' <'. $user->mail .">\n";
     $header .= "#\n";
     $header .= "msgid \"\"\n";
@@ -1351,7 +1356,7 @@ function _locale_export_po($language) {
   // Generating Portable Object Template
   else {
     $filename = 'drupal.pot';
-    $header .= "# LANGUAGE translation of PROJECT\n";
+    $header = "# LANGUAGE translation of PROJECT\n";
     $header .= "# Copyright (c) YEAR NAME <EMAIL@ADDRESS>\n";
     $header .= "#\n";
     $header .= "msgid \"\"\n";
@@ -1381,9 +1386,10 @@ function _locale_export_po($language) {
         print '#: '. $message['comment'] ."\n";
       }
       print 'msgid '. _locale_export_print($message['msgid']);
-      if ($plural = $message['plural']) {
+      if (!empty($message['plural'])) {
+        $plural = $message['plural'];
         print 'msgid_plural '. _locale_export_print($parent[$plural]['msgid']);
-        if ($language) {
+        if (isset($language)) {
           $translation = $message['translation'];
           for ($i = 0; $i < $meta->plurals; $i++) {
             print 'msgstr['. $i .'] '. _locale_export_print($translation);
@@ -1405,7 +1411,7 @@ function _locale_export_po($language) {
         }
       }
       else {
-        if ($language) {
+        if (isset($language)) {
           print 'msgstr '. _locale_export_print($message['translation']);
         }
         else {
@@ -1440,12 +1446,18 @@ function _locale_export_print($str) {
     $parts = array_merge($parts, $curparts);
   }
 
+  // Multiline string
   if (count($parts) > 1) {
     return "\"\"\n\"". implode("\"\n\"", $parts) ."\"\n";
   }
-  else {
+  // Single line string
+  elseif (count($parts) == 1) {
     return "\"$parts[0]\"\n";
   }
+  // No translation
+  else {
+    return "\"\"\n";
+  }
 }
 
 /**
@@ -1510,7 +1522,9 @@ function _locale_string_seek_query() {
     $query = array();
     $fields = array('string', 'language', 'searchin');
     foreach ($fields as $field) {
-      $query[$field] = !empty($_REQUEST[$field]) ? $_REQUEST[$field] : '';
+      if (isset($_REQUEST[$field])) {
+        $query[$field] = $_REQUEST[$field];
+      }
     }
   }
   return $query;
@@ -1580,9 +1594,12 @@ function _locale_string_seek() {
 
     if (count($rows)) {
       $output .= theme('table', $header, $rows);
+      if ($pager = theme('pager', NULL, 50)) {
+        $output .= $pager;
+      }
     }
-    if ($pager = theme('pager', NULL, 50)) {
-      $output .= $pager;
+    else {
+      $output .= t('No strings found for your search.');
     }
   }
 
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index c815d697aa6174249702429f034641430fc144ca..dcb2f9f851035fe26befa8939c60ff18c1f2727d 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -505,9 +505,9 @@ function forum_form_main($type, $edit = array()) {
  */
 function forum_form_forum($edit = array()) {
   $edit += array(
-    'name' => '', 
-    'description' => '', 
-    'tid' => NULL, 
+    'name' => '',
+    'description' => '',
+    'tid' => NULL,
     'weight' => 0,
   );
   $form['name'] = array('#type' => 'textfield',
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 745dc5e31d9e011ab8b1c09cb405512fd2c88e27..c3856f947b94b749772446fb9ce2938c5f6da12a 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -34,6 +34,7 @@ function locale_help($section) {
       return '<p>'. t("This page allows you to import a translation provided in the gettext Portable Object (.po) format. The easiest way to get your site translated is to obtain an existing Drupal translation and to import it. You can find existing translations on the <a href=\"@url\">Drupal translation page</a>. Note that importing a translation file might take a while.", array('@url' => 'http://drupal.org/project/translations')) .'</p>';
     case 'admin/build/locale/language/export':
       return '<p>'. t("This page allows you to export Drupal strings. The first option is to export a translation so it can be shared. The second option generates a translation template, which contains all Drupal strings, but without their translations. You can use this template to start a new translation using various software packages designed for this task.") .'</p>';
+    case 'admin/build/locale/string':
     case 'admin/build/locale/string/search':
       return '<p>'. t("It is often convenient to get the strings from your setup on the <a href=\"@export\">export page</a>, and use a desktop Gettext translation editor to edit the translations. On this page you can search in the translated and untranslated strings, and the default English texts provided by Drupal.", array("@export" => url("admin/build/locale/language/export"))) .'</p>';
     case 'admin/build/locale/language/configure':
@@ -315,11 +316,19 @@ function locale_language_name($lang) {
  * @param $field
  *   'name' => names in current language, localized
  *   'native' => native names
+ * @param $all
+ *   Boolean to return all languages or only enabled ones
  */
-function locale_language_list($field = 'name') {
-  $languages = language_list('enabled');
+function locale_language_list($field = 'name', $all = FALSE) {
+  if ($all) {
+    $languages = language_list();
+  }
+  else {
+    $languages = language_list('enabled');
+    $languages = $languages[1];
+  }
   $list = array();
-  foreach($languages[1] as $language) {
+  foreach($languages as $language) {
     $list[$language->language] = ($field == 'name') ? t($language->name) : $language->$field;
   }
   return $list;
diff --git a/sites/default/settings.php b/sites/default/settings.php
index eda139276f46c40edef89ef6b31bd90c8ed0057b..42df5e25d21bb2b19c0cde6e20b2a0b91aa23b92 100644
--- a/sites/default/settings.php
+++ b/sites/default/settings.php
@@ -112,7 +112,7 @@
  * It is not allowed to have a trailing slash; Drupal will add it
  * for you.
  */
-//$base_url = 'http://localhost';  // NO trailing slash!
+# $base_url = 'http://www.example.com';  // NO trailing slash!
 
 /**
  * PHP settings:
@@ -135,7 +135,6 @@
 ini_set('session.use_only_cookies', 1);
 ini_set('session.use_trans_sid',    0);
 ini_set('url_rewriter.tags',        '');
-ini_set('safe_mode', 1); // because my scripts actually take longer!
 
 /**
  * We try to set the correct cookie domain.
diff --git a/themes/garland/page.tpl.php b/themes/garland/page.tpl.php
index 2562513a761fdee1fb6b2e1523f14fdaab5d36fb..3663f6586a4abdfd05d12626f8b10e195e54755c 100644
--- a/themes/garland/page.tpl.php
+++ b/themes/garland/page.tpl.php
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language ?>" lang="<?php print $language ?>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>" lang="<?php print $language->language ?>">
   <head>
     <title><?php print $head_title ?></title>
     <?php print $head ?>