From 85e9f0959239d449b71b782547fb3c3cb35d0365 Mon Sep 17 00:00:00 2001
From: Tobias Stckler <tobiasstoeckler@googlemail.com>
Date: Sat, 22 Oct 2011 01:05:34 +0200
Subject: [PATCH] Consolidate .po file import to one directory.

---
 includes/install.core.inc                          |   50 +++++----
 includes/install.inc                               |   10 +-
 modules/locale/locale.admin.inc                    |    2 +-
 modules/locale/locale.bulk.inc                     |  116 ++++----------------
 modules/locale/locale.module                       |   28 +++++-
 modules/locale/locale.test                         |    5 +-
 modules/locale/tests/{translations => }/test.xx.po |    0 
 7 files changed, 88 insertions(+), 123 deletions(-)

diff --git a/includes/install.core.inc b/includes/install.core.inc
index 7405f9f..466d4c2 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -1125,21 +1125,31 @@ function install_select_profile_form($form, &$form_state, $profile_files) {
 }
 
 /**
- * Find all .po files for the current profile.
+ * Find all .po files useful for the installer.
  */
-function install_find_locales($profilename) {
-  $locales = file_scan_directory('./profiles/' . $profilename . '/translations', '/\.po$/', array('recurse' => FALSE));
-  array_unshift($locales, (object) array('name' => 'en'));
-  foreach ($locales as $key => $locale) {
-    // The locale (file name) might be drupal-7.2.cs.po instead of cs.po.
-    $locales[$key]->langcode = preg_replace('!^(.+\.)?([^\.]+)$!', '\2', $locale->name);
+function install_find_locales() {
+  $files = install_find_locale_files();
+  // English does not need a translation file.
+  array_unshift($files, (object) array('name' => 'en'));
+  foreach ($files as $key => $file) {
+    // Strip off the file name component before the language code.
+    $files[$key]->langcode = preg_replace('!^(.+\.)?([^\.]+)$!', '\2', $file->name);
     // Language codes cannot exceed 12 characters to fit into the {languages}
     // table.
-    if (strlen($locales[$key]->langcode) > 12) {
-      unset($locales[$key]);
+    if (strlen($files[$key]->langcode) > 12) {
+      unset($files[$key]);
     }
   }
-  return $locales;
+  return $files;
+}
+
+/**
+ * Find installer translation files either for a specific langcode or generally.
+ */
+function install_find_locale_files($langcode = NULL) {
+  $directory = variable_get('locale_translate_file_directory', conf_path() . '/files/translations');
+  $files = file_scan_directory($directory, '!install\.' . (!empty($langcode) ? '\.' . preg_quote($langcode, '!') : '[^\.]+') . '\.po$!', array('recurse' => FALSE));
+  return $files;
 }
 
 /**
@@ -1410,10 +1420,8 @@ function install_import_locales(&$install_state) {
   }
 
   // Collect files to import for this language.
-  $batch = locale_batch_by_language($install_locale, NULL);
+  $batch = locale_translate_batch_import_files($install_locale);
   if (!empty($batch)) {
-    // Remember components we cover in this batch set.
-    variable_set('install_locale_batch_components', $batch['#components']);
     return $batch;
   }
 }
@@ -1480,23 +1488,21 @@ function install_configure_form($form, &$form_state, &$install_state) {
 }
 
 /**
- * Installation task; import remaining languages via a batch process.
+ * Installation task; finish importing files at end of installation.
  *
  * @param $install_state
  *   An array of information about the current installation state.
  *
  * @return
  *   The batch definition, if there are language files to import.
+ *
+ * @todo
+ *   This currently does the same as the first import step. Need to revisit
+ *   once we have l10n_update functionality integrated.
  */
 function install_import_locales_remaining(&$install_state) {
-  include_once DRUPAL_ROOT . '/includes/locale.inc';
-  // Collect files to import for this language. Skip components already covered
-  // in the initial batch set.
-  $install_locale = $install_state['parameters']['locale'];
-  $batch = locale_batch_by_language($install_locale, NULL, variable_get('install_locale_batch_components', array()));
-  // Remove temporary variable.
-  variable_del('install_locale_batch_components');
-  return $batch;
+  include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
+  return locale_translate_batch_import_files($install_state['parameters']['locale']);
 }
 
 /**
diff --git a/includes/install.inc b/includes/install.inc
index 7dbd805..ebe077c 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -1103,14 +1103,14 @@ function st($string, array $args = array(), array $options = array()) {
     $locale_strings = array();
     if (isset($install_state['parameters']['profile']) && isset($install_state['parameters']['locale'])) {
       // If the given locale was selected, there should be at least one .po file
-      // with its name ending in {$install_state['parameters']['locale']}.po
+      // with its name ending in install.{$install_state['parameters']['locale']}.po
       // This might or might not be the entire filename. It is also possible
       // that multiple files end with the same extension, even if unlikely.
-      $po_files = file_scan_directory('./profiles/' . $install_state['parameters']['profile'] . '/translations', '/'. $install_state['parameters']['locale'] .'\.po$/', array('recurse' => FALSE));
-      if (count($po_files)) {
+      $locale_files = install_find_locale_files($install_state['parameters']['locale']);
+      if (count($locale_files)) {
         require_once DRUPAL_ROOT . '/includes/gettext.inc';
-        foreach ($po_files as $po_file) {
-          _locale_import_read_po('mem-store', $po_file);
+        foreach ($locale_files as $locale_file) {
+          _locale_import_read_po('mem-store', $locale_file);
         }
         $locale_strings = _locale_import_one_string('mem-report');
       }
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index e17ed7c..e1b99c3 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -385,7 +385,7 @@ function locale_languages_add_set_batch($langcode) {
   // See if we have language files to import for the newly added
   // language, collect and import them.
   include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
-  if ($batch = locale_batch_by_language($langcode, '_locale_batch_language_finished')) {
+  if ($batch = locale_translate_batch_import_files($langcode, TRUE)) {
     batch_set($batch);
   }
 }
diff --git a/modules/locale/locale.bulk.inc b/modules/locale/locale.bulk.inc
index 51f80a6..941343b 100644
--- a/modules/locale/locale.bulk.inc
+++ b/modules/locale/locale.bulk.inc
@@ -163,97 +163,41 @@ function locale_translate_export_po_form_submit($form, &$form_state) {
 }
 
 /**
- * Prepare a batch to import translations for all enabled
- * modules in a given language.
+ * Prepare a batch to run to import all translations.
  *
  * @param $langcode
- *   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.
+ *   (optional) Language code to limit files being imported.
+ * @param $finish_feedback
+ *   (optional) Whether to give feedback to the user when finished.
  *
- * @return
- *   A batch structure or FALSE if no files found.
+ * @todo
+ *   Integrate with update status to identify projects needed and integrate
+ *   l10n_update functionality to feed in translation files alike.
  */
-function locale_batch_by_language($langcode, $finished = NULL, $skip = array()) {
-  // Collect all files to import for all enabled modules and themes.
-  $files = array();
-  $components = array();
-  $query = db_select('system', 's');
-  $query->fields('s', array('name', 'filename'));
-  $query->condition('s.status', 1);
-  if (count($skip)) {
-    $query->condition('name', $skip, 'NOT IN');
-  }
-  $result = $query->execute();
-  foreach ($result as $component) {
-    // 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('recurse' => FALSE)));
-    $components[] = $component->name;
-  }
-
-  return _locale_batch_build($files, $finished, $components);
-}
-
-/**
- * Prepare a batch to run when installing modules or enabling themes.
- *
- * This batch will import translations for the newly added components
- * in all the languages already set up on the site.
- *
- * @param $components
- *   An array of component (theme and/or module) names to import
- *   translations for.
- * @param $finished
- *   Optional finished callback for the batch.
- */
-function locale_batch_by_component($components, $finished = '_locale_batch_system_finished') {
-  $files = array();
-  $languages = language_list('enabled');
-  unset($languages[1]['en']);
-  if (count($languages[1])) {
-    $language_list = join('|', array_keys($languages[1]));
-    // Collect all files to import for all $components.
-    $result = db_query("SELECT name, filename FROM {system} WHERE status = 1");
-    foreach ($result as $component) {
-      if (in_array($component->name, $components)) {
-        // Collect all files for this component in all enabled languages, named
-        // 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', '/(^|\.)(' . $language_list . ')\.po$/', array('recurse' => FALSE)));
-      }
-    }
-    return _locale_batch_build($files, $finished);
-  }
-  return FALSE;
+function locale_translate_batch_import_files($langcode = NULL, $finish_feedback = FALSE) {
+  $locale_translate_file_directory = variable_get('locale_translate_file_directory', conf_path() . '/files/translations');
+  $files = file_scan_directory($locale_translate_file_directory, '!' . (!empty($langcode) ? '\.' . preg_quote($langcode, '!') : '') . '\.po$!', array('recurse' => FALSE));
+  return locale_translate_batch_build($files, $finish_feedback);
 }
 
 /**
  * Build a locale batch from an array of files.
  *
  * @param $files
- *   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.
+ *   Array of file objects to import.
+ * @param $finish_feedback
+ *   (optional) Whether to give feedback to the user when finished.
  *
  * @return
- *   A batch structure.
+ *   A batch structure or FALSE if $files was empty.
  */
-function _locale_batch_build($files, $finished = NULL, $components = array()) {
+function locale_translate_batch_build($files, $finish_feedback = FALSE) {
   $t = get_t();
   if (count($files)) {
     $operations = array();
     foreach ($files as $file) {
-      // We call _locale_batch_import for every batch operation.
-      $operations[] = array('_locale_batch_import', array($file->uri));
+      // We call locale_translate_batch_import for every batch operation.
+      $operations[] = array('locale_translate_batch_import', array($file->uri));
     }
     $batch = array(
       'operations'    => $operations,
@@ -261,12 +205,9 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) {
       'init_message'  => $t('Starting import'),
       'error_message' => $t('Error importing interface translations'),
       'file'          => drupal_get_path('module', 'locale') . '/locale.bulk.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;
+    if ($finish_feedback) {
+      $batch['finished'] = 'locale_translate_batch_finished';
     }
     return $batch;
   }
@@ -281,7 +222,7 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) {
  * @param $results
  *   Contains a list of files imported.
  */
-function _locale_batch_import($filepath, &$context) {
+function locale_translate_batch_import($filepath, &$context) {
   // The filename is either {langcode}.po or {prefix}.{langcode}.po, so
   // we can extract the language code to use for the import from the end.
   if (preg_match('!(/|\.)([^\./]+)\.po$!', $filepath, $langcode)) {
@@ -293,20 +234,9 @@ function _locale_batch_import($filepath, &$context) {
 
 /**
  * Finished callback of system page locale import batch.
- * Inform the user of translation files imported.
- */
-function _locale_batch_system_finished($success, $results) {
-  if ($success) {
-    drupal_set_message(format_plural(count($results), 'One translation file imported for the newly installed modules.', '@count translation files imported for the newly installed modules.'));
-  }
-}
-
-/**
- * Finished callback of language addition locale import batch.
- * Inform the user of translation files imported.
  */
-function _locale_batch_language_finished($success, $results) {
+function locale_translate_batch_finished($success, $results) {
   if ($success) {
-    drupal_set_message(format_plural(count($results), 'One translation file imported for the enabled modules.', '@count translation files imported for the enabled modules.'));
+    drupal_set_message(format_plural(count($results), 'One translation file imported.', '@count translation files imported.'));
   }
 }
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 2037c35..3d2f19f 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -853,10 +853,16 @@ function locale_themes_enabled($themes) {
  * @param $components
  *   An array of component (theme and/or module) names to import
  *   translations for.
+ *
+ * @todo
+ *   This currently imports all .po files available, independent of
+ *   $components. Once we integrated with update status for project
+ *   identification, we should revisit and only import files for the
+ *   identified projects for the components.
  */
 function locale_system_update($components) {
   include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
-  if ($batch = locale_batch_by_component($components)) {
+  if ($batch = locale_translate_batch_import_files(NULL, TRUE)) {
     batch_set($batch);
   }
 }
@@ -1120,3 +1126,23 @@ function locale_form_locale_language_overview_form_alter(&$form, &$form_state) {
     }
   }
 }
+
+/**
+ * Implements hook_form_FORM_ID_alter() for system_file_system_settings().
+ *
+ * Add interface translation directory setting to directories configuration.
+ */
+function locale_form_system_file_system_settings_alter(&$form, $form_state) {
+  $form['locale_translate_file_directory'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Interface translations directory'),
+    '#default_value' => variable_get('locale_translate_file_directory', conf_path() . '/files/translations'),
+    '#maxlength' => 255,
+    '#description' => t('A local file system path where interface translation files are looked for. This directory must exist.'),
+    '#after_build' => array('system_check_directory'),
+    '#weight' => 10,
+  );
+  if ($form['file_default_scheme']) {
+    $form['file_default_scheme']['#weight'] = 20;
+  }
+}
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index b94f565..8eb6dfc 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -661,6 +661,9 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
   function setUp() {
     parent::setUp('locale', 'locale_test');
 
+    // Set the translation file directory.
+    variable_set('locale_translate_file_directory', drupal_get_path('module', 'locale_test'));
+
     $this->admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
     $this->drupalLogin($this->admin_user);
   }
@@ -774,7 +777,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
 
     // Ensure the translation file was automatically imported when language was
     // added.
-    $this->assertText(t('One translation file imported for the enabled modules.'), t('Language file automatically imported.'));
+    $this->assertText(t('One translation file imported.'), t('Language file automatically imported.'));
 
     // Ensure strings were successfully imported.
     $search = array(
diff --git a/modules/locale/tests/translations/test.xx.po b/modules/locale/tests/test.xx.po
similarity index 100%
rename from modules/locale/tests/translations/test.xx.po
rename to modules/locale/tests/test.xx.po
-- 
1.5.6.5

