Index: connectors/l10n_drupalorg/projects.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/connectors/l10n_drupalorg/Attic/projects.inc,v
retrieving revision 1.1.2.6.2.3
diff -u -p -r1.1.2.6.2.3 projects.inc
--- connectors/l10n_drupalorg/projects.inc	16 Aug 2009 15:00:51 -0000	1.1.2.6.2.3
+++ connectors/l10n_drupalorg/projects.inc	18 Sep 2009 17:43:36 -0000
@@ -140,7 +140,7 @@ function l10n_drupalorg_sync_files($rele
 
   // Extract and parse the local file and remove the tarball.
   else {
-    $return = l10n_community_parse_package($file, $release->rid);
+    $return = l10n_community_parse_package($file, $release);
     unlink($file);
   }
 
Index: connectors/l10n_localpacks/l10n_localpacks.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/connectors/l10n_localpacks/Attic/l10n_localpacks.module,v
retrieving revision 1.1.2.9.2.5
diff -u -p -r1.1.2.9.2.5 l10n_localpacks.module
--- connectors/l10n_localpacks/l10n_localpacks.module	16 Aug 2009 15:00:51 -0000	1.1.2.9.2.5
+++ connectors/l10n_localpacks/l10n_localpacks.module	18 Sep 2009 17:43:36 -0000
@@ -177,7 +177,7 @@ function l10n_localpacks_scan($automated
     if (file_exists($file_name)) {
       if (filemtime($file_name) > $release->last_parsed) {
         include_once drupal_get_path('module', 'l10n_community') .'/extractor.inc';
-        $result = l10n_community_parse_package($file_name, $release->rid);
+        $result = l10n_community_parse_package($file_name, $release);
 
         // User feedback, if not automated. Log messages are already done.
         if (isset($result['error']) && !$automated) {
Index: connectors/l10n_project/l10n_project.sync.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/connectors/l10n_project/Attic/l10n_project.sync.inc,v
retrieving revision 1.1.2.15
diff -u -p -r1.1.2.15 l10n_project.sync.inc
--- connectors/l10n_project/l10n_project.sync.inc	16 Aug 2009 15:00:51 -0000	1.1.2.15
+++ connectors/l10n_project/l10n_project.sync.inc	18 Sep 2009 17:43:36 -0000
@@ -254,7 +254,7 @@ function l10n_project_pick_and_parse($re
 
   // Extract and parse the local file and remove the tarball.
   else {
-    $return = l10n_project_parse_package($file, $release->rid);
+    $return = l10n_project_parse_package($file, $release);
     // Clear stats cache, so new data shows up.
     cache_clear_all('l10n:stats', 'cache');
   }
@@ -271,10 +271,10 @@ function l10n_project_pick_and_parse($re
  *
  * @param $package_file
  *   Path to the package file to be extracted and parsed.
- * @param $release_rid
- *   Release ID.
+ * @param $release
+ *   Release object.
  */
-function l10n_project_parse_package($package_file, $release_rid) {
+function l10n_project_parse_package($package_file, $release) {
   $error = $message = '';
 
   // Potx module is already a dependency.
@@ -310,7 +310,7 @@ function l10n_project_parse_package($pac
 
         // Get all source files and save strings with our callback for this release.
         $files = _potx_explore_dir($temp_path);
-        l10n_community_save_file($release_rid);
+        l10n_community_save_file(array($release->pid, $release->rid));
         $version = l10n_community_detect_major_version($package_file);
         foreach ($files as $name) {
           _potx_process_file($name, strlen($temp_path) + 1, 'l10n_community_save_string', 'l10n_community_save_file', $version);
@@ -326,17 +326,17 @@ function l10n_project_parse_package($pac
         $message = 'Contents of %filename have been scanned.';
 
         // Parsed this releases files.
-        db_query("UPDATE {l10n_community_release} SET last_parsed = %d WHERE rid = %d", time(), $release_rid);
+        db_query("UPDATE {l10n_community_release} SET last_parsed = %d WHERE rid = %d", time(), $release->rid);
 
         // Update error list for this release. Although the errors are related to
         // files, we are not interested in the fine details, the file names are in
         // the error messages as text. We assume no other messages are added while
         // importing, so we can safely use drupal_get_message() to grab our errors.
-        db_query("DELETE FROM {l10n_community_error} WHERE rid = %d", $release_rid);
+        db_query("DELETE FROM {l10n_community_error} WHERE rid = %d", $release->rid);
         $messages = drupal_get_messages('error');
         if (isset($messages['error']) && is_array($messages['error'])) {
           foreach ($messages['error'] as $error_message) {
-            db_query("INSERT INTO {l10n_community_error} (rid, value) VALUES (%d, '%s')", $release_rid, $error_message);
+            db_query("INSERT INTO {l10n_community_error} (rid, value) VALUES (%d, '%s')", $release->rid, $error_message);
           }
         }
       }
Index: l10n_community/ajax.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/ajax.inc,v
retrieving revision 1.1.2.18.2.4
diff -u -p -r1.1.2.18.2.4 ajax.inc
--- l10n_community/ajax.inc	16 Aug 2009 15:00:51 -0000	1.1.2.18.2.4
+++ l10n_community/ajax.inc	18 Sep 2009 17:43:36 -0000
@@ -23,7 +23,7 @@
  */
 function l10n_community_string_details($langcode = NULL, $sid = 0) {
   // List of project releases, where this string is used.
-  $result = db_query('SELECT p.pid, p.title project_title, r.rid, r.title release_title, COUNT(l.lineno) as occurance_count FROM {l10n_community_project} p INNER JOIN {l10n_community_release} r ON p.pid = r.pid INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid WHERE s.sid = %d AND p.status = 1 GROUP BY r.rid ORDER by p.pid, r.rid', $sid);
+  $result = db_query('SELECT l.pid, p.title project_title, l.rid, r.title release_title, COUNT(l.lineno) as occurance_count FROM {l10n_community_line} l INNER JOIN {l10n_community_project} p ON l.pid = p.pid INNER JOIN {l10n_community_release} r ON l.rid = r.rid WHERE l.sid = %d AND p.status = 1 GROUP BY l.rid ORDER BY l.pid, l.rid', $sid);
 
   $list = array();
   $output = array();
Index: l10n_community/export.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/export.inc,v
retrieving revision 1.1.2.15.2.14
diff -u -p -r1.1.2.15.2.14 export.inc
--- l10n_community/export.inc	16 Sep 2009 14:01:18 -0000	1.1.2.15.2.14
+++ l10n_community/export.inc	18 Sep 2009 17:43:36 -0000
@@ -388,19 +388,19 @@ function l10n_community_export($uri, $re
   $project = l10n_community_get_projects(array('uri' => $uri));
   if ($template) {
     // We are exporting a template explicitly.
-    $sql = 'SELECT s.sid, s.value, s.context, f.location, f.revision, l.lineno, l.type FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid WHERE r.pid = %d';
+    $sql = 'SELECT s.sid, s.value, s.context, f.location, f.revision, l.lineno, l.type FROM {l10n_community_file} f INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid WHERE f.pid = %d';
     $sql_args = array($project->pid);
   }
   else {
     // We only export active translations, not suggestions.
-    $sql = "SELECT s.sid, s.value, s.context, f.location, f.revision, l.lineno, l.type, t.translation, t.uid_approved, t.time_approved FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid  LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND is_active = 1 AND is_suggestion = 0 WHERE r.pid = %d";
+    $sql = "SELECT s.sid, s.value, s.context, f.location, f.revision, l.lineno, l.type, t.translation, t.uid_approved, t.time_approved FROM {l10n_community_file} f INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid  LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND is_active = 1 AND is_suggestion = 0 WHERE f.pid = %d";
     $sql_args = array($language->language, $project->pid);
   }
 
   if (isset($release)) {
     // Release restriction.
     $sql_args[] = $release;
-    $sql .= ' AND r.rid = %d';
+    $sql .= ' AND f.rid = %d';
     $releases = l10n_community_get_releases($uri);
     $release = $releases[$release];
   }
Index: l10n_community/extractor.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/extractor.inc,v
retrieving revision 1.1.2.13.2.4
diff -u -p -r1.1.2.13.2.4 extractor.inc
--- l10n_community/extractor.inc	16 Aug 2009 15:00:51 -0000	1.1.2.13.2.4
+++ l10n_community/extractor.inc	18 Sep 2009 17:43:36 -0000
@@ -14,10 +14,10 @@
  *
  * @param $package_file
  *   Path to the package file to be extracted and parsed.
- * @param $release_rid
- *   Release ID.
+ * @param $release
+ *   Release object.
  */
-function l10n_community_parse_package($package_file, $release_rid) {
+function l10n_community_parse_package($package_file, $release) {
   if (!ini_get('safe_mode')) {
     // This could take a long time.
     @set_time_limit(0);
@@ -60,7 +60,7 @@ function l10n_community_parse_package($p
     else {
       // Get all source files and save strings with our callback for this release.
       $files = _potx_explore_dir($temp_path);
-      l10n_community_save_file($release_rid);
+      l10n_community_save_file(array($release->pid, $release->rid));
       $version = l10n_community_detect_major_version($package_file);
       foreach ($files as $name) {
         _potx_process_file($name, strlen($temp_path) + 1, 'l10n_community_save_string', 'l10n_community_save_file', $version);
@@ -73,17 +73,17 @@ function l10n_community_parse_package($p
       $message = t('Contents of %filename have been scanned.', array('%filename' => $package_file));
 
       // Parsed this releases files.
-      db_query("UPDATE {l10n_community_release} SET last_parsed = %d WHERE rid = %d", time(), $release_rid);
+      db_query("UPDATE {l10n_community_release} SET last_parsed = %d WHERE rid = %d", time(), $release->rid);
 
       // Update error list for this release. Although the errors are related to
       // files, we are not interested in the fine details, the file names are in
       // the error messages as text. We assume no other messages are added while
       // importing, so we can safely use drupal_get_message() to grab our errors.
-      db_query("DELETE FROM {l10n_community_error} WHERE rid = %d", $release_rid);
+      db_query("DELETE FROM {l10n_community_error} WHERE rid = %d", $release->rid);
       $messages = drupal_get_messages('error');
       if (isset($messages['error']) && is_array($messages['error'])) {
         foreach ($messages['error'] as $error_message) {
-          db_query("INSERT INTO {l10n_community_error} (rid, value) VALUES (%d, '%s')", $release_rid, $error_message);
+          db_query("INSERT INTO {l10n_community_error} (rid, value) VALUES (%d, '%s')", $release->rid, $error_message);
         }
       }
     }
@@ -113,28 +113,29 @@ function l10n_community_parse_package($p
  * with), if $revision is not given.
  *
  * This is called:
- *  - before any file parsing with ($rid, NULL)
+ *  - before any file parsing with (array($pid, $rid), NULL)
  *  - just as a new file is found by potx with ($revision, $file)
  *  - just as a new string is found by our own callback with (NULL, $file)
  *
  * @param $revision
  *   CVS revision information about $file. If not given, the recorded
- *   fid of $file will be returned.
+ *   fid of $file will be returned in an array with ($pid, $rid, $fid).
  * @param $file
- *   File location in package. If not given, $revision is taken as a
- *   release id to use to store the file list.
+ *   File location in package. If not given, $revision is taken as an array
+ *   with project and release id to use to store the file list.
  */
 function l10n_community_save_file($revision = NULL, $file = NULL) {
+  static $pid = 0;
   static $rid = 0;
   static $files = array();
 
   if (!isset($file)) {
     // We get the release number for the files.
-    $rid = $revision;
+    list($pid, $rid) = $revision;
   }
   elseif (!isset($revision)) {
     // We return data for a specific file.
-    return $files[$file];
+    return array($pid, $rid, $files[$file]);
   }
   else {
     if ($existing_file = db_fetch_object(db_query("SELECT * FROM {l10n_community_file} WHERE rid = %d AND location = '%s'", $rid, $file))) {
@@ -146,7 +147,7 @@ function l10n_community_save_file($revis
     }
     else {
       // New file in this release.
-      db_query("INSERT INTO {l10n_community_file} (rid, location, revision) VALUES(%d, '%s', '%s')", $rid, $file, $revision);
+      db_query("INSERT INTO {l10n_community_file} (pid, rid, location, revision) VALUES(%d, '%s', '%s')", $pid, $rid, $file, $revision);
       $fid = db_result(db_query("SELECT fid FROM {l10n_community_file} WHERE rid = %d and location = '%s'", $rid, $file));
     }
     $files[$file] = $fid;
@@ -188,6 +189,9 @@ function l10n_community_save_string($val
 
   // If we have the file entry now, we can process adding the string.
   if (isset($files[$file])) {
+    // Explode files array to pid, rid and fid.
+    list($pid, $rid, $fid) = $files[$file];
+    
     // A \0 separator in the string means we deal with a string with plural variants.
     // Unlike Drupal core, we store all in the same string, as it is easier
     // to handle later, and we don't need the individual string parts.
@@ -196,9 +200,9 @@ function l10n_community_save_string($val
       db_query("INSERT INTO {l10n_community_string} (value, context) VALUES ('%s', '%s')", $value, $context);
       $sid = db_result(db_query("SELECT sid FROM {l10n_community_string} WHERE value = BINARY '%s' AND context = '%s'", $value, $context));
     }
-    if (!db_result(db_query("SELECT fid FROM {l10n_community_line} WHERE fid = %d AND sid = %d AND lineno = %d AND type = %d", $files[$file], $sid, $line, $string_type))) {
+    if (!db_result(db_query("SELECT fid FROM {l10n_community_line} WHERE fid = %d AND sid = %d AND lineno = %d AND type = %d", $fid, $sid, $line, $string_type))) {
       // Location does not exist with this string.
-      db_query("INSERT INTO {l10n_community_line} (fid, sid, lineno, type) VALUES (%d, %d, %d, %d)", $files[$file], $sid, $line, $string_type);
+      db_query("INSERT INTO {l10n_community_line} (pid, rid, fid, sid, lineno, type) VALUES (%d, %d, %d, %d, %d, %d)", $pid, $rid, $fid, $sid, $line, $string_type);
     }
   }
 }
Index: l10n_community/import.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/import.inc,v
retrieving revision 1.1.2.5.2.10
diff -u -p -r1.1.2.5.2.10 import.inc
--- l10n_community/import.inc	16 Sep 2009 14:01:18 -0000	1.1.2.5.2.10
+++ l10n_community/import.inc	18 Sep 2009 17:43:36 -0000
@@ -100,7 +100,7 @@ function l10n_community_import_form_subm
       list($inserted, $updated, $unchanged, $suggested) = _l10n_community_import_one_string();
       drupal_set_message(t('The translation was successfully imported.'));
       l10n_community_update_message($inserted, $updated, $unchanged, $suggested, 0);
-      cache_clear_all('l10n:stats:'. $form_state['values']['langcode'], 'cache', TRUE);
+      cache_clear_all('l10n:stats:'. $form_state['values']['langcode'], 'cache');
     }
   }
   else {
Index: l10n_community/l10n_community.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/l10n_community.admin.inc,v
retrieving revision 1.1.2.10
diff -u -p -r1.1.2.10 l10n_community.admin.inc
--- l10n_community/l10n_community.admin.inc	28 Aug 2009 15:56:45 -0000	1.1.2.10
+++ l10n_community/l10n_community.admin.inc	18 Sep 2009 17:43:36 -0000
@@ -349,15 +349,10 @@ function l10n_community_delete_project($
     $pid
   );
 
-  // Cascade delete all related entries in project, release, file and line.
-  db_query(
-    'DELETE p, r, f, l FROM {l10n_community_project} p
-     INNER JOIN {l10n_community_release} r ON p.pid = r.pid
-     INNER JOIN {l10n_community_file} f ON r.rid = f.rid
-     INNER JOIN {l10n_community_line} l ON f.fid = l.fid
-     WHERE p.pid = %d',
-    $pid
-  );
+  db_query('DELETE l FROM {l10n_community_line} l WHERE l.pid = %d', $pid);
+  db_query('DELETE f FROM {l10n_community_file} f WHERE f.pid = %d', $pid);
+  db_query('DELETE r FROM {l10n_community_release} r WHERE r.pid = %d', $pid);
+  db_query('DELETE p FROM {l10n_community_project} p WHERE p.pid = %d', $pid);
 
   if (!$skip_strings) {
     l10n_community_delete_orphans();
Index: l10n_community/l10n_community.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/l10n_community.install,v
retrieving revision 1.1.2.11.2.11
diff -u -p -r1.1.2.11.2.11 l10n_community.install
--- l10n_community/l10n_community.install	16 Aug 2009 15:00:51 -0000	1.1.2.11.2.11
+++ l10n_community/l10n_community.install	18 Sep 2009 17:43:37 -0000
@@ -165,6 +165,12 @@ function l10n_community_schema() {
         'not null' => TRUE,
         'disp-width' => '11'
       ),
+      'pid' => array(
+        'description' => 'Reference to the {l10n_community_project}.pid of the parent project.',
+        'type' => 'int',
+        'not null' => FALSE,
+        'disp-width' => '11'
+      ),
       'rid' => array(
         'description' => 'Reference to the {l10n_community_release}.rid of the parent release.',
         'type' => 'int',
@@ -193,6 +199,18 @@ function l10n_community_schema() {
   $schema['l10n_community_line'] = array(
     'description' => 'Information on occurances of strings on lines of specific files.',
     'fields' => array(
+      'pid' => array(
+        'description' => 'Reference to the {l10n_community_project}.pid of the parent project.',
+        'type' => 'int',
+        'not null' => FALSE,
+        'disp-width' => '11'
+      ),
+      'rid' => array(
+        'description' => 'Reference to the {l10n_community_release}.rid of the parent release.',
+        'type' => 'int',
+        'not null' => FALSE,
+        'disp-width' => '11'
+      ),
       'fid' => array(
         'description' => 'Reference to the {l10n_community_file}.fid of the parent file.',
         'type' => 'int',
@@ -221,7 +239,9 @@ function l10n_community_schema() {
     ),
     'indexes' => array(
       'fid' => array('fid'),
-      'sid' => array('sid')
+      'sid' => array('sid'),
+      'pid' => array('pid'),
+      'rid' => array('rid'),
     ),
   );
 
@@ -536,3 +556,36 @@ function l10n_community_update_6005() {
   db_add_field($ret, 'l10n_community_string', 'context', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
   return $ret;
 }
+
+/**
+ * Denormalize data in order to improve performance: Push project ID to file table.
+ */
+function l10n_community_update_6006() {
+  $ret = array();
+
+  db_add_field($ret, 'l10n_community_file', 'pid', array('type' => 'int', 'not null' => FALSE, 'disp-width' => 11));
+
+  $q = db_query("SELECT rid, pid FROM {l10n_community_release}");
+  while ($release = db_fetch_object($q)) {
+    db_query("UPDATE {l10n_community_file} SET pid = %d WHERE rid = %d", $release->pid, $release->rid);
+  }
+  return $ret;
+}
+
+/**
+ * Denormalize data in order to improve performance: Push project and release ID to line table.
+ */
+function l10n_community_update_6007() {
+  $ret = array();
+
+  db_add_field($ret, 'l10n_community_line', 'pid', array('type' => 'int', 'not null' => FALSE, 'disp-width' => 11));
+  db_add_field($ret, 'l10n_community_line', 'rid', array('type' => 'int', 'not null' => FALSE, 'disp-width' => 11));
+  db_add_index($ret, 'l10n_community_line', 'pid', array('pid'));
+  db_add_index($ret, 'l10n_community_line', 'rid', array('rid'));
+
+  $q = db_query("SELECT fid, rid, pid FROM {l10n_community_file}");
+  while ($row = db_fetch_object($q)) {
+    db_query("UPDATE {l10n_community_line} SET pid = %d, rid = %d WHERE fid = %d", $row->pid, $row->rid, $row->fid);
+  }
+  return $ret;
+}
Index: l10n_community/l10n_community.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/l10n_community.module,v
retrieving revision 1.1.2.23.2.49
diff -u -p -r1.1.2.23.2.49 l10n_community.module
--- l10n_community/l10n_community.module	17 Sep 2009 12:25:04 -0000	1.1.2.23.2.49
+++ l10n_community/l10n_community.module	18 Sep 2009 17:43:37 -0000
@@ -1490,7 +1490,40 @@ function l10n_community_get_stats($langc
 function l10n_community_cron() {
   $lastrun = variable_get('l10n_cron_stats', 1);
   if (($_SERVER['REQUEST_TIME'] - $lastrun) > 3600) {
-    cache_clear_all('l10n:stats', 'cache', TRUE);
+    l10n_community_cache_clear_all();
+    l10n_communiy_rebuild_stats();
     variable_set('l10n_cron_stats', $_SERVER['REQUEST_TIME']);
   }
 }
+
+/**
+ * Clear all l10n_community caches.
+ */
+function l10n_community_cache_clear_all() {
+  cache_clear_all('l10n:stats', 'cache', TRUE);
+  cache_clear_all('l10n:count', 'cache', TRUE);
+}
+
+/**
+ * Rebuild the most important stats for the site.
+ */
+function l10n_communiy_rebuild_stats() {
+  l10n_community_get_stats();
+  l10n_community_get_string_count('languages');
+  l10n_community_get_string_count('projects');
+  if ($project = l10n_community_get_highlighted_project()) {
+    l10n_community_get_string_count('languages', $project->pid);
+  }
+}
+
+/**
+ * Load and return the highlighted project if set and found.
+ */
+function l10n_community_get_highlighted_project() {
+  if ($highlight_project = variable_get('l10n_community_highlighted_project', '')) {
+    if ($project = db_fetch_object(db_query("SELECT * FROM {l10n_community_project} WHERE title = '%s'", $highlight_project))) {
+      return $project;
+    }
+  }
+  return NULL;
+}
Index: l10n_community/moderate.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/moderate.inc,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 moderate.inc
--- l10n_community/moderate.inc	16 Sep 2009 14:01:18 -0000	1.1.2.2
+++ l10n_community/moderate.inc	18 Sep 2009 17:43:37 -0000
@@ -162,16 +162,14 @@ function l10n_community_get_suggestions(
   $project = $filters['project'];
   if ($release || $project) {
     $join[] = "INNER JOIN {l10n_community_line} l ON ts.sid = l.sid";
-    $join[] = "INNER JOIN {l10n_community_file} f ON f.fid = l.fid";    
     // If we have a release we ignore the project
     if ($release) {
       // Release restriction.
       $where_args[] = $release;
-      $where[] = 'f.rid = %d';
+      $where[] = 'l.rid = %d';
     }  
     elseif ($project) {
-      $join[] = "INNER JOIN {l10n_community_release} r ON f.rid = r.rid";
-      $where[] = "r.pid = %d";
+      $where[] = "l.pid = %d";
       $where_args[] = $project->pid;
     }
   }
@@ -207,9 +205,9 @@ function l10n_community_get_suggestions(
 
   // Build the queries
   $sql_args = array_merge($join_args, $where_args);
-  $sql_where = implode(' ', $join) . ' WHERE ' . implode(' AND ', $where);
-  $sql = $select . ' ' . $sql_where;
-  $sql_count = $select_count . ' ' . $sql_where;
+  $sql_where = implode(' ', $join) .' WHERE '. implode(' AND ', $where);
+  $sql = $select .' '. $sql_where;
+  $sql_count = $select_count .' '. $sql_where;
 
   $strings = pager_query($sql, $filters['limit'], 0, $sql_count, $sql_args);
   $result = array();
Index: l10n_community/pages.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/pages.inc,v
retrieving revision 1.1.2.20.2.20
diff -u -p -r1.1.2.20.2.20 pages.inc
--- l10n_community/pages.inc	16 Sep 2009 14:01:18 -0000	1.1.2.20.2.20
+++ l10n_community/pages.inc	18 Sep 2009 17:43:37 -0000
@@ -44,7 +44,7 @@ function l10n_community_explore_language
         array(
           array('data' => l($language->name .' ('. $langcode .')', 'translate/languages/'. $langcode), 'class' => 'rowhead'),
         ),
-        isset($string_counts[$langcode]) ? theme('l10n_community_progress_columns', $num_source, $string_counts[$langcode][0], $string_counts[$langcode][1]) : theme('l10n_community_progress_columns', $num_source, 0, 0)
+        isset($string_counts[$langcode]) ? theme('l10n_community_progress_columns', $num_source, @$string_counts[$langcode]['translations'], @$string_counts[$langcode]['suggestions']) : theme('l10n_community_progress_columns', $num_source, 0, 0)
       );
     }
   }
@@ -73,14 +73,13 @@ function l10n_community_explore_projects
   $table = array();
   $string_counts = l10n_community_get_string_count('projects');
   foreach ($projects as $project) {
-    list($title, $uri, $sum, $translated, $suggested) = isset($string_counts[$project->pid]) ? $string_counts[$project->pid] : array($project->title, $project->uri, 0, 0, 0);
     $table[] = array_merge(
       array(
-        array('data' => l($title, 'translate/projects/'. $uri), 'class' => 'rowhead'),
+        array('data' => l($project->title, 'translate/projects/'. $project->uri), 'class' => 'rowhead'),
       ),
       // Multiply summary count by languages handled, so we get an
       // accurate picture of completeness.
-      theme('l10n_community_progress_columns', ($sum * $language_count), $translated, $suggested)
+      theme('l10n_community_progress_columns', (@$string_counts[$project->pid]['count'] * $language_count), @$string_counts[$project->pid]['translations'], @$string_counts[$project->pid]['suggestions'])
     );
   }
   $output .= theme(
@@ -286,8 +285,8 @@ function l10n_community_language_progres
         theme(
           'l10n_community_progress_columns',
           $num_source,
-          !empty($string_counts[$langcode][0]) ? $string_counts[$langcode][0] : 0,
-          !empty($string_counts[$langcode][1]) ? $string_counts[$langcode][1] : 0
+          @$string_counts[$langcode]['translations'],
+          @$string_counts[$langcode]['suggestions']
         )
       );
     }
@@ -451,56 +450,82 @@ function l10n_community_get_string_count
 
     case 'project':
       // Return a count of all strings in this project, id required.
-      return db_result(db_query('SELECT COUNT(DISTINCT s.sid) FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid WHERE r.pid = %d', $id));
+      return db_result(db_query('SELECT COUNT(DISTINCT s.sid) FROM {l10n_community_line} l INNER JOIN {l10n_community_string} s ON l.sid = s.sid WHERE l.pid = %d', $id));
 
     case 'languages':
-      // Summeries based on language codes, restricted to a specific project if $id is set.
-      $sums = array();
-      if (!isset($id)) {
-        // Simple count query if we are not filtering by project.
-        $count_sql = "SELECT COUNT(DISTINCT sid) AS translation_count, language, is_suggestion FROM {l10n_community_translation} WHERE is_active = 1 AND translation != '' GROUP BY language, is_suggestion";
+      if ($stats = cache_get('l10n:count:languages:'. $id, 'cache')) {
+        return $stats->data;
       }
       else {
-        // Rather complex join if we also need to factor the project in.
-        $count_sql = "SELECT COUNT(DISTINCT t.sid) AS translation_count, t.language, t.is_suggestion FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid WHERE r.pid = %d AND t.is_active = 1 AND t.translation != '' GROUP BY t.language, t.is_suggestion";
-      }
-      $result = db_query($count_sql, $id);
-      while ($row = db_fetch_object($result)) {
-        if (!isset($sums[$row->language])) {
-          // Set default zeroes for summaries.
-          $sums[$row->language] = array(0, 0);
+        // Summeries based on language codes, restricted to a specific project if $id is set.
+        $sums = array();
+        if (!isset($id)) {
+          // Simple count query if we are not filtering by project.
+          $count1_sql = "SELECT COUNT(sid) AS translation_count, language FROM {l10n_community_translation} WHERE is_active = 1 AND translation != '' AND is_suggestion = 0 GROUP BY language";
+          $count2_sql = "SELECT COUNT(sid) AS translation_count, language FROM {l10n_community_translation} WHERE has_suggestion = 1 GROUP BY language";
+          $count_args = array();
+        }
+        else {
+          // More complex joins if we also need to factor the project in.
+          $count1_sql = "SELECT COUNT(DISTINCT t.sid) AS translation_count, t.language FROM {l10n_community_line} l LEFT JOIN {l10n_community_translation} t ON l.sid = t.sid WHERE l.pid = %d AND t.is_active = 1 AND t.translation != '' AND t.is_suggestion = 0 GROUP BY t.language";
+          $count2_sql = "SELECT COUNT(DISTINCT t.sid) AS translation_count, t.language FROM {l10n_community_line} l LEFT JOIN {l10n_community_translation} t ON l.sid = t.sid WHERE l.pid = %d AND t.has_suggestion = 1 GROUP BY t.language";
+          $count_args = array($id);
+        }
+        $result = db_query($count1_sql, $count_args);
+        while ($row = db_fetch_object($result)) {
+          $sums[$row->language]['translations'] = $row->translation_count;
         }
-        // Fill in the 0 or 1 element based on whether we have a result
-        // for suggestions or translations.
-        $sums[$row->language][(int) $row->is_suggestion] = $row->translation_count;
+        $result = db_query($count2_sql, $count_args);
+        while ($row = db_fetch_object($result)) {
+          $sums[$row->language]['suggestions'] = $row->translation_count;
+        }
+        cache_set('l10n:count:languages:'. $id, $sums, 'cache', CACHE_PERMANENT);
+        return $sums;
       }
-      return $sums;
       break;
 
     case 'projects':
       // Get summaries by projects. Restricted to a specific language, if $id is set.
 
-      // First get the count of strings available for translation.
-      $sums = $count_args = array();
-      $result = db_query("SELECT COUNT(DISTINCT s.sid) AS string_count, p.pid, p.title, p.uri FROM {l10n_community_project} p INNER JOIN {l10n_community_release} r ON p.pid = r.pid INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid GROUP BY p.pid;");
-      while ($row = db_fetch_object($result)) {
-        // Initialize remaining fields to zeroes too.
-        $sums[$row->pid] = array($row->title, $row->uri, $row->string_count, 0, 0);
-      }
-      // Get the count of distinct strings translated and suggestions per project.
-      $count_sql = "SELECT COUNT(DISTINCT t.sid) AS translation_count, r.pid, t.is_suggestion FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid WHERE t.is_active = 1 AND t.translation != '' ";
-      if (isset($id)) {
-        // Limit to language if desired.
-        $count_sql .= "AND t.language = '%s' ";
-        $count_args[] = $id;
+      // General community statistics.
+      if ($stats = cache_get('l10n:count:projects:'. $id, 'cache')) {
+        return $stats->data;
       }
-      $count_sql .= 'GROUP BY r.pid, t.is_suggestion ';
-      $result = db_query($count_sql, $count_args);
-      while ($row = db_fetch_object($result)) {
-        // Fill up the zero spots we added above with real data.
-        $sums[$row->pid][((int) $row->is_suggestion) + 3] = $row->translation_count;
+      else {
+        // First get the count of strings available for translation.
+        $sums = $count_args = array();
+        $result = db_query("SELECT COUNT(DISTINCT s.sid) AS string_count, l.pid FROM {l10n_community_line} l INNER JOIN {l10n_community_string} s ON l.sid = s.sid GROUP BY l.pid");
+        while ($row = db_fetch_object($result)) {
+          $sums[$row->pid] = array('count' => $row->string_count);
+        }
+        // Get the count of distinct strings translated per project.
+        $count_sql = "SELECT COUNT(DISTINCT t.tid) AS translation_count, l.pid FROM {l10n_community_line} l LEFT JOIN {l10n_community_translation} t ON l.sid = t.sid WHERE t.is_active = 1 AND t.translation != '' AND t.is_suggestion = 0 ";
+        if (isset($id)) {
+          // Limit to language if desired.
+          $count_sql .= "AND t.language = '%s' ";
+          $count_args[] = $id;
+        }
+        $count_sql .= 'GROUP BY l.pid';
+        $result = db_query($count_sql, $count_args);
+        while ($row = db_fetch_object($result)) {
+          $sums[$row->pid]['translations'] = $row->translation_count;
+        }
+        // Get the count of distinct strings having suggestions per project.
+        $count_sql = "SELECT COUNT(DISTINCT t.sid) AS translation_count, l.pid FROM {l10n_community_line} l LEFT JOIN {l10n_community_translation} t ON l.sid = t.sid WHERE t.has_suggestion = 1 ";
+        if (isset($id)) {
+          // Limit to language if desired.
+          $count_sql .= "AND t.language = '%s' ";
+          $count_args[] = $id;
+        }
+        $count_sql .= 'GROUP BY l.pid';
+        $result = db_query($count_sql, $count_args);
+        while ($row = db_fetch_object($result)) {
+          $sums[$row->pid]['translations'] = $row->translation_count;
+        }
+        cache_set('l10n:count:projects:'. $id, $sums, 'cache', CACHE_PERMANENT);
+        return $sums;
       }
-      return $sums;
+      break;
 
     case 'top-people':
       // Get summaries of people having most active translations per language.
Index: l10n_community/translate.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/translate.inc,v
retrieving revision 1.1.2.7.2.18
diff -u -p -r1.1.2.7.2.18 translate.inc
--- l10n_community/translate.inc	16 Sep 2009 14:23:33 -0000	1.1.2.7.2.18
+++ l10n_community/translate.inc	18 Sep 2009 17:43:37 -0000
@@ -623,47 +623,49 @@ function theme_l10n_community_in_context
  *   An array of string records from database.
  */
 function l10n_community_get_strings($langcode, $filters, $pager = NULL) {
-
+  $join = $join_args = $where = $where_args = array();
   $sql = $sql_count = '';
-  $sql_args = array();
 
-  if (!isset($filters['project'])) {
-    // No project based filtering.
-    $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE";
-    $sql_count = "SELECT COUNT(DISTINCT(s.sid)) FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE";
-    $sql_args = array($langcode);
-  }
-  else {
-    // Project based filtering and language based filtering built in.
-    $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE r.pid = %d";
-    $sql_count = "SELECT COUNT(DISTINCT(s.sid)) FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE r.pid = %d";
-    $sql_args = array($langcode, $filters['project']->pid);
-  }
+  $select = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active FROM {l10n_community_string} s";
+  $select_count = "SELECT COUNT(DISTINCT(s.sid)) FROM {l10n_community_string} s";
+  $join[] = "LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0";
+  $join_args[] = $langcode;
 
   // Add submitted by condition
   if (!empty($filters['author'])) {
-    $search_sql = " AND t.uid_entered = %d";
-    $sql .= $search_sql;
-    $sql_count .= $search_sql;
-    $sql_args[] = $filters['author']->uid;
+    $where[] = "t.uid_entered = %d";
+    $where_args[] = $filters['author']->uid;
   }
 
-  if (!empty($filters['search'])) {
-    // Search in the source or target strings.
-    $sql_args[] = $filters['search'];
-    $sql_args[] = $filters['search'];
-    $search_sql = " AND (s.value LIKE '%%%s%%' OR t.translation LIKE '%%%s%%')";
-    $sql .= $search_sql;
-    $sql_count .= $search_sql;
+  // Release restriction.
+  $release = empty($filters['release']) || $filters['release'] === 'all' ? NULL : $filters['release'];
+  $project = $filters['project'];
+  if ($release || $project) {
+    $join[] = "INNER JOIN {l10n_community_line} l ON s.sid = l.sid";
+    // If we have a release we ignore the project
+    if ($release) {
+      // Release restriction.
+      $where_args[] = $release;
+      $where[] = 'l.rid = %d';
+    }  
+    elseif ($project) {
+      $where[] = "l.pid = %d";
+      $where_args[] = $project->pid;
+    }
   }
 
-  if (isset($filters['release']) && $filters['release'] != 'all') {
-    // Release restriction.
-    $sql_args[] = $filters['release'];
-    $sql_args[] = $filters['release'];
-    $release_sql = ' AND r.rid = %d';
-    $sql .= $release_sql;
-    $sql_count .= $release_sql;
+  // Context based filtering.
+  if (isset($filters['context']) && $filters['context'] != 'all') {
+    // We use 'none' for no context, so '' can be the defaut (for all contexts).
+    $where_args[] = $filters['context'] == 'none' ? '' : $filters['context'];
+    $where[] = "s.context = '%s'";
+  }
+
+  if (!empty($filters['search'])) {
+    // Search in the source or target strings.
+    $where_args[] = $filters['search'];
+    $where_args[] = $filters['search'];
+    $where[] = "(s.value LIKE '%%%s%%' OR t.translation LIKE '%%%s%%')";
   }
 
   // Restriction based on string status by translation / suggestions.
@@ -674,38 +676,27 @@ function l10n_community_get_strings($lan
     // records in the result set in this case). The translation field is empty or
     // NULL in this case, as we are not allowing NULL there and only saving an empty
     // translation if there are suggestions but no translation yet.
-    $status_sql .= " AND (t.translation is NULL OR t.translation = '')";
+    $where[] = "(t.translation is NULL OR t.translation = '')";
   } 
   elseif ($filters['status'] & L10N_STATUS_TRANSLATED) {
-    $status_sql .= " AND t.translation != ''";
+    $where[] = "t.translation != ''";
   }
   if ($filters['status'] & L10N_STATUS_HAS_SUGGESTION) {
     // Note that we are not searching in the suggestions themselfs, only
     // the source and active translation values. The user interface underlines
     // that we are  looking for strings which have suggestions, not the
     // suggestions themselfs.
-    $status_sql .= " AND t.has_suggestion = 1";
+    $where[] = "t.has_suggestion = 1";
   }
   elseif ($filters['status'] & L10N_STATUS_NO_SUGGESTION) {
-    $status_sql .= " AND ((t.has_suggestion IS NULL) OR (t.has_suggestion = 0))";
-  }
-  $sql .= $status_sql;
-  $sql_count .= $status_sql;
-
-  // Context based filtering.
-  if (isset($filters['context']) && $filters['context'] != 'all') {
-    // We use 'none' for no context, so '' can be the defaut (for all contexts).
-    $sql_args[] = $filters['context'] == 'none' ? '' : $filters['context'];
-    $context_sql = " AND s.context = '%s'";
-    $sql .= $context_sql;
-    $sql_count .= $context_sql;
+    $where[] = "((t.has_suggestion IS NULL) OR (t.has_suggestion = 0))";
   }
 
-  // Morph "WHERE AND" to "WHERE" and remove closing "WHERE". The first appears
-  // if there was no project filtering but further filtering was made. The
-  // second appears if only language filtering was used.
-  $sql = str_replace('WHERE AND', 'WHERE', preg_replace('!(WHERE$)!', '', $sql));
-  $sql_count = str_replace('WHERE AND', 'WHERE', preg_replace('!(WHERE$)!', '', $sql_count));
+  // Build the queries
+  $sql_args = array_merge($join_args, $where_args);
+  $sql_where = implode(' ', $join) . (count($where) ? (' WHERE '. implode(' AND ', $where)) : '');
+  $sql = $select .' '. $sql_where;
+  $sql_count = $select_count .' '. $sql_where;
 
   // We either need a pager or a full result.
   if (isset($pager)) {
Index: l10n_community/welcome.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/welcome.inc,v
retrieving revision 1.1.2.7.2.9
diff -u -p -r1.1.2.7.2.9 welcome.inc
--- l10n_community/welcome.inc	16 Sep 2009 14:01:18 -0000	1.1.2.7.2.9
+++ l10n_community/welcome.inc	18 Sep 2009 17:43:37 -0000
@@ -83,7 +83,7 @@ function l10n_community_welcome_page() {
   );
   $output .= str_replace('class="admin-panel"', 'class="admin-panel admin-panel-contribute"', theme('admin_block', $block));
 
-  if (($highlight_project = variable_get('l10n_community_highlighted_project', '')) && ($project = db_fetch_object(db_query("SELECT * FROM {l10n_community_project} WHERE title = '%s'", array($highlight_project))))) {
+  if ($project = l10n_community_get_highlighted_project()) {
     // Display progress status of the highlighted project.
     include_once drupal_get_path('module', 'l10n_community') .'/pages.inc';
     $output .= l10n_community_language_progress_for_project($project, l10n_community_get_languages(), t('Translation status for %project', array('%project' => $project->title)), t('Highlighted project'));
Index: l10n_groups/l10n_groups.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_groups/Attic/l10n_groups.module,v
retrieving revision 1.1.2.4.2.6
diff -u -p -r1.1.2.4.2.6 l10n_groups.module
--- l10n_groups/l10n_groups.module	12 Sep 2009 08:28:13 -0000	1.1.2.4.2.6
+++ l10n_groups/l10n_groups.module	18 Sep 2009 17:43:37 -0000
@@ -91,6 +91,7 @@ function l10n_groups_node_info() {
  */
 function l10n_groups_insert($node) {
   db_query("INSERT INTO {l10n_groups_group} (nid, language, model) VALUES (%d, '%s', %d)", $node->nid, $node->l10n_group_language, $node->l10n_group_model);
+  l10n_community_cache_clear_all();
 }
 
 /**
@@ -98,6 +99,7 @@ function l10n_groups_insert($node) {
  */
 function l10n_groups_delete(&$node) {
   db_query('DELETE FROM {l10n_groups_group} WHERE nid = %d', $node->nid);
+  l10n_community_cache_clear_all();
 }
 
 /**
