Repository: translate/pootle

Issue:
Add timestamp to our local TM entries
When updating our local TM in Elasticsearch, let's add a timestamp of the submission (in UTC) as a separate field in the entry structure. In the translation editor, when rendering 'Similar translations' block, let's display the metadata like this:

`Translated by <username> in “<some_project>” project 2 days ago`

(where `2 days ago` is an extra part that is rendered based on the stored date). For entries that don't have a timestamp, we'll fallback to the current message format:

`Translated by <username> in “<some_project>”`

Rationale: knowing when the particular translation was added allows translators to put more weight to the translations that were done recently.



Discussion:

Resolving patch:
diff --git a/pootle/apps/pootle_app/management/commands/update_tmserver.py b/pootle/apps/pootle_app/management/commands/update_tmserver.py
--- a/pootle/apps/pootle_app/management/commands/update_tmserver.py
+++ b/pootle/apps/pootle_app/management/commands/update_tmserver.py
@@ -20,7 +20,9 @@
 
 from django.conf import settings
 from django.core.management.base import BaseCommand, CommandError
+from django.utils import dateparse
 
+from pootle.core.utils import dateformat
 from pootle_store.models import Unit
 
 
@@ -57,6 +59,7 @@ def get_units(self, *filenames):
                 'revision',
                 'source_f',
                 'target_f',
+                'submitted_on',
                 'submitted_by__username',
                 'submitted_by__full_name',
                 'submitted_by__email',
@@ -76,6 +79,14 @@ def get_unit_data(self, unit):
         if unit['submitted_by__email']:
             email_md5 = md5(unit['submitted_by__email']).hexdigest()
 
+        iso_submitted_on = unit.get('submitted_on', None)
+
+        display_submitted_on = None
+        if iso_submitted_on:
+            display_submitted_on = dateformat.format(
+                dateparse.parse_datetime(str(iso_submitted_on))
+            )
+
         return {
             '_index': self.INDEX_NAME,
             '_type': unit['store__translation_project__language__code'],
@@ -88,6 +99,8 @@ def get_unit_data(self, unit):
             'email_md5': email_md5,
             'source': unit['source_f'],
             'target': unit['target_f'],
+            'iso_submitted_on': iso_submitted_on,
+            'display_submitted_on': display_submitted_on,
         }
 
 
@@ -153,6 +166,8 @@ def get_unit_data(self, unit):
             'email_md5': None,
             'source': unit.source,
             'target': unit.target,
+            'iso_submitted_on': None,
+            'display_submitted_on': None,
         }
 
 
diff --git a/pootle/apps/pootle_store/models.py b/pootle/apps/pootle_store/models.py
--- a/pootle/apps/pootle_store/models.py
+++ b/pootle/apps/pootle_store/models.py
@@ -899,6 +899,12 @@ def update_tmserver(self):
             'email_md5': '',
         }
 
+        if self.submitted_on:
+            obj.update({
+                'iso_submitted_on': self.submitted_on.isoformat(),
+                'display_submitted_on': dateformat.format(self.submitted_on),
+            })
+
         if self.submitted_by:
             obj.update({
                 'username': self.submitted_by.username,
diff --git a/pootle/core/search/backends/elasticsearch.py b/pootle/core/search/backends/elasticsearch.py
--- a/pootle/core/search/backends/elasticsearch.py
+++ b/pootle/core/search/backends/elasticsearch.py
@@ -89,6 +89,9 @@ def search(self, unit):
                         'username': hit['_source']['username'],
                         'fullname': hit['_source']['fullname'],
                         'email_md5': hit['_source']['email_md5'],
+                        'iso_submitted_on': hit['_source'].get('iso_submitted_on', None),
+                        'display_submitted_on': hit['_source'].get('display_submitted_on',
+                                                                None),
                         'score': hit['_score'] * self.weight,
                     })
                 else:


Test patch: