Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v
retrieving revision 1.196
diff -u -p -r1.196 CHANGELOG.txt
--- CHANGELOG.txt	10 May 2007 19:55:23 -0000	1.196
+++ CHANGELOG.txt	14 May 2007 16:41:57 -0000
@@ -36,6 +36,7 @@ Drupal 6.0, xxxx-xx-xx (development vers
     * Themed the installer with the Garland theme.
     * Added form to provide initial site information during installation.
     * Added ability to provide extra installation steps programmatically.
+    * Made it possible to import interface translations in install time.
 
 Drupal 5.0, 2007-01-15
 ----------------------
Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.48
diff -u -p -r1.48 install.php
--- install.php	14 May 2007 13:43:29 -0000	1.48
+++ install.php	14 May 2007 16:41:58 -0000
@@ -436,7 +436,7 @@ function install_select_profile() {
     }
 
     drupal_maintenance_theme();
-    install_task_list('profile');
+    install_task_list('profile-select');
 
     drupal_set_title(st('Select an installation profile'));
     print theme('install_page', drupal_get_form('install_select_profile_form', $profiles));
@@ -474,7 +474,7 @@ function install_select_profile_form($pr
  * Find all .po files for the current profile.
  */
 function install_find_locales($profilename) {
-  $locales = file_scan_directory('./profiles/'. $profilename, '\.po$', array('.', '..', 'CVS'), 0, FALSE);
+  $locales = file_scan_directory('./profiles/'. $profilename .'/po', '\.po$', array('.', '..', 'CVS'), 0, FALSE);
   array_unshift($locales, (object) array('name' => 'en'));
   return $locales;
 }
@@ -492,8 +492,26 @@ function install_select_locale($profilen
   // Find all available locales.
   $locales = install_find_locales($profilename);
 
-  // Don't need to choose locale if only one (English) is available.
-  if (sizeof($locales) == 1) {
+  // If only the built-in (English) language is available,
+  // and we are using the default profile, inform the user
+  // that the installer can be localized. Otherwise we assume
+  // the user know what he is doing.
+  if (count($locales) == 1) {
+    if ($profilename == 'default') {
+      drupal_maintenance_theme();
+      install_task_list('profile-select');
+      drupal_set_title(st('Localization of the Drupal installer'));
+      $output = '<p>'. st('Drupal is capable of being installed in any language from the start, not only English. A language pack might be available in your language already. To be able to install Drupal and use it in your language from the start, follow these steps:') . '</p>';
+      $output .= '<ul><li>'. st('Check whether <a href="@translations" target="_blank">a translation of this Drupal version</a> is available in your language.', array('@translations' => 'http://drupal.org/project/Translations')) .'</li>';
+      $output .= '<li>'. st('If available, download the translation pack and extract it to your Drupal root directory. Translation files will get placed into different directories.') .'</li>';
+      $output .= '<li>'. st('Continue the installation by reloading this page and select from the listed languages.') .'</li>';
+      $output .= '</ul><p>' . st('How should the installation continue?') .'</p>';
+      $output .= '<ul><li><a href="install.php?profile='. $profilename . '&amp;locale=en">'. st('Continue installation in English') .'</a></li><li><a href="install.php?profile='. $profilename . '">'. st('Reload this page to select a language') .'</a></li></ul>';
+      print theme('install_page', $output);
+      exit;
+    }
+    // One language, but not the default profile, assume
+    // the user knows what he is doing.
     return FALSE;
   }
   else {
@@ -504,7 +522,7 @@ function install_select_locale($profilen
     }
 
     drupal_maintenance_theme();
-    install_task_list('locale');
+    install_task_list('locale-select');
 
     drupal_set_title(st('Choose your preferred language'));
     print theme('install_page', drupal_get_form('install_select_locale_form', $locales));
@@ -541,7 +559,7 @@ function install_select_locale_form($loc
  */
 function install_no_profile_error() {
   drupal_maintenance_theme();
-  install_task_list('profile');
+  install_task_list('profile-select');
   drupal_set_title(st('No profiles available'));
   print theme('install_page', '<p>'. st('We were unable to find any installer profiles. Installer profiles tell us what modules to enable and what schema to install in the database. A profile is necessary to continue with the installation process.') .'</p>');
   exit;
@@ -577,7 +595,7 @@ function install_missing_modules_error($
  * Tasks performed after the database is initialized. Called from install.php.
  */
 function install_tasks($profile, $task) {
-  global $base_url;
+  global $base_url, $install_locale;
   $output = '';
 
   // Bootstrap newly installed Drupal, while preserving existing messages.
@@ -591,6 +609,9 @@ function install_tasks($profile, $task) 
     variable_set('install_task', 'configure');
     $task = 'configure';
   }
+  
+  // We are using a list of if constructs here to allow for
+  // passing from one task to the other in the same request.
 
   if ($task == 'configure') {
     drupal_set_title(st('Configure site'));
@@ -621,56 +642,96 @@ function install_tasks($profile, $task) 
     drupal_process_form('install_configure_form', $form, $form_state);
     if (empty($form_state['redirect'])) {
       $output = drupal_render_form('install_configure_form', $form);
-      install_task_list('configure');
+    }
+    else {
+      $task = 'profile';
     }
   }
 
-  // If we have no output, then install.php is done and now we turn to
-  // our profile to run it's own tasks.
-  if (empty($output)) {
-    // Profile might define more tasks.
-    $function = $profile .'_profile_final';
+  // If found an unknown task or the 'profile-custom' task, which is
+  // reserved for profiles, hand over the control to the profile,
+  // so it can run any number of custom tasks it defines.
+  if (!in_array($task, install_reserved_tasks())) {
+    $function = $profile .'_profile_tasks';
     if (function_exists($function)) {
-      // More tasks are required by this profile.
+      // The profile needs to run more code, maybe even more tasks.
       // $task is sent through as a reference and may be changed!
       $output = $function($task);
     }
+    
+    // If the profile doesn't move on to a new task we assume
+    // that it is done: we let the installer regain control and
+    // proceed with the locale import.
+    if ($task == 'profile') {
+      $task = 'locale-import';
+    }
+  }
+    
+  // Import interface translations for the enabled modules, after
+  // any changes made by the profile through the profile forms.
+  if ($task == 'locale-import') {
+    if (!empty($install_locale) && ($install_locale != 'en')) {
+      include_once 'includes/locale.inc';
+      // Enable installation language as default site language.
+      locale_add_language($install_locale, NULL, NULL, NULL, NULL, NULL, 1, TRUE);
+      // Collect files to import for this language.
+      $batch = locale_batch_installer($install_locale);
+      if (!empty($batch)) {
+        // Start a batch, switch to 'locale-batch' task. We need to
+        // set the variable here, because batch_process() redirects.
+        variable_set('install_task', 'locale-batch');
+        batch_set($batch);
+        $path = $base_url .'/install.php?locale='. $install_locale .'&profile='. $profile;
+        batch_process($path, $path);
+      }
+    }
+    // Found nothing to import or not foreign language, go to next task.
+   $task = 'finished';
+  }
+  
+  // We are running a batch import of interface translation files.
+  // This might run in multiple HTTP requests, constantly redirecting
+  // to the same address, until the batch finished callback is invoked
+  // and the task advances to 'finished'.
+  if ($task == 'locale-batch') {
+    include_once 'includes/batch.inc';
+    include_once 'includes/locale.inc';
+    $output .= _batch_page();
+  }
+
+  // Display a 'finished' page to user.
+  if ($task == 'finished') {
+    drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
+    $output = '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
+    $messages = drupal_set_message();
+    $output .= '<p>'. (isset($messages['error']) ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
+    $task = 'done';
+  }
+
+  // The end of the install process. Remember profile used.
+  if ($task == 'done') {
+    // Rebuild menu to get content type links registered by the profile,
+    // and possibly any other menu items created through the tasks.
+    menu_rebuild();
+    variable_set('install_profile', $profile);
+  }
 
-    // Safety: if the profile doesn't do anything, catch it.
-    if ($task == 'configure') {
-      $task = 'finished';
-    }
-
-    // Display default 'finished' page to user. A custom finished page
-    // can be displayed by skipping this step and going to 'done' directly.
-    if ($task == 'finished') {
-      drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
-      $page = '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
-      $page .= $output;
-      $messages = drupal_set_message();
-      $page .= '<p>'. (isset($messages['error']) ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
-      $output = $page;
-      $task = 'done';
-    }
-
-    // The end of the install process. Remember profile used.
-    if ($task == 'done') {
-      // Rebuild menu to get content type links registered by the profile,
-      // and possibly any other menu items created through the tasks.
-      menu_rebuild();
-      variable_set('install_profile', $profile);
-    }
-
-    // Set task for user, and remember the task in the database.
-    install_task_list($task);
-    variable_set('install_task', $task);
+  // Set task for user, and remember the task in the database.
+  install_task_list($task);
+  variable_set('install_task', $task);
 
-  }
   // Output page.
   print theme('maintenance_page', $output);
 }
 
 /**
+ * The list of reserved tasks to run in the installer.
+ */
+function install_reserved_tasks() {
+  return array('configure', 'locale-import', 'locale-batch', 'finished', 'done');
+}
+
+/**
  * Page to check installation requirements and report any errors.
  */
 function install_check_requirements($profile) {
@@ -700,25 +761,28 @@ function install_check_requirements($pro
 function install_task_list($active = NULL) {
   // Default list of tasks.
   $tasks = array(
-    'profile' => st('Choose profile'),
-    'locale' => st('Choose language'),
-    'requirements' => st('Verify requirements'),
-    'database' => st('Setup database'),
-    'configure' => st('Configure site'),
+    'profile-select' => st('Choose profile'),
+    'locale-select'  => st('Choose language'),
+    'requirements'   => st('Verify requirements'),
+    'database'       => st('Setup database'),
+    'configure'      => st('Configure site'),
   );
 
   $profiles = install_find_profiles();
-  // Remove profiles if only one profile exists.
-  if (count($profiles) == 1) {
-    unset($tasks['profile']);
-  }
-
-  // Remove locale if no install profiles use them.
   $profile = isset($_GET['profile']) && isset($profiles[$_GET['profile']]) ? $_GET['profile'] : '.';
-  if (count(install_find_locales($profile)) == 1) {
-    unset($tasks['locale']);
+  $locales = install_find_locales($profile);
+  
+  // Keep the profile selection task if we have more profiles or only the
+  // default profile is available and with only the built-in language, in
+  // which case we use this screen to present information about translations.
+  if (count($profiles) == 1) {
+    $first_profile = array_shift($profiles);
+    if ($first_profile->name != 'default' || count($locales) > 1) {
+      unset($tasks['profile-select']);
+    }
   }
 
+  // Add tasks defined by the profile.
   if ($profile) {
     $function = $profile .'_profile_task_list';
     if (function_exists($function)) {
@@ -730,7 +794,16 @@ function install_task_list($active = NUL
   }
 
   // Add finished step as the last task.
-  $tasks += array('finished' => st('Finished'));
+  $tasks += array(
+    'locale-batch' => st('Import translations'),
+    'finished'     => st('Finished')
+  );
+
+  // Remove locale related tasks if the install profile does not use them.
+  if (count($locales) == 1) {
+    unset($tasks['locale-select']);
+    unset($tasks['locale-batch']);
+  }
 
   // Let the theming function know that 'finished' and 'done'
   // include everything, so every step is completed.
@@ -865,6 +938,8 @@ function install_configure_form_validate
 }
 
 function install_configure_form_submit($form_values, $form, &$form_state) {
+  global $user;
+  
   variable_set('site_name', $form_values['site_name']);
   variable_set('site_mail', $form_values['site_mail']);
   variable_set('date_default_timezone', $form_values['date_default_timezone']);
@@ -875,6 +950,9 @@ function install_configure_form_submit($
   if (isset($form_values['clean_url'])) {
     variable_set('clean_url', $form_values['clean_url']);
   }
+  // The user is now logged in, but has no session ID yet, which
+  // would be required later in the request, so remember it.
+  $user->sid = session_id();
 
   return 'finished';
 }
Index: includes/install.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.inc,v
retrieving revision 1.38
diff -u -p -r1.38 install.inc
--- includes/install.inc	8 May 2007 16:36:55 -0000	1.38
+++ includes/install.inc	14 May 2007 16:41:58 -0000
@@ -578,7 +578,7 @@ function st($string, $args = array()) {
 
   if (!isset($locale_strings)) {
     $locale_strings = array();
-    $filename = './profiles/'. $profile .'/'. $install_locale .'.po';
+    $filename = './profiles/'. $profile .'/po/'. $install_locale .'.po';
     if (file_exists($filename)) {
       require_once './includes/locale.inc';
       $file = (object) array('filepath' => $filename);
Index: includes/locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.123
diff -u -p -r1.123 locale.inc
--- includes/locale.inc	14 May 2007 13:43:32 -0000	1.123
+++ includes/locale.inc	14 May 2007 16:42:00 -0000
@@ -281,12 +281,13 @@ function locale_languages_predefined_for
   if (isset($form_values['name'])) {
     // Custom language form.
     locale_add_language($langcode, $form_values['name'], $form_values['native'], $form_values['direction'], $form_values['domain'], $form_values['prefix']);
+    drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($form_values['name']), '@locale-help' => url('admin/help/locale'))));
   }
   else {
     // Predefined language selection.
     $predefined = _locale_get_predefined_list();
-    $lang = &$predefined[$langcode];
-    locale_add_language($langcode, $lang[0], isset($lang[1]) ? $lang[1] : $lang[0], isset($lang[2]) ? $lang[2] : 0, '', $langcode);
+    locale_add_language($langcode);
+    drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($predefined[$langcode][0]), '@locale-help' => url('admin/help/locale'))));
   }
 
   $form_state['redirect'] = 'admin/settings/language';
@@ -602,8 +603,8 @@ function locale_translate_import_form_su
     $langcode = $form_values['langcode'];
     if (!isset($languages[$langcode])) {
       $predefined = _locale_get_predefined_list();
-      $lang = &$predefined[$langcode];
-      locale_add_language($langcode, $lang[0], isset($lang[1]) ? $lang[1] : '', isset($lang[2]) ? $lang[2] : 0, '', '', FALSE);
+      locale_add_language($langcode);
+      drupal_set_message(t('The language %language has been created.', array('%language' => t($predefined[$langcode][0]))));
     }
 
     // Now import strings into the language
@@ -831,32 +832,41 @@ function locale_translate_delete($lid) {
  * @param $prefix
  *   Optional path prefix for the language. Defaults to the
  *   language code if omitted.
- * @param $verbose
- *   Switch to omit the verbose message to the user when used
- *   only as a utility function.
+ * @param $enabled
+ *   Optionally TRUE to enable the language when created or FALSE to disable.
+ * @param $default
+ *   Optionall set this language to be the default.
  */
-function locale_add_language($langcode, $name, $native, $direction = LANGUAGE_RTL, $domain = '', $prefix = '', $verbose = TRUE) {
+function locale_add_language($langcode, $name = NULL, $native = NULL, $direction = LANGUAGE_RTL, $domain = '', $prefix = '', $enabled = FALSE, $default = FALSE) {
   // Default prefix on language code.
   if (empty($prefix)) {
     $prefix = $langcode;
   }
+  
+  // If name was not set, we add a predefined language.
+  if (!isset($name)) {
+    $predefined = _locale_get_predefined_list();
+    $name = $predefined[$langcode][0];
+    $native = isset($predefined[$langcode][1]) ? $predefined[$langcode][1] : $predefined[$langcode][0];
+    $direction = isset($predefined[$langcode][2]) ? $predefined[$langcode][2] : LANGUAGE_RTL;
+  }
 
-  db_query("INSERT INTO {languages} (language, name, native, direction, domain, prefix) VALUES ('%s', '%s', '%s', %d, '%s', '%s')", $langcode, $name, $native, $direction, $domain, $prefix);
+  db_query("INSERT INTO {languages} (language, name, native, direction, domain, prefix, enabled) VALUES ('%s', '%s', '%s', %d, '%s', '%s', %d)", $langcode, $name, $native, $direction, $domain, $prefix, $enabled);
 
   // Add empty translations for strings (to optimize locale())
   $result = db_query("SELECT lid FROM {locales_source}");
   while ($string = db_fetch_object($result)) {
     db_query("INSERT INTO {locales_target} (lid, language, translation) VALUES (%d,'%s', '')", $string->lid, $langcode);
   }
-
-  // Set message depending on the verbosity required.
-  if ($verbose) {
-    drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($name), '@locale-help' => url('admin/help/locale'))));
-  }
-  else {
-    drupal_set_message(t('The language %language has been created.', array('%language' => t($name))));
+  
+  // Only set it as default if enabled.
+  if ($enabled && $default) {
+    variable_set('language_default', (object) array('language' => $langcode, 'name' => $name, 'native' => $native, 'direction' => $direction, 'enabled' => (int) $enabled, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => $prefix, 'weight' => 0));
   }
 
+  // Increment count of enabled languages.
+  variable_set('language_count', variable_get('language_count', 1) + 1);
+
   watchdog('locale', 'The %language language (%code) has been created.', array('%language' => $name, '%code' => $langcode));
 }
 /**
@@ -1906,7 +1916,7 @@ function _locale_get_predefined_list() {
     "af" => array("Afrikaans"),
     "ak" => array("Akan"),
     "am" => array("Amharic", "አማርኛ"),
-    "ar" => array("Arabic", /* Left-to-right marker "‭" */ "العربية", 1),
+    "ar" => array("Arabic", /* Left-to-right marker "‭" */ "العربية", LANGUAGE_RTL),
     "as" => array("Assamese"),
     "av" => array("Avar"),
     "ay" => array("Aymara"),
@@ -1941,7 +1951,7 @@ function _locale_get_predefined_list() {
     "es" => array("Spanish", "Español"),
     "et" => array("Estonian", "Eesti"),
     "eu" => array("Basque", "Euskera"),
-    "fa" => array("Persian", /* Left-to-right marker "‭" */ "فارسی", 1),
+    "fa" => array("Persian", /* Left-to-right marker "‭" */ "فارسی", LANGUAGE_RTL),
     "ff" => array("Fulah", "Fulfulde"),
     "fi" => array("Finnish", "Suomi"),
     "fj" => array("Fiji"),
@@ -1955,7 +1965,7 @@ function _locale_get_predefined_list() {
     "gu" => array("Gujarati"),
     "gv" => array("Manx"),
     "ha" => array("Hausa"),
-    "he" => array("Hebrew", /* Left-to-right marker "‭" */ "עברית", 1),
+    "he" => array("Hebrew", /* Left-to-right marker "‭" */ "עברית", LANGUAGE_RTL),
     "hi" => array("Hindi", "हिन्दी"),
     "ho" => array("Hiri Motu"),
     "hr" => array("Croatian", "Hrvatski"),
@@ -2022,7 +2032,7 @@ function _locale_get_predefined_list() {
     "pa" => array("Punjabi"),
     "pi" => array("Pali"),
     "pl" => array("Polish", "Polski"),
-    "ps" => array("Pashto", /* Left-to-right marker "‭" */ "پښتو", 1),
+    "ps" => array("Pashto", /* Left-to-right marker "‭" */ "پښتو", LANGUAGE_RTL),
     "pt" => array("Portuguese, Portugal", "Português"),
     "pt-br" => array("Portuguese, Brazil", "Português"),
     "qu" => array("Quechua"),
@@ -2066,7 +2076,7 @@ function _locale_get_predefined_list() {
     "ty" => array("Tahitian"),
     "ug" => array("Uighur"),
     "uk" => array("Ukrainian", "Українська"),
-    "ur" => array("Urdu", /* Left-to-right marker "‭" */ "اردو", 1),
+    "ur" => array("Urdu", /* Left-to-right marker "‭" */ "اردو", LANGUAGE_RTL),
     "uz" => array("Uzbek", "o'zbek"),
     "ve" => array("Venda"),
     "vi" => array("Vietnamese", "Tiếng Việt"),
@@ -2083,3 +2093,95 @@ function _locale_get_predefined_list() {
 /**
  * @} End of "locale-api-languages-predefined"
  */
+
+/**
+ * @defgroup locale-autoimport Automatic interface translation import
+ * @{
+ */
+
+/**
+ * Prepare a batch to use to import translations.
+ *
+ * @param $langcode
+ *   Language code to import translations for.
+ * @return
+ *   A batch structure or FALSE if no files found.
+ */
+function locale_batch_installer($langcode) {
+
+  // Collect all files to import for all enabled modules and themes.
+  $files = array();
+  $result = db_query("SELECT name, filename FROM {system} WHERE status = 1");
+  while ($component = db_fetch_object($result)) {
+    // Collect all files for all components, names as $langcode.po or
+    // with names ending with $langcode.po. This allows for filenames
+    // like node-module.de.po to let translators use small files and
+    // be able to import in smaller chunks.
+    $files = array_merge($files, file_scan_directory(dirname($component->filename) .'/po/', '(^|\.)'. $langcode .'\.po$', array('.', '..', 'CVS'), 0, FALSE));
+  }
+  
+  if (count($files)) {
+    $$operations = array();
+    foreach($files as $file) {
+      // We call _locale_batch_import for every batch operation
+      // with the file name and language code.
+      $operations[] = array('_locale_batch_import', array($file->filename, $langcode));
+    }
+    return _locale_batch_build($operations, '_locale_batch_installer_finished');
+  }
+  
+  // Found nothing to import.
+  return FALSE;
+}
+
+/**
+ * Build a locale batch from an array of files.
+ *
+ * @param $operations
+ *   Array of operations to perform
+ * @param $finished
+ *   A finished callback to use for the batch
+ * @return
+ *   A batch structure
+ */
+function _locale_batch_build($operations, $finished) {
+  $t = get_t();
+  if (count($operations)) {
+    $batch = array(
+      'operations'    => $operations,
+      'title'         => $t('Importing interface translations'),
+      'init_message'  => $t('Starting import'),
+      'error_message' => $t('Error importing interface translations'),
+      'finished'      => $finished,
+    );
+    return $batch;
+  }
+  return FALSE;
+}
+
+/**
+ * Perform interface translation import as a batch step.
+ *
+ * @param $filepath
+ *   Path to a file to import.
+ * @param $langcode
+ *   Language to import file into.
+ * @param $results
+ *   Contains a list of files imported.
+ */
+function _locale_batch_import($filepath, $langcode, &$context) {
+  $file = (object) array('filename' => basename($filepath), 'filepath' => $filepath);
+  _locale_import_read_po('db-store', $file, 'keep', $langcode);
+  $context['results'][] = $filepath;
+}
+
+/**
+ * Batch callback invoked when installer import processing finishes.
+ * Advance installer task to the finished screen.
+ */
+function _locale_batch_installer_finished($success, $results) {
+  variable_set('install_task', 'finished');
+}
+/**
+ * @} End of "locale-autoimport"
+ */
Index: profiles/default/default.profile
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.profile,v
retrieving revision 1.10
diff -u -p -r1.10 default.profile
--- profiles/default/default.profile	10 May 2007 19:55:24 -0000	1.10
+++ profiles/default/default.profile	14 May 2007 16:42:00 -0000
@@ -28,7 +28,10 @@ function default_profile_details() {
  * Return a list of tasks that this profile supports.
  *
  * @return
- *   A keyed array of tasks the profile will perform during the _final stage.
+ *   A keyed array of tasks the profile will perform during
+ *   the final stage. The keys of the array will be used internally,
+ *   while the values will be displayed to the user in the installer
+ *   task list.
  */
 function default_profile_task_list() {
 }
@@ -36,19 +39,23 @@ function default_profile_task_list() {
 /**
  * Perform any final installation tasks for this profile.
  *
- * You can implement a state machine here to walk the user through
- * more tasks, by setting $task to something other then the reserved
- * 'configure', 'finished' and 'done' values. The installer goes
- * through the configure-finished-done tasks in this order, if you
- * don't modify $task. If you implement your custom tasks, this
- * function will get called in every HTTP request (for form
- * processing, printing your information screens and so on) until
- * you advance to the 'finished' or 'done' tasks. Once ready with
- * your profile's tasks, set $task to 'finished' and optionally
- * return a final message to be included on the default final
- * install page. Alternatively you can set $task to 'done' and
- * return a completely custom finished page. In both cases, you
- * hand the control back to the installer.
+ * The installer goes through the configure -> locale-import ->
+ * locale-batch -> finished -> done tasks in this order, if you
+ * don't implement this function in your profile.
+ *
+ * If this function is implemented, you can have any number of
+ * custom tasks to perform, implementing a state machine here to
+ * walk the user through those tasks, by setting $task to something
+ * other then the reserved tasks listed in install_reserved_tasks()
+ * and the 'profile' task this function gets called with for first
+ * time. If you implement your custom tasks, this function will get called
+ * in every HTTP request (for form processing, printing your
+ * information screens and so on) until you advance to the
+ * 'locale-import' task, with which you hand control back to the
+ * installer.
+ *
+ * You should define the list of custom tasks you implement by
+ * returning an array of them in hook_profile_task_list().
  *
  * Should a profile want to display a form here, it can; it should set
  * the task using variable_set('install_task', 'new_task') and use
@@ -56,16 +63,14 @@ function default_profile_task_list() {
  * drupal_get_form().
  *
  * @param $task
- *   The current $task of the install system. When hook_profile_final()
- *   is first called, this is 'configure' (the last built-in task of
- *   the Drupal installer).
+ *   The current $task of the install system. When hook_profile_tasks()
+ *   is first called, this is 'profile'.
  *
  * @return
- *   An optional HTML string to display to the user. Used as part of the
- *   completed page if $task is set to 'finished', or used to display a
- *   complete page in all other cases.
+ *   An optional HTML string to display to the user. Only used if you
+ *   modify the $task, otherwise discarded.
  */
-function default_profile_final(&$task) {
+function default_profile_tasks(&$task) {
 
   // Insert default user-defined node types into the database. For a complete
   // list of available node type attributes, refer to the node type API
@@ -108,7 +113,4 @@ function default_profile_final(&$task) {
   $theme_settings = variable_get('theme_settings', array());
   $theme_settings['toggle_node_info_page'] = FALSE;
   variable_set('theme_settings', $theme_settings);
-
-  // Let the installer know we're finished:
-  $task = 'finished';
 }
