[FIX #1048] Localize timestamps in chat history

If current locale is xx-YY, looks up xx_YY first, xx then and finally
falls back to us.

goog.i18n.DateTimeSymbols database is used for localization.

Signed-off-by: Eric Dvorsak <eric@dvorsak.fr>
This commit is contained in:
Mikhail Gusarov 2018-01-04 02:13:12 +01:00 committed by Eric Dvorsak
parent 2292d2e500
commit 4a08d2a818
No known key found for this signature in database
GPG Key ID: 932AC1CE5F05DE0C
3 changed files with 100 additions and 19 deletions

View File

@ -6,7 +6,10 @@
unparse]]
[status-im.i18n :refer [label label-pluralize]]
[goog.string :as gstring]
goog.string.format))
goog.string.format
goog.i18n.DateTimeFormat
[clojure.string :as s]
[goog.object :refer [get]]))
(defn now []
(t/now))
@ -21,18 +24,47 @@
(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60))))
(defn to-short-str
([ms]
(to-short-str ms #(unparse (formatters :hour-minute) %)))
([ms today-format-fn]
(let [date (from-long ms)
local (plus date time-zone-offset)
today (t/today-at-midnight)
yesterday (plus today (days -1))]
(cond
(before? date yesterday) (unparse (formatter "dd MMM hh:mm") local)
(before? date today) (label :t/datetime-yesterday)
:else (today-format-fn local)))))
;; xx-YY locale, xx locale or en fallback
(defn- locale-symbols [locale-name]
(if-let [loc (get goog.i18n (str "DateTimeSymbols_" locale-name))]
loc
(let [name-first (s/replace (or locale-name "") #"-.*$" "")
loc (get goog.i18n (str "DateTimeSymbols_" name-first))]
(or loc goog.i18n.DateTimeSymbols_en))))
;; Closure does not have an enum for datetime formats
(def short-date-time-format 10)
(def short-date-format 2)
(defn mk-fmt [locale format]
(goog.i18n.DateTimeFormat. format (locale-symbols locale)))
(def date-time-fmt
(mk-fmt status-im.i18n/locale short-date-time-format))
(def date-fmt
(mk-fmt status-im.i18n/locale short-date-format))
(defn- to-str [ms old-fmt-fn yesterday-fmt-fn today-fmt-fn]
(let [date (from-long ms)
local (plus date time-zone-offset)
today (t/today-at-midnight)
yesterday (plus today (days -1))]
(cond
(before? date yesterday) (old-fmt-fn local)
(before? date today) (yesterday-fmt-fn local)
:else (today-fmt-fn local))))
(defn to-short-str [ms]
(to-str ms
#(.format date-fmt %)
#(label :t/datetime-yesterday)
#(unparse (formatters :hour-minute) %)))
(defn day-relative [ms]
(to-str ms
#(.format date-time-fmt %)
#(label :t/datetime-yesterday)
#(label :t/datetime-today)))
(defn timestamp->mini-date [ms]
(unparse (formatter "dd MMM") (-> ms
@ -55,10 +87,6 @@
from-long
(plus time-zone-offset)))))
(defn day-relative [ms]
(when (pos? ms)
(to-short-str ms #(label :t/datetime-today))))
(defn format-time-ago [diff unit]
(let [name (label-pluralize diff (:name unit))]
(label :t/datetime-ago-format {:ago (label :t/datetime-ago)

View File

@ -21,7 +21,8 @@
[status-im.test.utils.gfycat.core]
[status-im.test.utils.signing-phrase.core]
[status-im.test.utils.transducers]
[status-im.test.utils.async]))
[status-im.test.utils.async]
[status-im.test.utils.datetime]))
(enable-console-print!)
@ -53,4 +54,5 @@
'status-im.test.utils.random
'status-im.test.utils.gfycat.core
'status-im.test.utils.signing-phrase.core
'status-im.test.utils.transducers)
'status-im.test.utils.transducers
'status-im.test.utils.datetime)

View File

@ -0,0 +1,51 @@
(ns status-im.test.utils.datetime
(:require [cljs.test :refer-macros [deftest is]]
[status-im.utils.datetime :as d]
[cljs-time.core :as t]))
(defn match [name symbols]
(is (identical? (.-dateTimeSymbols_ (d/mk-fmt name d/short-date-format))
symbols)))
(deftest date-time-formatter-test
(match "en-US" goog.i18n.DateTimeSymbols_en_US)
(match "en-ZZ" goog.i18n.DateTimeSymbols_en)
(match "en" goog.i18n.DateTimeSymbols_en)
(match "nb-NO" goog.i18n.DateTimeSymbols_nb)
(match "nb" goog.i18n.DateTimeSymbols_nb)
(match "whoa-WHOA" goog.i18n.DateTimeSymbols_en)
(match "whoa" goog.i18n.DateTimeSymbols_en))
;; 1970-01-01 00:00:00 UTC
(def epoch 0)
;; 1970-01-03 00:00:00 UTC
(def epoch-plus-3d 172800000)
(deftest to-short-str-today-test
(with-redefs [t/*ms-fn* (constantly epoch-plus-3d)
d/time-zone-offset (t/period :hours 0)]
(is (= (d/to-short-str epoch-plus-3d) "00:00"))))
(deftest to-short-str-before-yesterday-us-test
(with-redefs [t/*ms-fn* (constantly epoch-plus-3d)
d/time-zone-offset (t/period :hours 0)
d/date-fmt (d/mk-fmt "us" d/short-date-format)]
(is (= (d/to-short-str epoch) "Jan 1, 1970"))))
(deftest to-short-str-before-yesterday-nb-test
(with-redefs [d/time-zone-offset (t/period :hours 0)
d/date-fmt (d/mk-fmt "nb-NO" d/short-date-format)
t/*ms-fn* (constantly epoch-plus-3d)]
(is (= (d/to-short-str epoch) "1. jan. 1970"))))
(deftest day-relative-before-yesterday-us-test
(with-redefs [t/*ms-fn* (constantly epoch-plus-3d)
d/time-zone-offset (t/period :hours 0)
d/date-time-fmt (d/mk-fmt "us" d/short-date-time-format)]
(is (= (d/day-relative epoch) "Jan 1, 1970, 12:00:00 AM"))))
(deftest day-relative-before-yesterday-nb-test
(with-redefs [t/*ms-fn* (constantly epoch-plus-3d)
d/time-zone-offset (t/period :hours 0)
d/date-time-fmt (d/mk-fmt "nb-NO" d/short-date-time-format)]
(is (= (d/day-relative epoch) "1. jan. 1970, 00:00:00"))))