diff -urp --strip-trailing-cr ../drupal-6.x-dev/includes/locale.inc ./includes/locale.inc --- ../drupal-6.x-dev/includes/locale.inc 2007-11-11 17:14:45.000000000 +0100 +++ ./includes/locale.inc 2007-11-16 22:54:03.000000000 +0100 @@ -2416,22 +2416,31 @@ function _locale_get_predefined_list() { * Language code to import translations for. * @param $finished * Optional finished callback for the batch. + * @param $skip + * Array of component names to skip. Used in the installer for the + * second pass import, when most components are already imported. * @return * A batch structure or FALSE if no files found. */ -function locale_batch_by_language($langcode, $finished = '_locale_batch_installer_finished') { +function locale_batch_by_language($langcode, $finished = '_locale_batch_installer_initial_finished', $skip = array()) { // Collect all files to import for all enabled modules and themes. $files = array(); - $result = db_query("SELECT name, filename FROM {system} WHERE status = 1"); + $components = array(); + $query = "SELECT name, filename FROM {system} WHERE status = 1"; + if (count($skip)) { + $query .= " AND name NOT IN (". db_placeholders($skip, 'varchar') .")"; + } + $result = db_query($query, $skip); 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) .'/translations', '(^|\.)'. $langcode .'\.po$', array('.', '..', 'CVS'), 0, FALSE)); + $components[] = $component->name; } - return _locale_batch_build($files, $finished); + return _locale_batch_build($files, $finished, $components); } /** @@ -2474,10 +2483,12 @@ function locale_batch_by_component($comp * Array of files to import * @param $finished * Optional finished callback for the batch. + * @param $components + * Optional list of component names the batch covers. Used in the installer. * @return * A batch structure */ -function _locale_batch_build($files, $finished = NULL) { +function _locale_batch_build($files, $finished = NULL, $components = array()) { $t = get_t(); if (count($files)) { $operations = array(); @@ -2490,6 +2501,9 @@ function _locale_batch_build($files, $fi 'init_message' => $t('Starting import'), 'error_message' => $t('Error importing interface translations'), 'file' => './includes/locale.inc', + // This is not a batch API construct, but data passed along to the + // installer, so we know what did we import already. + '#components' => $components, ); if (isset($finished)) { $batch['finished'] = $finished; @@ -2538,10 +2552,18 @@ function _locale_batch_language_finished } /** - * Finished callback of installer locale import batch. + * Finished callback for the first installer locale import batch. + * Advance installer task to the configure screen. + */ +function _locale_batch_installer_initial_finished($success, $results) { + variable_set('install_task', 'configure'); +} + +/** + * Finished callback for the second installer locale import batch. * Advance installer task to the finished screen. */ -function _locale_batch_installer_finished($success, $results) { +function _locale_batch_installer_remaining_finished($success, $results) { variable_set('install_task', 'finished'); } diff -urp --strip-trailing-cr ../drupal-6.x-dev/install.php ./install.php --- ../drupal-6.x-dev/install.php 2007-11-16 00:12:38.000000000 +0100 +++ ./install.php 2007-11-17 00:07:08.000000000 +0100 @@ -27,6 +27,9 @@ function install_main() { // Ensure correct page headers are sent (e.g. caching) drupal_page_header(); + // Set up $language, so t() caller functions will still work. + drupal_init_language(); + // Check existing settings.php. $verify = install_verify_settings(); @@ -525,6 +528,19 @@ function install_select_locale($profilen return FALSE; } else { + // Allow profile to pre-select the language, skipping the selection. + $function = $profilename .'_profile_details'; + if (function_exists($function)) { + $details = $function(); + if (isset($details['language'])) { + foreach ($locales as $locale) { + if ($details['language'] == $locale->name) { + return $locale->name; + } + } + } + } + foreach ($locales as $locale) { if ($_POST['locale'] == $locale->name) { return $locale->name; @@ -599,18 +615,52 @@ function install_tasks($profile, $task) drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); $_SESSION['messages'] = $messages; - // Build a page for a final task. + // URL used to direct page requests. + $url = $base_url .'/install.php?locale='. $install_locale .'&profile='. $profile; + + // Build a page for final tasks. drupal_maintenance_theme(); if (empty($task)) { - variable_set('install_task', 'configure'); - $task = 'configure'; + variable_set('install_task', 'locale-initial-import'); + $task = 'locale-initial-import'; } // We are using a list of if constructs here to allow for // passing from one task to the other in the same request. + // Import interface translations for the enabled modules. + if ($task == 'locale-initial-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_by_language($install_locale); + if (!empty($batch)) { + // Remember components we cover in this batch set. + variable_set('locale_install_batch_components', $batch['#components']); + // Start a batch, switch to 'locale-batch' task. We need to + // set the variable here, because batch_process() redirects. + variable_set('install_task', 'locale-initial-batch'); + batch_set($batch); + batch_process($url, $url); + } + } + // Found nothing to import or not foreign language, go to next task. + $task = 'configure'; + } + + // 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 'configure'. + if ($task == 'locale-initial-batch') { + include_once 'includes/batch.inc'; + include_once 'includes/locale.inc'; + $output = _batch_page(); + } + if ($task == 'configure') { - drupal_set_title(st('Configure site')); // We break the form up so we can tell when it's been successfully // submitted. @@ -650,6 +700,7 @@ if (Drupal.jsEnabled) { // Build menu to allow clean URL check. menu_rebuild(); $output = drupal_render_form('install_configure_form', $form); + drupal_set_title(st('Configure site')); } else { $task = 'profile'; @@ -660,48 +711,43 @@ if (Drupal.jsEnabled) { // 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())) { + drupal_set_title(st('Configure site')); $function = $profile .'_profile_tasks'; if (function_exists($function)) { // 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); + $output = $function($task, $url); } // 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. + // that it is done. if ($task == 'profile') { - $task = 'locale-import'; + $task = 'profile-finished'; } } - // Import interface translations for the enabled modules, after - // any changes made by the profile through the profile forms. - if ($task == 'locale-import') { + // Profile custom tasks are done, so let the installer regain + // control and proceed with importing the remaining translations. + if ($task == 'profile-finished') { 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_by_language($install_locale); + // Collect files to import for this language. Skip components + // already covered in the initial batch set. + $batch = locale_batch_by_language($install_locale, '_locale_batch_installer_remaining_finished', variable_get('locale_install_batch_components', array())); + // Remove temporary variable. + variable_del('locale_install_batch_components'); if (!empty($batch)) { - // Start a batch, switch to 'locale-batch' task. We need to + // Start a batch, switch to 'locale-remaining-batch' task. We need to // set the variable here, because batch_process() redirects. - variable_set('install_task', 'locale-batch'); + variable_set('install_task', 'locale-remaining-batch'); batch_set($batch); - $path = $base_url .'/install.php?locale='. $install_locale .'&profile='. $profile; - batch_process($path, $path); + batch_process($url, $url); } } // 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') { + if ($task == 'locale-remaining-batch') { include_once 'includes/batch.inc'; include_once 'includes/locale.inc'; $output = _batch_page(); @@ -743,7 +789,7 @@ if (Drupal.jsEnabled) { * The list of reserved tasks to run in the installer. */ function install_reserved_tasks() { - return array('configure', 'locale-import', 'locale-batch', 'finished', 'done'); + return array('configure', 'locale-initial-import', 'locale-initial-batch', 'profile-finished', 'locale-remaining-batch', 'finished', 'done'); } /** @@ -799,11 +845,12 @@ function install_check_requirements($pro function install_task_list($active = NULL) { // Default list of tasks. $tasks = array( - 'profile-select' => st('Choose profile'), - 'locale-select' => 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'), + 'locale-initial-batch' => st('Set up translations'), + 'configure' => st('Configure site'), ); $profiles = install_find_profiles(); @@ -826,11 +873,13 @@ function install_task_list($active = NUL } } - // If necessary, add translation import to the task list. - if (count($locales) > 1 && !empty($_GET['locale']) && $_GET['locale'] != 'en') { - $tasks += array( - 'locale-batch' => st('Import translations'), - ); + if (count($locales) < 2 || empty($_GET['locale']) || $_GET['locale'] == 'en') { + // If not required, remove translation import from the task list. + unset($tasks['locale-initial-batch']); + } + else { + // If required, add remaining translations import step. + $tasks += array('locale-remaining-batch' => st('Finish translations')); } // Add finished step as the last task. diff -urp --strip-trailing-cr ../drupal-6.x-dev/profiles/default/default.profile ./profiles/default/default.profile --- ../drupal-6.x-dev/profiles/default/default.profile 2007-11-06 10:00:31.000000000 +0100 +++ ./profiles/default/default.profile 2007-11-17 00:27:43.000000000 +0100 @@ -5,7 +5,7 @@ * Return an array of the modules to be enabled when this profile is installed. * * @return - * An array of modules to be enabled. + * An array of modules to enable. */ function default_profile_modules() { return array('color', 'comment', 'help', 'menu', 'taxonomy', 'dblog'); @@ -15,7 +15,9 @@ function default_profile_modules() { * Return a description of the profile for the initial installation screen. * * @return - * An array with keys 'name' and 'description' describing this profile. + * An array with keys 'name' and 'description' describing this profile, + * and optional 'language' to override the language selection for + * language-specific profiles. */ function default_profile_details() { return array( @@ -39,38 +41,54 @@ function default_profile_task_list() { /** * Perform any final installation tasks for this profile. * - * 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. + * The installer goes through the profile-select -> locale-select + * -> requirements -> database -> locale-initial-batch -> configure + * -> locale-remaining-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. + * custom tasks to perform after 'configure', implementing a state + * machine here to walk the user through those tasks. First time, + * this function gets called with $task set to 'profile', and you + * can advance to further tasks by setting $task to your tasks' + * identifiers, used as array keys in the hook_profile_task_list() + * above. You must avoid the reserved tasks listed in + * install_reserved_tasks(). 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 'profile-finished' task, with which you + * hand control back to the installer. Each custom page you + * return needs to provide a way to continue, such as a form + * submission or a link. You should also set custom page titles, + * if the default "Configure site" title is not appropriate. * * You should define the list of custom tasks you implement by - * returning an array of them in hook_profile_task_list(). + * returning an array of them in hook_profile_task_list(), as these + * show up in the list of tasks on the installer user interface. * - * 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 - * the form technique used in install_tasks() rather than using - * drupal_get_form(). + * Remember that the user will be able to reload the pages multiple + * times, so you might want to use variable_set() and variable_get() + * to remember your data and control further processing, if $task + * is insufficient. Should a profile want to display a form here, + * it can; the form should set '#redirect' to FALSE, and rely on + * an action in the submit handler, such as variable_set(), to + * detect submission and proceed to further tasks. + * + * Important: Any temporary variables must be removed using + * variable_del() before advancing to the 'profile-finished' phase. * * @param $task * The current $task of the install system. When hook_profile_tasks() * is first called, this is 'profile'. + * @param $url + * Complete URL to be used for a link or form action on a custom page, + * if providing any, to allow the user to proceed with the installation. * * @return * An optional HTML string to display to the user. Only used if you * modify the $task, otherwise discarded. */ -function default_profile_tasks(&$task) { +function default_profile_tasks(&$task, $url) { // Insert default user-defined node types into the database. For a complete // list of available node type attributes, refer to the node type API