|
@@ -2,10 +2,39 @@
|
2
|
2
|
|
3
|
3
|
import moment from 'moment';
|
4
|
4
|
|
|
5
|
+import { RECENT_URL_STORAGE } from './constants';
|
|
6
|
+
|
5
|
7
|
import { i18next } from '../base/i18n';
|
6
|
8
|
import { parseURIString } from '../base/util';
|
7
|
9
|
|
8
|
|
-import { RECENT_URL_STORAGE } from './constants';
|
|
10
|
+/**
|
|
11
|
+ * MomentJS uses static language bundle loading, so in order to support
|
|
12
|
+ * dynamic language selection in the app we need to load all bundles that we
|
|
13
|
+ * support in the app.
|
|
14
|
+ * FIXME: If we decide to support MomentJS in other features as well
|
|
15
|
+ * we may need to move this import and the lenient matcher to the i18n feature.
|
|
16
|
+ */
|
|
17
|
+require('moment/locale/bg');
|
|
18
|
+require('moment/locale/de');
|
|
19
|
+require('moment/locale/eo');
|
|
20
|
+require('moment/locale/es');
|
|
21
|
+require('moment/locale/fr');
|
|
22
|
+require('moment/locale/hy-am');
|
|
23
|
+require('moment/locale/it');
|
|
24
|
+require('moment/locale/nb');
|
|
25
|
+
|
|
26
|
+// OC is not available. Please submit OC translation
|
|
27
|
+// to the MomentJS project.
|
|
28
|
+
|
|
29
|
+require('moment/locale/pl');
|
|
30
|
+require('moment/locale/pt');
|
|
31
|
+require('moment/locale/pt-br');
|
|
32
|
+require('moment/locale/ru');
|
|
33
|
+require('moment/locale/sk');
|
|
34
|
+require('moment/locale/sl');
|
|
35
|
+require('moment/locale/sv');
|
|
36
|
+require('moment/locale/tr');
|
|
37
|
+require('moment/locale/zh-cn');
|
9
|
38
|
|
10
|
39
|
/**
|
11
|
40
|
* Retreives the recent room list and generates all the data needed to be
|
|
@@ -21,6 +50,11 @@ export function getRecentRooms(): Promise<Array<Object>> {
|
21
|
50
|
const recentRoomDS = [];
|
22
|
51
|
|
23
|
52
|
if (recentURLs) {
|
|
53
|
+ // we init the locale on every list render, so then it
|
|
54
|
+ // changes immediately if a language change happens
|
|
55
|
+ // in the app.
|
|
56
|
+ const locale = _getSupportedLocale();
|
|
57
|
+
|
24
|
58
|
for (const e of JSON.parse(recentURLs)) {
|
25
|
59
|
const location = parseURIString(e.conference);
|
26
|
60
|
|
|
@@ -31,8 +65,11 @@ export function getRecentRooms(): Promise<Array<Object>> {
|
31
|
65
|
conference: e.conference,
|
32
|
66
|
conferenceDuration: e.conferenceDuration,
|
33
|
67
|
conferenceDurationString:
|
34
|
|
- _getDurationString(e.conferenceDuration),
|
35
|
|
- dateString: _getDateString(e.date),
|
|
68
|
+ _getDurationString(
|
|
69
|
+ e.conferenceDuration,
|
|
70
|
+ locale
|
|
71
|
+ ),
|
|
72
|
+ dateString: _getDateString(e.date, locale),
|
36
|
73
|
dateTimeStamp: e.date,
|
37
|
74
|
initials: _getInitials(location.room),
|
38
|
75
|
room: location.room,
|
|
@@ -76,12 +113,15 @@ export function updateRecentURLs(recentURLs: Array<Object>) {
|
76
|
113
|
* Returns a well formatted date string to be displayed in the list.
|
77
|
114
|
*
|
78
|
115
|
* @param {number} dateTimeStamp - The UTC timestamp to be converted to String.
|
|
116
|
+ * @param {string} locale - The locale to init the formatter with. Note: This
|
|
117
|
+ * locale must be supported by the formatter so ensure this prerequisite
|
|
118
|
+ * before invoking the function.
|
79
|
119
|
* @private
|
80
|
120
|
* @returns {string}
|
81
|
121
|
*/
|
82
|
|
-function _getDateString(dateTimeStamp: number) {
|
|
122
|
+function _getDateString(dateTimeStamp: number, locale: string) {
|
83
|
123
|
const date = new Date(dateTimeStamp);
|
84
|
|
- const m = moment(date).locale(i18next.language);
|
|
124
|
+ const m = _getLocalizedFormatter(date, locale);
|
85
|
125
|
|
86
|
126
|
if (date.toDateString() === new Date().toDateString()) {
|
87
|
127
|
// The date is today, we use fromNow format.
|
|
@@ -96,12 +136,14 @@ function _getDateString(dateTimeStamp: number) {
|
96
|
136
|
* length.
|
97
|
137
|
*
|
98
|
138
|
* @param {number} duration - The duration in MS.
|
|
139
|
+ * @param {string} locale - The locale to init the formatter with. Note: This
|
|
140
|
+ * locale must be supported by the formatter so ensure this prerequisite
|
|
141
|
+ * before invoking the function.
|
99
|
142
|
* @private
|
100
|
143
|
* @returns {string}
|
101
|
144
|
*/
|
102
|
|
-function _getDurationString(duration: number) {
|
103
|
|
- return moment.duration(duration)
|
104
|
|
- .locale(i18next.language)
|
|
145
|
+function _getDurationString(duration: number, locale: string) {
|
|
146
|
+ return _getLocalizedFormatter(duration, locale)
|
105
|
147
|
.humanize();
|
106
|
148
|
}
|
107
|
149
|
|
|
@@ -115,3 +157,47 @@ function _getDurationString(duration: number) {
|
115
|
157
|
function _getInitials(room: string) {
|
116
|
158
|
return room && room.charAt(0) ? room.charAt(0).toUpperCase() : '?';
|
117
|
159
|
}
|
|
160
|
+
|
|
161
|
+/**
|
|
162
|
+ * Returns a localized date formatter initialized with the
|
|
163
|
+ * provided date (@code Date) or duration (@code Number).
|
|
164
|
+ *
|
|
165
|
+ * @private
|
|
166
|
+ * @param {Date | number} dateToFormat - The date or duration to format.
|
|
167
|
+ * @param {string} locale - The locale to init the formatter with. Note: This
|
|
168
|
+ * locale must be supported by the formatter so ensure this prerequisite
|
|
169
|
+ * before invoking the function.
|
|
170
|
+ * @returns {Object}
|
|
171
|
+ */
|
|
172
|
+function _getLocalizedFormatter(dateToFormat: Date | number, locale: string) {
|
|
173
|
+ if (typeof dateToFormat === 'number') {
|
|
174
|
+ return moment.duration(dateToFormat).locale(locale);
|
|
175
|
+ }
|
|
176
|
+
|
|
177
|
+ return moment(dateToFormat).locale(locale);
|
|
178
|
+}
|
|
179
|
+
|
|
180
|
+/**
|
|
181
|
+ * A lenient locale matcher to match language and dialect if possible.
|
|
182
|
+ *
|
|
183
|
+ * @private
|
|
184
|
+ * @returns {string}
|
|
185
|
+ */
|
|
186
|
+function _getSupportedLocale() {
|
|
187
|
+ const i18nLocale = i18next.language.toLowerCase();
|
|
188
|
+ const localeRegexp = new RegExp('^([a-z]{2,2})(-)*([a-z]{2,2})*$');
|
|
189
|
+ const localeResult = localeRegexp.exec(i18nLocale);
|
|
190
|
+
|
|
191
|
+ if (localeResult) {
|
|
192
|
+ const currentLocaleRegexp = new RegExp(
|
|
193
|
+ `^${localeResult[1]}(-)*${`(${localeResult[3]})*` || ''}`
|
|
194
|
+ );
|
|
195
|
+
|
|
196
|
+ return moment.locales().find(
|
|
197
|
+ lang => currentLocaleRegexp.exec(lang)
|
|
198
|
+ ) || 'en';
|
|
199
|
+ }
|
|
200
|
+
|
|
201
|
+ // default fallback
|
|
202
|
+ return 'en';
|
|
203
|
+}
|