From 67c7a06c2852d69cd01ff0a989cdf6090eb909dd Mon Sep 17 00:00:00 2001
From: lilia <liliakai@gmail.com>
Date: Wed, 10 Aug 2016 11:33:56 -0700
Subject: [PATCH] Use momentjs for timestamp localization

Let momentjs handle proper pluralization of relative times. This comes
at the sacrifice of displaying 'minutes' in the conversation list
timestamp rather than 'min'. Note that we don't use moment's fromNow
instance method so as to preserve the rounding logic that matches the
Android client.

// FREEBIE
---
 _locales/en/messages.json         | 36 ++++---------------------------
 js/chromium.js                    |  9 +++++---
 js/views/timestamp_view.js        | 31 ++++++++++++--------------
 test/views/timestamp_view_test.js |  2 +-
 4 files changed, 25 insertions(+), 53 deletions(-)

diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 3255b25269..ba3e56eebe 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -310,43 +310,15 @@
         "description": "Informational text displayed if a sync operation times out."
     },
     "timestamp_s": {
-       "description": "Short or abbreviated timestamp for messages sent less than a minute ago. Displayed in the conversation list.",
+       "description": "Brief timestamp for messages sent less than a minute ago. Displayed in the conversation list and message bubble.",
        "message": "now"
     },
     "timestamp_m": {
-      "description": "Short or abbreviated timestamp for messages sent a minute ago. Displayed in the conversation list.",
-      "message": "1 min"
-    },
-    "timestamp_mm": {
-        "description": "Short or abbreviated timestamp for messages sent multiple minutes ago. Displayed in the conversation list.",
-       "message": "%d min"
+       "description": "Brief timestamp for messages sent about one minute ago. Displayed in the conversation list and message bubble.",
+       "message": "1 minute"
     },
     "timestamp_h": {
-        "description": "Short or abbreviated timestamp for messages sent about an hour ago. Displayed in the conversation list.",
+       "description": "Brief timestamp for messages sent about one minute ago. Displayed in the conversation list and message bubble.",
        "message": "1 hour"
-    },
-    "timestamp_hh": {
-        "description": "Short or abbreviated timestamp for messages sent multiple hours ago. Displayed in the conversation list.",
-       "message": "%d hours"
-    },
-    "extendedTimestamp_s": {
-        "description": "Timestamp for messages sent less than a minute ago. Displayed in the message bubble.",
-       "message": "now"
-    },
-    "extendedTimestamp_m": {
-       "description": "Timestamp for messages sent about a minute ago. Displayed in the message bubble.",
-       "message": "1 minute ago"
-    },
-    "extendedTimestamp_mm": {
-       "description": "Timestamp for messages sent multiple minutes ago. Displayed in the message bubble.",
-       "message": "%d minutes ago"
-    },
-    "extendedTimestamp_h": {
-       "description": "Timestamp for messages sent one hour ago. Displayed in the message bubble.",
-       "message": "1 hour ago"
-    },
-    "extendedTimestamp_hh": {
-       "description": "Timestamp for messages sent multiple hours ago. Displayed in the message bubble.",
-       "message": "%d hours ago"
     }
 }
diff --git a/js/chromium.js b/js/chromium.js
index 87412124f2..39d7b5f3e0 100644
--- a/js/chromium.js
+++ b/js/chromium.js
@@ -169,9 +169,12 @@
             return chrome.i18n.getMessage(message, substitutions);
         }
     };
-    if (window.chrome && chrome.i18n) {
-        moment.locale(chrome.i18n.getUILanguage());
-    }
+    i18n.getLocale = function() {
+        if (window.chrome && chrome.i18n) {
+            return chrome.i18n.getUILanguage();
+        }
+        return 'en';
+    };
 
     window.textsecure = window.textsecure || {};
     window.textsecure.registration = {
diff --git a/js/views/timestamp_view.js b/js/views/timestamp_view.js
index bb1999bd98..3de8b515cf 100644
--- a/js/views/timestamp_view.js
+++ b/js/views/timestamp_view.js
@@ -5,6 +5,15 @@
     'use strict';
     window.Whisper = window.Whisper || {};
 
+    moment.updateLocale(i18n.getLocale(), {
+        relativeTime : {
+            s: i18n('timestamp_s') || 'now',
+            m: i18n('timestamp_m') || '1 minute',
+            h: i18n('timestamp_h') || '1 hour'
+        }
+    });
+    moment.locale(i18n.getLocale());
+
     Whisper.TimestampView = Whisper.View.extend({
         initialize: function(options) {
             extension.windows.onClosed(this.clearTimeout.bind(this));
@@ -50,13 +59,13 @@
                 return timestamp.format(this._format.d);
             } else if (timediff.hours() > 1) {
                 this.delay = moment(timestamp).add(timediff.hours() + 1,'h').diff(moment());
-                return this.relativeTime(timediff.hours(), 'hh');
+                return this.relativeTime(timediff.hours(), 'h');
             } else if (timediff.hours() === 1) {
                 this.delay = moment(timestamp).add(timediff.hours() + 1,'h').diff(moment());
                 return this.relativeTime(timediff.hours(), 'h');
             } else if (timediff.minutes() > 1) {
                 this.delay = moment(timestamp).add(timediff.minutes() + 1,'m').diff(moment());
-                return this.relativeTime(timediff.minutes(), 'mm');
+                return this.relativeTime(timediff.minutes(), 'm');
             } else if (timediff.minutes() === 1) {
                 this.delay = moment(timestamp).add(timediff.minutes() + 1,'m').diff(moment());
                 return this.relativeTime(timediff.minutes(), 'm');
@@ -65,16 +74,10 @@
                 return this.relativeTime(timediff.seconds(), 's');
             }
         },
-        relativeTime : function (number, string, isFuture) {
-            var format = i18n("timestamp_"+string) || this._format[string];
-            return format.replace(/%d/i, number);
+        relativeTime : function (number, string) {
+            return moment.duration(number, string).humanize();
         },
         _format: {
-            s: "now",
-            m: "1 min",
-            mm: "%d min",
-            h: "1 hour",
-            hh: "%d hours",
             y: "MMM D, YYYY",
             mo: "MMM D",
             d: "ddd"
@@ -82,15 +85,9 @@
     });
     Whisper.ExtendedTimestampView = Whisper.TimestampView.extend({
         relativeTime : function (number, string, isFuture) {
-            var format = i18n("extendedTimestamp_"+string) || this._format[string];
-            return format.replace(/%d/i, number);
+            return moment.duration(-1 * number, string).humanize(string !== 's');
         },
         _format: {
-            s: "now",
-            m: "%d minute ago",
-            mm: "%d minutes ago",
-            h: "%d hour ago",
-            hh: "%d hours ago",
             y: "MMM D, YYYY LT",
             mo: "MMM D LT",
             d: "ddd LT"
diff --git a/test/views/timestamp_view_test.js b/test/views/timestamp_view_test.js
index 3615666e11..bf426926f8 100644
--- a/test/views/timestamp_view_test.js
+++ b/test/views/timestamp_view_test.js
@@ -46,7 +46,7 @@ describe('TimestampView', function() {
 
         // check recent timestamps
         checkDiff(30, 'now', 'now'); // 30 seconds
-        checkDiff(40*60, '40 min', '40 minutes ago');
+        checkDiff(40*60, '40 minutes', '40 minutes ago');
         checkDiff(60*60, '1 hour', '1 hour ago');
         checkDiff(125*60, '2 hours', '2 hours ago');