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.11
diff -u -p -r1.1.2.5.2.11 import.inc
--- l10n_community/import.inc	18 Sep 2009 18:03:18 -0000	1.1.2.5.2.11
+++ l10n_community/import.inc	30 Sep 2009 12:14:02 -0000
@@ -97,9 +97,9 @@ function l10n_community_import_form_subm
     // Do the actual parsing on the local file.
     if (l10n_community_import($file, $form_state['values']['langcode'], $form_state['values']['is_suggestion'], $uid)) {
       // Get status report on what was done in the process.
-      list($inserted, $updated, $unchanged, $suggested) = _l10n_community_import_one_string();
+      list($inserted, $updated, $unchanged, $suggested, $duplicates) = _l10n_community_import_one_string();
       drupal_set_message(t('The translation was successfully imported.'));
-      l10n_community_update_message($inserted, $updated, $unchanged, $suggested, 0);
+      l10n_community_update_message($inserted, $updated, $unchanged, $suggested, $duplicates);
       cache_clear_all('l10n:stats:'. $form_state['values']['langcode'], 'cache');
     }
   }
@@ -305,12 +305,17 @@ function _l10n_community_import_one_stri
   static $updated = 0;
   static $unchanged = 0;
   static $suggested = 0;
+  static $duplicates = 0;
 
   if ($value == NULL) {
     // Result stats queried.
-    return array($inserted, $updated, $unchanged, $suggested);
+    return array($inserted, $updated, $unchanged, $suggested, $duplicates);
   }
-  elseif (!empty($value['msgid']) && !empty($value['msgstr'])) {
+  
+  // Trim translation (we will apply source string based whitespace later).
+  $value['msgstr'] = trim($value['msgstr']);
+  
+  if (!empty($value['msgid']) && !empty($value['msgstr'])) {
     // We only save non-empty translations/suggestions.
 
     if (empty($uid)) {
@@ -334,6 +339,9 @@ function _l10n_community_import_one_stri
 
       // Merge plural versions into one for saving values.
       $value['msgstr'] = is_array($value['msgstr']) ? join("\0", $value['msgstr']) : $value['msgstr'];
+      
+      // Trim imported translation to have whitesapce from source string.
+      $value['msgstr'] = l10n_community_trim($value['msgstr'], $value['msgid']);
 
       if ($translation && (empty($translation->translation) || ($translation->translation != $value['msgstr']))) {
         // If we have an empty translation placeholder (ie. no translation yet,
@@ -344,7 +352,12 @@ function _l10n_community_import_one_stri
       }
 
       if ($is_suggestion || !$translation) {
-        l10n_community_target_save($sid, $value['msgstr'], $langcode, $uid, $is_suggestion, $inserted, $updated, $unchanged, $suggested);
+        if (!l10n_community_is_duplicate($value['msgstr'], $sid, $langcode)) {
+          l10n_community_target_save($sid, $value['msgstr'], $langcode, $uid, $is_suggestion, $inserted, $updated, $unchanged, $suggested);
+        }
+        else {
+          $duplicates++;
+        }
       }
       else {
         // We certainly did not update this one.
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.53
diff -u -p -r1.1.2.23.2.53 l10n_community.module
--- l10n_community/l10n_community.module	30 Sep 2009 08:57:06 -0000	1.1.2.23.2.53
+++ l10n_community/l10n_community.module	30 Sep 2009 12:14:02 -0000
@@ -1090,9 +1090,6 @@ function l10n_community_get_contexts() {
  */
 function l10n_community_target_save($sid, $translation, $langcode, $uid, $suggestion, &$inserted, &$updated, &$unchanged, &$suggested) {
 
-  // Load source string and adjust translation whitespace based on source.
-  $source_string = db_result(db_query('SELECT value FROM {l10n_community_string} WHERE sid = %d', $sid));
-  $translation = l10n_community_trim($translation, $source_string);
   // Look for an existing active translation, if any.
   $existing_string = db_fetch_object(db_query("SELECT sid, tid, translation FROM {l10n_community_translation} WHERE sid = %d AND language = '%s' AND is_suggestion = 0 AND is_active = 1", $sid, $langcode));
 
@@ -1243,6 +1240,7 @@ function l10n_community_project_uri_by_t
  */
 function l10n_community_is_duplicate($suggestion, $sid, $langcode) {
   // Use BINARY matching to avoid marking case-corrections as duplicate.
+  // Matches everything active, regardless of being translations or suggestions.
   return (bool) db_result(db_query("SELECT s.sid FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid WHERE t.translation = BINARY '%s' AND t.is_active = 1 AND t.language = '%s' AND s.sid = %d", $suggestion, $langcode, $sid));
 }
 
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.19
diff -u -p -r1.1.2.7.2.19 translate.inc
--- l10n_community/translate.inc	18 Sep 2009 18:03:19 -0000	1.1.2.7.2.19
+++ l10n_community/translate.inc	30 Sep 2009 12:14:03 -0000
@@ -480,10 +480,11 @@ function l10n_community_translate_form_s
       continue;
     }
 
+    $source_string = db_result(db_query('SELECT value FROM {l10n_community_string} WHERE sid = %d', $sid));
     $text = '';
-    if (is_string($item['translation']['value'])) {
+    if (is_string($item['translation']['value']) && strlen(trim($item['translation']['value']))) {
       // Single string representation: simple translation.
-      $text = $item['translation']['value'];
+      $text = l10n_community_trim($item['translation']['value'], $source_string);
     }
     if (is_array($item['translation']['value'])) {
       // Array -> plural variants are provided. Join them with a NULL separator.
Index: l10n_remote/l10n_remote.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_remote/Attic/l10n_remote.module,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 l10n_remote.module
--- l10n_remote/l10n_remote.module	16 Sep 2009 14:01:18 -0000	1.1.2.2
+++ l10n_remote/l10n_remote.module	30 Sep 2009 12:14:03 -0000
@@ -117,35 +117,53 @@ function l10n_remote_xmlrpc_status($vers
 function l10n_remote_xmlrpc_string_submit($langcode, $source, $translation, $uid, $client_token, $signature) {
 
   // Check signature and permission parameters.
-  if ($uid && $signature == md5(l10n_remote_user_api_key($uid, $client_token) . $langcode . $source . $translation . $client_token)) {
-    if (($account = user_load($uid)) && $account->status && user_access('access localization community', $account) && user_access('submit suggestions remotely', $account)) {
-      watchdog('l10n_community', 'Submitted translation from client.');
-      // Check for existing string, and *always* save this as suggestion.
-      $languages = l10n_community_get_languages('name');
+  if (!($uid && $signature == md5(l10n_remote_user_api_key($uid, $client_token) . $langcode . $source . $translation . $client_token))) {
+    //watchdog('l10n_community', 'Submitted translation with wrong parameters or signature.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Wrong parameters or signature. Did you set your user API key on your user account page?');
+  }
+
+  // Check whether we have an actual translation to save.
+  $translation = trim($translation);
+  if (empty($translation)) {
+    //watchdog('l10n_community', 'Empty remote translation submission.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Empty translations are not saved.');
+  }
+  
+  // Check user access.
+  if (!(($account = user_load($uid)) && $account->status && user_access('access localization community', $account) && user_access('submit suggestions remotely', $account))) {
+    //watchdog('l10n_community', 'Unauthorized or blocked user attempted submission.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Blocked user account or no permission to submit translations.');
+  }
 
-      if (!isset($languages[$langcode])) {
-        watchdog('l10n_community', 'Language not allowed for remote submission.', NULL, WATCHDOG_WARNING);
-        return array('status' => FALSE, 'reason' => 'Language not accepted.');
-      }
-      elseif (l10n_community_get_permission($langcode, $account) == L10N_PERM_NONE) {
-        watchdog('l10n_community', 'Not allowed to submit translations in this language remotely.', NULL, WATCHDOG_WARNING);
-        return array('status' => FALSE, 'reason' => 'Not allowed to submit translations in this language.');
-      }
-      elseif ($sid = db_result(db_query("SELECT sid FROM {l10n_community_string} WHERE value = '%s'", $source))) {
-        l10n_community_target_save($sid, $translation, $langcode, $uid, TRUE, $inserted, $updated, $unchanged, $suggested);
-        return array('status' => TRUE, 'sid' => $sid);
-      }
-      else {
-        return array('status' => FALSE, 'reason' => 'Source string not found on server list.');
-      }
-    }
-    else {
-      watchdog('l10n_community', 'Unauthorized or blocked user attempted submission.', NULL, WATCHDOG_WARNING);
-      return array('status' => FALSE, 'reason' => 'No permission to submit translations.');
-    }
-  }
-  else {
-    watchdog('l10n_community', 'Submitted translation with wrong parameters or signature.', NULL, WATCHDOG_WARNING);
-    return array('status' => FALSE, 'reason' => 'Wrong parameters or signature.');
+  // Check that the language is set up on the server at all.
+  $languages = l10n_community_get_languages('name');
+  if (!isset($languages[$langcode])) {
+    //watchdog('l10n_community', 'Language not allowed for remote submission.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Language not accepted.');
+  }
+  
+  // Check if the user has permission to submit strings in this language. 
+  if (l10n_community_get_permission($langcode, $account) == L10N_PERM_NONE) {
+    //watchdog('l10n_community', 'Not allowed to submit translations in this language remotely.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Not allowed to submit translations in this language.');
+  }
+  
+  // Check whether we have this source string managed.
+  // @todo: add context support as soon as l10n_client starts to support it!
+  if (!($sid = db_result(db_query("SELECT sid FROM {l10n_community_string} WHERE BINARY value = '%s'", $source)))) {
+    //watchdog('l10n_community', 'Source string does not exist on server.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Source string not found on server, translation not saved.');
+  }
+  
+  // Trim string to have the same whitespace as the source and check duplicates.
+  $translation = l10n_community_trim($translation, $source);
+  if (l10n_community_is_duplicate($translation, $sid, $langcode)) {
+    //watchdog('l10n_community', 'Duplicate translation submitted.', NULL, WATCHDOG_WARNING);
+    return array('status' => FALSE, 'reason' => 'Suggested translation already appears as active translation or suggestion.');
   }
+  
+  // If we got this far, everything is fine and $translation contains the
+  // text as expected with whitespace correction. Signal success to the client.
+  l10n_community_target_save($sid, $translation, $langcode, $uid, TRUE, $inserted, $updated, $unchanged, $suggested);
+  return array('status' => TRUE, 'sid' => $sid);
 }
