Index: locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.199
diff -u -p -r1.199 locale.inc
--- locale.inc	6 Jan 2009 13:20:17 -0000	1.199
+++ locale.inc	16 Jan 2009 17:03:56 -0000
@@ -2517,6 +2517,7 @@ function locale_batch_by_language($langc
   // Collect all files to import for all enabled modules and themes.
   $files = array();
   $components = array();
+  $languages = _locale_get_language_with_fallback($langcode);
   $query = db_select('system', 's');
   $query->fields('s', array('name', 'filename'));
   $query->condition('s.status', 1);
@@ -2525,11 +2526,22 @@ function locale_batch_by_language($langc
   }
   $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$/', '/(\.\.?|CVS)$/', 0, FALSE));
+    // Iterate through a language and its potential two-digit fallback.
+    // We need to do this in order to ensure that the language takes
+    // precedence over its fallback.
+    foreach ($languages as $language) {
+      // 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.
+      $new_files = file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)' . $language . '\.po$/', '/(\.\.?|CVS)$/', 0, FALSE);
+      // Whether for the original or the fallback language, the imports
+      // need to be assigned to the original language.
+      foreach (array_keys($new_files) as $key) {
+        $new_files[$key]->langcode = $langcode;
+      }
+      $files = array_merge($files, $new_files);
+    }
     $components[] = $component->name;
   }
 
@@ -2552,16 +2564,29 @@ function locale_batch_by_component($comp
   $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");
-    while ($component = db_fetch_object($result)) {
-      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$/', '/(\.\.?|CVS)$/', 0, FALSE));
+    foreach (array_keys($languages[1]) as $langcode) {
+      $languages = _locale_get_language_with_fallback($langcode);
+      // Collect all files to import for all $components.
+      $result = db_query("SELECT name, filename FROM {system} WHERE status = 1");
+      while ($component = db_fetch_object($result)) {
+        if (in_array($component->name, $components)) {
+          // Iterate through a language and its potential two-digit fallback.
+          // We need to do this in order to ensure that the language takes
+          // precedence over its fallback.
+          foreach ($languages as $language) {
+            // 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.
+            $new_files = file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)' . $language . '\.po$/', '/(\.\.?|CVS)$/', 0, FALSE);
+            // Whether for the original or the fallback language, the imports
+            // need to be assigned to the original language.
+            foreach (array_keys($new_files) as $key) {
+              $new_files[$key]->langcode = $langcode;
+            }
+            $files = array_merge($files, $new_files);
+          }
+        }
       }
     }
     return _locale_batch_build($files, $finished);
@@ -2587,20 +2612,21 @@ function _locale_batch_build($files, $fi
     $operations = array();
     foreach ($files as $file) {
       // We call _locale_batch_import for every batch operation.
-      $operations[] = array('_locale_batch_import', array($file->filename));    }
-      $batch = array(
-        'operations'    => $operations,
-        'title'         => $t('Importing interface translations'),
-        '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;
-      }
+      $operations[] = array('_locale_batch_import', array($file->filename, $file->langcode));
+    }
+    $batch = array(
+      'operations'    => $operations,
+      'title'         => $t('Importing interface translations'),
+      '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;
+    }
     return $batch;
   }
   return FALSE;
@@ -2611,15 +2637,18 @@ function _locale_batch_build($files, $fi
  *
  * @param $filepath
  *   Path to a file to import.
- * @param $results
+ * @param $langcode_override
+ *   A language code to be set to the imported strings. Enables the use
+ *   of language import fallbacks.
+ * @param $context
  *   Contains a list of files imported.
  */
-function _locale_batch_import($filepath, &$context) {
+function _locale_batch_import($filepath, $langcode_override, &$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)) {
     $file = (object) array('filename' => basename($filepath), 'filepath' => $filepath);
-    _locale_import_read_po('db-store', $file, LOCALE_IMPORT_KEEP, $langcode[2]);
+    _locale_import_read_po('db-store', $file, LOCALE_IMPORT_KEEP, $langcode_override ? $langcode_override : $langcode[2]);
     $context['results'][] = $filepath;
   }
 }
@@ -2645,5 +2674,16 @@ function _locale_batch_language_finished
 }
 
 /**
+ * Return an array of a language and its two-digit fallback, if any.
+ */
+function _locale_get_language_with_fallback($langcode) {
+  $langcodes = array($langcode);
+  if (strlen($langcode) > 2) {
+    $langcodes[] = substr($langcode, 0, 2);
+  }
+  return $langcodes;
+}
+
+/**
  * @} End of "locale-autoimport"
  */
