Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RN] Add proper locale support to MomentJS #2325

Merged
merged 1 commit into from
Jan 3, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 94 additions & 8 deletions react/features/recent-list/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,39 @@

import moment from 'moment';

import { RECENT_URL_STORAGE } from './constants';

import { i18next } from '../base/i18n';
import { parseURIString } from '../base/util';

import { RECENT_URL_STORAGE } from './constants';
/**
* MomentJS uses static language bundle loading, so in order to support
* dynamic language selection in the app we need to load all bundles that we
* support in the app.
* FIXME: If we decide to support MomentJS in other features as well
* we may need to move this import and the lenient matcher to the i18n feature.
*/
require('moment/locale/bg');
require('moment/locale/de');
require('moment/locale/eo');
require('moment/locale/es');
require('moment/locale/fr');
require('moment/locale/hy-am');
require('moment/locale/it');
require('moment/locale/nb');

// OC is not available. Please submit OC translation
// to the MomentJS project.

require('moment/locale/pl');
require('moment/locale/pt');
require('moment/locale/pt-br');
require('moment/locale/ru');
require('moment/locale/sk');
require('moment/locale/sl');
require('moment/locale/sv');
require('moment/locale/tr');
require('moment/locale/zh-cn');

/**
* Retreives the recent room list and generates all the data needed to be
Expand All @@ -21,6 +50,11 @@ export function getRecentRooms(): Promise<Array<Object>> {
const recentRoomDS = [];

if (recentURLs) {
// we init the locale on every list render, so then it
// changes immediately if a language change happens
// in the app.
const locale = _getSupportedLocale();

for (const e of JSON.parse(recentURLs)) {
const location = parseURIString(e.conference);

Expand All @@ -31,8 +65,11 @@ export function getRecentRooms(): Promise<Array<Object>> {
conference: e.conference,
conferenceDuration: e.conferenceDuration,
conferenceDurationString:
_getDurationString(e.conferenceDuration),
dateString: _getDateString(e.date),
_getDurationString(
e.conferenceDuration,
locale
),
dateString: _getDateString(e.date, locale),
dateTimeStamp: e.date,
initials: _getInitials(location.room),
room: location.room,
Expand Down Expand Up @@ -76,12 +113,15 @@ export function updateRecentURLs(recentURLs: Array<Object>) {
* Returns a well formatted date string to be displayed in the list.
*
* @param {number} dateTimeStamp - The UTC timestamp to be converted to String.
* @param {string} locale - The locale to init the formatter with. Note: This
* locale must be supported by the formatter so ensure this prerequisite
* before invoking the function.
* @private
* @returns {string}
*/
function _getDateString(dateTimeStamp: number) {
function _getDateString(dateTimeStamp: number, locale: string) {
const date = new Date(dateTimeStamp);
const m = moment(date).locale(i18next.language);
const m = _getLocalizedFormatter(date, locale);

if (date.toDateString() === new Date().toDateString()) {
// The date is today, we use fromNow format.
Expand All @@ -96,12 +136,14 @@ function _getDateString(dateTimeStamp: number) {
* length.
*
* @param {number} duration - The duration in MS.
* @param {string} locale - The locale to init the formatter with. Note: This
* locale must be supported by the formatter so ensure this prerequisite
* before invoking the function.
* @private
* @returns {string}
*/
function _getDurationString(duration: number) {
return moment.duration(duration)
.locale(i18next.language)
function _getDurationString(duration: number, locale: string) {
return _getLocalizedFormatter(duration, locale)
.humanize();
}

Expand All @@ -115,3 +157,47 @@ function _getDurationString(duration: number) {
function _getInitials(room: string) {
return room && room.charAt(0) ? room.charAt(0).toUpperCase() : '?';
}

/**
* Returns a localized date formatter initialized with the
* provided date (@code Date) or duration (@code Number).
*
* @private
* @param {Date | number} dateToFormat - The date or duration to format.
* @param {string} locale - The locale to init the formatter with. Note: This
* locale must be supported by the formatter so ensure this prerequisite
* before invoking the function.
* @returns {Object}
*/
function _getLocalizedFormatter(dateToFormat: Date | number, locale: string) {
if (typeof dateToFormat === 'number') {
return moment.duration(dateToFormat).locale(locale);
}

return moment(dateToFormat).locale(locale);
}

/**
* A lenient locale matcher to match language and dialect if possible.
*
* @private
* @returns {string}
*/
function _getSupportedLocale() {
const i18nLocale = i18next.language.toLowerCase();
const localeRegexp = new RegExp('^([a-z]{2,2})(-)*([a-z]{2,2})*$');
const localeResult = localeRegexp.exec(i18nLocale);

if (localeResult) {
const currentLocaleRegexp = new RegExp(
`^${localeResult[1]}(-)*${`(${localeResult[3]})*` || ''}`
);

return moment.locales().find(
lang => currentLocaleRegexp.exec(lang)
) || 'en';
}

// default fallback
return 'en';
}