diff --git a/l10n_update.admin.inc b/l10n_update.admin.inc
index bebee3e..69a08f0 100644
--- a/l10n_update.admin.inc
+++ b/l10n_update.admin.inc
@@ -136,33 +136,36 @@ function l10n_update_admin_import_form_submit($form, $form_state) {
   $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
   $projects = l10n_update_get_projects();
 
-  if ($op == t('Update translations')) {
-    $languages = array_filter($form_state['values']['languages']);
-    $updates = $form_state['values']['updates'];
-    $mode = $form_state['values']['mode'];
-    if ($projects && $updates) {
-      module_load_include('batch.inc', 'l10n_update');
-      // Filter out updates in other languages. If no languages, all of them will be updated
-      $updates = _l10n_update_prepare_updates($updates, NULL, $languages);
-      $batch = l10n_update_batch_multiple($updates, $mode);
-      batch_set($batch);
-    }
-    else {
-      drupal_set_message(t('Cannot find any translation updates.'), 'error');
-    }
-  }
-  elseif ($op == t('Refresh information')) {
-    // Get current version of projects.
-    l10n_update_build_projects();
-
-    // Get available translation updates and update file history.
-    if ($available = l10n_update_available_releases(TRUE)) {
-      l10n_update_flag_history($available);
-      drupal_set_message(t('Fetched information about available updates from the server'));
-    }
-    else {
-      drupal_set_message(t('Failed to fetch information about available updates from the server.'), 'error');
-    }
+  switch ($op) {
+    case t('Update translations'):
+      l10n_update_available_releases(TRUE);
+      $languages = array_filter($form_state['values']['languages']);
+      $updates = $form_state['values']['updates'];
+      $mode = $form_state['values']['mode'];
+      if ($projects && $updates) {
+        module_load_include('batch.inc', 'l10n_update');
+        // Filter out updates in other languages. If no languages, all of them will be updated
+        $updates = _l10n_update_prepare_updates($updates, NULL, $languages);
+        $batch = l10n_update_batch_multiple($updates, $mode);
+        batch_set($batch);
+      }
+      else {
+        drupal_set_message(t('Cannot find any translation updates.'), 'error');
+      }
+      break;
+    case t('Refresh information'):
+      // Get current version of projects.
+      l10n_update_build_projects();
+  
+      // Get available translation updates and update file history.
+      if ($available = l10n_update_available_releases(TRUE)) {
+        l10n_update_flag_history($available);
+        drupal_set_message(t('Fetched information about available updates from the server'));
+      }
+      else {
+        drupal_set_message(t('Failed to fetch information about available updates from the server.'), 'error');
+      }
+      break;
   }
 }
 
diff --git a/l10n_update.batch.inc b/l10n_update.batch.inc
index cc2406e..4129768 100644
--- a/l10n_update.batch.inc
+++ b/l10n_update.batch.inc
@@ -6,6 +6,7 @@
  */
 
 // module_load_include will not work in batch.
+// @todo Can this be done differently ?
 include_once 'l10n_update.check.inc';
 
 /**
@@ -115,6 +116,7 @@ function _l10n_update_create_batch($operations = array()) {
 function _l10n_update_batch_download($id, $file, &$context) {
   $t = get_t();
   if (l10n_update_source_download($file)) {
+    // @todo Update cache_l10n_update with file data? See l10n_update_batch_status_fetch().
     $context['message'] = $t('Importing: %name.', array('%name' => $file->filename));
     $context['results'][$id] = array('file' => $file);
   }
@@ -266,3 +268,69 @@ function _l10n_update_batch_finished($success, $results) {
     drupal_set_message($t('Error importing translations.'), 'error');
   }
 }
+
+/**
+ * @todo
+ */
+function l10n_update_batch_status($sources) {
+  $status = array();
+
+  $batch = array(
+    'finished' => 'l10n_update_batch_status_finished',
+    'title' => t('Checking available translation update data'),
+    'error_message' => t('Error checking available translation update data.'),
+    'file' => drupal_get_path('module', 'l10n_update') . '/l10n_update.batch.inc',
+  );
+  foreach ($sources as $source) {
+    $batch['operations'][] = array('l10n_update_batch_status_fetch', array($source));
+  }
+
+  batch_set($batch);
+}
+
+/**
+ * @todo
+ */
+function l10n_update_batch_status_fetch($source, &$context) {
+  $t = get_t();
+  $cid = 'available_translations_remote:' . $source->url;
+
+  // Check the translation file at the remote server and store the result in
+  // cache if successfull.
+  $result = l10n_update_http_check($source->url);
+  if ($result && !empty($result->updated)) {
+    $context['message'] = $t('Checking available translation update data ...');
+    $source->type = 'download';
+    // There may have been redirects so we store the resulting url.
+    $source->fileurl = isset($result->redirect_url) ? $result->redirect_url : $source->url;
+    unset($source->url);
+    $source->timestamp = $result->updated;
+
+    // Store the source data in the cache.
+    // @todo Is $source->url the right key to use? Alternative $source->name + $source->language
+    $frequency = variable_get('l10n_update_check_frequency', 0);
+    $expire = $frequency ? REQUEST_TIME + (60 * 60 * 24 * $frequency) : REQUEST_TIME + L10N_UPDATE_CACHE_MIN_TTL;
+    cache_set($cid, $source, 'cache_l10n_update', $expire);
+
+    $context['results'] ++;
+  }
+
+  // If no file was found on the server, the project is a custom module or
+  // no translation has yet been released by the translation server.
+  // @todo Should we cache failures too? If not they will be checked on every pageload of the l10n_update status page.
+}
+
+/**
+ * @todo
+ */
+function l10n_update_batch_status_finished($success, $results) {
+  $t = get_t();
+  if($success) {
+    if ($results) {
+      drupal_set_message(format_plural($results['updated'], 'Checked available translation update data for one project.', 'Checked available translation update data for @count projects.'));
+    }
+  }
+  else {
+    drupal_set_message($t('An error occurred trying to get available translation update data.'), 'error');
+  }
+}
diff --git a/l10n_update.check.inc b/l10n_update.check.inc
index 066ae1f..6344f37 100644
--- a/l10n_update.check.inc
+++ b/l10n_update.check.inc
@@ -28,16 +28,16 @@ module_load_include('inc', 'l10n_update');
  *   Available releases indexed by project and language.
  */
 function l10n_update_available_releases($refresh = FALSE) {
+// @todo Below 1 line is for testing only. To be removed !!
+//$refresh = TRUE;
   $frequency = variable_get('l10n_update_check_frequency', 0) * 24 * 3600;
   if (!$refresh && ($cache = cache_get('l10n_update_available_releases', 'cache_l10n_update')) && (!$frequency || $cache->created > REQUEST_TIME - $frequency)) {
     return $cache->data;
   }
   else {
     $projects = l10n_update_get_projects(TRUE);
-    $languages = l10n_update_language_list();
-    $local = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL;
-    $remote = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE;
-    $available = l10n_update_check_projects($projects, array_keys($languages), $local, $remote);
+    $languages = array_keys(l10n_update_language_list());
+    $available = l10n_update_check_projects($projects, $languages);
     cache_set('l10n_update_available_releases', $available, 'cache_l10n_update', $frequency ? REQUEST_TIME + $frequency : CACHE_PERMANENT);
     return $available;
   }
@@ -50,26 +50,29 @@ function l10n_update_available_releases($refresh = FALSE) {
  *   Projects to check (objects).
  * @param $languages
  *   Array of language codes to check, none to check all.
- * @param $check_local
- *   Check local translation file.
- * @param $check_remote
- *   Check remote translation file.
  *
  * @return array
  *   Available sources indexed by project, language.
  */
-function l10n_update_check_projects($projects, $languages = NULL, $check_local = TRUE, $check_remote = TRUE) {
-  $languages = $languages ? $languages : array_keys(l10n_update_language_list());
-  $result = array();
-  foreach ($projects as $name => $project) {
-    foreach ($languages as $lang) {
-      $source = l10n_update_source_build($project, $lang);
-      if ($update = l10n_update_source_check($source, $check_local, $check_remote)) {
-        $result[$name][$lang] = $update;
-      }
-    }
+function l10n_update_check_projects($projects, $languages = NULL) {
+  $check_local = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL;
+  $check_remote = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE;
+
+  if ($check_local) {
+    $result_local = l10n_update_check_projects_local($projects, $languages);
+  }
+  if ($check_remote) {
+    $result_remote = l10n_update_check_projects_remote($projects, $languages);
+  }
+  if ($check_local && $check_remote) {
+    return l10n_update_compare_projects($result_local, $result_remote);
+  }
+  if ($check_local) {
+    return $result_local;
+  }
+  else {
+    return $result_remote;
   }
-  return $result;
 }
 
 /**
@@ -101,6 +104,14 @@ function l10n_update_build_updates($history, $available) {
 }
 
 /**
+ * @todo Remove this function when l10n_update_check_translations() is rebuild
+ */
+function l10n_update_source_check($source, $local, $remote) {
+  //dpm(debug_backtrace());
+}
+
+
+/**
  * Check updates for active projects and languages.
  *
  * @param $count
@@ -131,6 +142,7 @@ function l10n_update_check_translations($count, $before, $limit = 1) {
   $q->orderBy('last_checked');
   $result = $q->execute();
 
+  //@todo: Rebuild for batch processing instead of using l10n_update_source_check().
   if ($result) {
     $local = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_LOCAL;
     $remote = variable_get('l10n_update_check_mode', L10N_UPDATE_CHECK_ALL) & L10N_UPDATE_CHECK_REMOTE;
@@ -204,35 +216,73 @@ function l10n_update_source_build($project, $langcode, $filename = L10N_UPDATE_D
 }
 
 /**
- * Check local and remote sources for the file.
- *
- * @param $source
- *   Translation source object.
- *   @see l10n_update_source_build()
- * @param $check_local
- *   File object of local translation file.
- * @param $check_remote
- *   File object of remote translation file.
- * @return object
- *   File object of most recent translation; local or remote.
+ * @todo
  */
-function l10n_update_source_check($source, $check_local = TRUE, $check_remote = TRUE) {
-  $local = $remote = NULL;
-  if ($check_local) {
-    $check = clone $source;
-    if (l10n_update_source_check_file($check)) {
-      $local = $check;
+function l10n_update_check_projects_local($projects, $languages = NULL) {
+  $languages = $languages ? $languages : array_keys(l10n_update_language_list());
+  $result = array();
+
+  foreach ($projects as $name => $project) {
+    foreach ($languages as $lang) {
+      $project_clone = clone $project;
+      $source = l10n_update_source_build($project_clone, $lang);
+      if (l10n_update_source_check_file($source)) {
+        $result[$name][$lang] = $source;
+      }
     }
   }
-  if ($check_remote) {
-    $check = clone $source;
-    if (l10n_update_source_check_download($check)) {
-      $remote = $check;
+  return $result;
+}
+
+/**
+ * @todo
+ */
+function l10n_update_check_projects_remote($projects, $languages = NULL) {
+  $languages = $languages ? $languages : array_keys(l10n_update_language_list());
+  $sources = array();
+
+  foreach ($projects as $name => $project) {
+    foreach ($languages as $lang) {
+      $project_clone = clone $project;
+      $source = l10n_update_source_build($project_clone, $lang);
+      $source->url = l10n_update_build_string($source, $source->l10n_path);
+      $sources[] = $source;
+    }
+  }
+
+  return l10n_update_get_remote_status($sources);
+}
+
+/**
+ * @todo
+ */
+function l10n_update_get_remote_status($sources) {
+  $status = array();
+
+  // If the status is in cache and is not expired,
+  // don't bother checking at the server.
+  $batch_sources = $sources;
+  foreach($batch_sources as $name => $source) {
+    $cid = 'available_translations_remote:' . $source->url;
+    $cache = cache_get($cid, 'cache_l10n_update');
+    if ($cache && $cache->expire > REQUEST_TIME) {
+      unset($batch_sources[$name]);
+    }
+  }
+
+  // Build and execute the batch process.
+  module_load_include('batch.inc', 'l10n_update');
+  l10n_update_batch_status($batch_sources);
+
+  // Get the result from cache and return the data.
+  foreach ($sources as $source) {
+    $cid = 'available_translations_remote:' . $source->url;
+    if  ($cache = cache_get($cid, 'cache_l10n_update')) {
+      $status[$cache->data->project][$cache->data->language] = $cache->data;
     }
   }
 
-  // Get remote if newer than local only, they both can be empty
-  return _l10n_update_source_compare($local, $remote) < 0 ? $remote : $local;
+  return $status;
 }
 
 /**
@@ -250,6 +300,7 @@ function l10n_update_source_check($source, $check_local = TRUE, $check_remote =
  *   data, redirect status and updated timestamp.
  *   NULL if failure.
  */
+/*
 function l10n_update_source_check_download($source) {
   $url = l10n_update_build_string($source, $source->l10n_path);
   $result = l10n_update_http_check($url);
@@ -261,6 +312,7 @@ function l10n_update_source_check_download($source) {
     return $result;
   }
 }
+*/
 
 /**
  * Check whether we've got the file in the filesystem under 'translations'.
@@ -398,6 +450,23 @@ function l10n_update_source_history($file) {
 }
 
 /**
+ * @todo
+ */
+function l10n_update_compare_projects($local_projects, $remote_projects) {
+  $projects = array_merge(array_keys($local_projects), array_keys($remote_projects));
+  $languages = array_keys(l10n_update_language_list());
+  $result = array();
+  foreach ($projects as $name) {
+    foreach ($languages as $lang) {
+      $local = isset($local_projects[$name][$lang]) ? $local_projects[$name][$lang] : NULL;
+      $remote = isset($remote_projects[$name][$lang]) ? $remote_projects[$name][$lang] : NULL;
+      $result[$name][$lang] = _l10n_update_source_compare($local, $remote) < 0 ? $remote : $local;
+    }
+  }
+  return $result;
+}
+
+/**
  * Compare two update sources, looking for the newer one (bigger timestamp).
  *
  * This function can be used as a callback to compare two source objects.
diff --git a/l10n_update.inc b/l10n_update.inc
index 9ab8908..9e791f5 100644
--- a/l10n_update.inc
+++ b/l10n_update.inc
@@ -190,6 +190,7 @@ function _l10n_update_build_project($name, $version = NULL, $server = L10N_UPDAT
  */
 function l10n_update_file_history($file) {
   // Update or write new record
+  // @todo Replace with db_merge();
   if (db_query("SELECT project FROM {l10n_update_file} WHERE project = :project AND language = :language", array(':project' => $file->project, ':language' => $file->language))->fetchField()) {
     $update = array('project', 'language');
   }
diff --git a/l10n_update.module b/l10n_update.module
index 0698a68..11c59c4 100644
--- a/l10n_update.module
+++ b/l10n_update.module
@@ -38,6 +38,11 @@ define('L10N_UPDATE_CRON_PROJECTS', 10);
  */
 define('L10N_UPDATE_CRON_UPDATES', 2);
 
+/**
+ * The minimum cache lifetime of translation status in seconds.
+ * Within this timeframe no new attempts will be made to check for available updates.
+ */
+define('L10N_UPDATE_CACHE_MIN_TTL', 3600);
 
 /**
  * Implements hook_help().
