From 4f27a022c3e9e4ee3b85ecc85f175bb9af2bc8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Tue, 12 Aug 2025 14:28:25 +0200 Subject: [PATCH] Make relatives times coherent with web (#9062) * Make relatives times coherent with web * Fix test --- .../friendly_date/friendly_date.test.tsx | 89 ++++++--- app/components/friendly_date/index.tsx | 170 ++++-------------- app/i18n/index.ts | 21 +++ .../checklist_item/checklist_item.test.tsx | 4 +- assets/base/i18n/en.json | 12 -- index.ts | 1 + package-lock.json | 12 ++ package.json | 1 + 8 files changed, 133 insertions(+), 177 deletions(-) diff --git a/app/components/friendly_date/friendly_date.test.tsx b/app/components/friendly_date/friendly_date.test.tsx index 4929f54b3..c57733a7c 100644 --- a/app/components/friendly_date/friendly_date.test.tsx +++ b/app/components/friendly_date/friendly_date.test.tsx @@ -9,118 +9,157 @@ import FriendlyDate from './index'; describe('Friendly Date', () => { it('should render correctly', () => { + jest.useFakeTimers(); + jest.setSystemTime(new Date('2020-05-15T00:00:00.000Z')); + const justNow = new Date(); justNow.setSeconds(justNow.getSeconds() - 10); + let value = justNow.getTime(); const justNowText = renderWithIntl( - , + , ); expect(justNowText.getByText('Now')).toBeTruthy(); const minutesAgo = new Date(); minutesAgo.setMinutes(minutesAgo.getMinutes() - 1); + value = minutesAgo.getTime(); const minutesAgoText = renderWithIntl( - , + , ); - expect(minutesAgoText.getByText('1 min ago')).toBeTruthy(); + expect(minutesAgoText.getByText('1 min. ago')).toBeTruthy(); const hoursAgo = new Date(); hoursAgo.setHours(hoursAgo.getHours() - 4); + value = hoursAgo.getTime(); const hoursAgoText = renderWithIntl( - , + , ); expect(hoursAgoText.getByText('4 hours ago')).toBeTruthy(); const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); + value = yesterday.getTime(); const yesterdayText = renderWithIntl( - , + , ); - expect(yesterdayText.getByText('Yesterday')).toBeTruthy(); + expect(yesterdayText.getByText('yesterday')).toBeTruthy(); const daysAgo = new Date(); daysAgo.setDate(daysAgo.getDate() - 10); + value = daysAgo.getTime(); const daysAgoText = renderWithIntl( - , + , ); expect(daysAgoText.getByText('10 days ago')).toBeTruthy(); // Difference is less than 30 days const daysEdgeCase = new Date(2020, 3, 28); const daysEdgeCaseTodayDate = new Date(2020, 4, 28); + jest.setSystemTime(daysEdgeCaseTodayDate); + value = daysEdgeCase.getTime(); const daysEdgeCaseText = renderWithIntl( - , + , ); - expect(daysEdgeCaseText.getByText('1 month ago')).toBeTruthy(); + expect(daysEdgeCaseText.getByText('last month')).toBeTruthy(); const daysAgoMax = new Date(2020, 4, 6); const daysAgoMaxTodayDate = new Date(2020, 5, 5); + jest.setSystemTime(daysAgoMaxTodayDate); + value = daysAgoMax.getTime(); const daysAgoMaxText = renderWithIntl( - , + , ); expect(daysAgoMaxText.getByText('30 days ago')).toBeTruthy(); const monthsAgo = new Date(); monthsAgo.setMonth(monthsAgo.getMonth() - 2); + value = monthsAgo.getTime(); const monthsAgoText = renderWithIntl( - , + , ); expect(monthsAgoText.getByText('2 months ago')).toBeTruthy(); const yearsAgo = new Date(); yearsAgo.setFullYear(yearsAgo.getFullYear() - 2); + value = yearsAgo.getTime(); const yearsAgoText = renderWithIntl( - , + , ); expect(yearsAgoText.getByText('2 years ago')).toBeTruthy(); + + jest.useRealTimers(); }); it('should render correctly with times in the future', () => { + jest.useFakeTimers(); + jest.setSystemTime(new Date('2020-05-15T00:00:00.000Z')); + const justNow = new Date(); justNow.setSeconds(justNow.getSeconds() + 10); + let value = justNow.getTime(); const justNowText = renderWithIntl( - , + , ); expect(justNowText.getByText('Now')).toBeTruthy(); const inMinutes = new Date(); inMinutes.setMinutes(inMinutes.getMinutes() + 2); + value = inMinutes.getTime(); const inMinutesText = renderWithIntl( - , + , ); - expect(inMinutesText.getByText('in 2 mins')).toBeTruthy(); + expect(inMinutesText.getByText('in 2 min.')).toBeTruthy(); const inHours = new Date(); inHours.setHours(inHours.getHours() + 2); + value = inHours.getTime(); const inHoursText = renderWithIntl( - , + , ); expect(inHoursText.getByText('in 2 hours')).toBeTruthy(); const inDays = new Date(); inDays.setDate(inDays.getDate() + 2); + value = inDays.getTime(); const inDaysText = renderWithIntl( - , + , ); expect(inDaysText.getByText('in 2 days')).toBeTruthy(); + const inDaysEdgeCase = new Date(2020, 5, 28); + const inDaysEdgeCaseTodayDate = new Date(2020, 4, 28); + jest.setSystemTime(inDaysEdgeCaseTodayDate); + value = inDaysEdgeCase.getTime(); + const inDaysEdgeCaseText = renderWithIntl( + , + ); + expect(inDaysEdgeCaseText.getByText('next month')).toBeTruthy(); + + const inDaysMax = new Date(2020, 5, 4); + const inDaysMaxTodayDate = new Date(2020, 4, 5); + jest.setSystemTime(inDaysMaxTodayDate); + value = inDaysMax.getTime(); + const inDaysMaxText = renderWithIntl( + , + ); + expect(inDaysMaxText.getByText('in 30 days')).toBeTruthy(); + const inMonths = new Date(); inMonths.setMonth(inMonths.getMonth() + 2); + value = inMonths.getTime(); const inMonthsText = renderWithIntl( - , + , ); expect(inMonthsText.getByText('in 2 months')).toBeTruthy(); const inYears = new Date(); inYears.setFullYear(inYears.getFullYear() + 2); + value = inYears.getTime(); const inYearsText = renderWithIntl( - , + , ); expect(inYearsText.getByText('in 2 years')).toBeTruthy(); + + jest.useRealTimers(); }); }); diff --git a/app/components/friendly_date/index.tsx b/app/components/friendly_date/index.tsx index b4a204530..61bef3196 100644 --- a/app/components/friendly_date/index.tsx +++ b/app/components/friendly_date/index.tsx @@ -1,43 +1,49 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import moment from 'moment'; import React from 'react'; import {type IntlShape, useIntl} from 'react-intl'; import {type StyleProp, Text, type TextStyle} from 'react-native'; import {DateTime} from '@constants'; -import {isYesterday} from '@utils/datetime'; const {SECONDS} = DateTime; type Props = { style?: StyleProp; - sourceDate?: number | Date; - value: number | Date; + value: number; }; -function FriendlyDate({style, sourceDate, value}: Props) { +function FriendlyDate({style, value}: Props) { const intl = useIntl(); - const formattedTime = getFriendlyDate(intl, value, sourceDate); + const formattedTime = getFriendlyDate(intl, value); return ( {formattedTime} ); } -export function getFriendlyDate(intl: IntlShape, inputDate: number | Date, sourceDate?: number | Date): string { - const today = sourceDate ? new Date(sourceDate) : new Date(); - const date = new Date(inputDate); - const difference = (today.getTime() - date.getTime()) / 1000; - if (difference < 0) { - return getFriendlyDateAfter(intl, -difference, date, today); - } +function getDiff(inputDate: number, unit: moment.unitOfTime.Diff) { + const input = new Date(inputDate); + const today = new Date(); - return getFriendlyDateBefore(intl, difference, date, today); + const momentA = moment.utc(input.getTime()); + const momentB = moment.utc(today.getTime()); + + const diff = momentA.startOf(unit).diff(momentB.startOf(unit), unit); + + return diff; } -function getFriendlyDateAfter(intl: IntlShape, difference: number, date: Date, today: Date): string { +export function getFriendlyDate(intl: IntlShape, inputDate: number): string { + const today = new Date(); + const date = new Date(inputDate); + const difference = (date.getTime() - today.getTime()) / 1000; + const absoluteDifference = Math.abs(difference); + const sign = Math.sign(difference); + // Message: Now - if (difference < SECONDS.MINUTE) { + if (absoluteDifference < SECONDS.MINUTE) { return intl.formatMessage({ id: 'friendly_date.now', defaultMessage: 'Now', @@ -45,143 +51,31 @@ function getFriendlyDateAfter(intl: IntlShape, difference: number, date: Date, t } // Message: Minutes - if (difference < SECONDS.HOUR) { - const minutes = Math.floor(Math.round((10 * difference) / SECONDS.MINUTE) / 10); - return intl.formatMessage({ - id: 'friendly_date.mins', - defaultMessage: 'in {count} {count, plural, one {min} other {mins}}', - }, { - count: minutes, - }); + if (absoluteDifference < SECONDS.HOUR) { + return intl.formatRelativeTime(getDiff(inputDate, 'minute'), 'minute', {numeric: 'auto', style: 'short'}); } // Message: Hours - if (difference < SECONDS.DAY) { - const hours = Math.floor(Math.round((10 * difference) / SECONDS.HOUR) / 10); - return intl.formatMessage({ - id: 'friendly_date.hours', - defaultMessage: 'in {count} {count, plural, one {hour} other {hours}}', - }, { - count: hours, - }); + if (absoluteDifference < SECONDS.DAY) { + return intl.formatRelativeTime(getDiff(inputDate, 'hour'), 'hour', {numeric: 'auto'}); } // Message: Days - if (difference < SECONDS.DAYS_31) { - if (today.getDate() + 1 === date.getDate() && today.getMonth() === date.getMonth()) { - return intl.formatMessage({ - id: 'friendly_date.tomorrow', - defaultMessage: 'Tomorrow', - }); - } - const completedAMonth = today.getMonth() !== date.getMonth() && today.getDate() <= date.getDate(); + if (absoluteDifference < SECONDS.DAYS_31) { + const passedDate = sign === 1 ? today.getDate() <= date.getDate() : today.getDate() >= date.getDate(); + const completedAMonth = today.getMonth() !== date.getMonth() && passedDate; if (!completedAMonth) { - const days = Math.floor(Math.round((10 * difference) / SECONDS.DAY) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.days', - defaultMessage: 'in {count} {count, plural, one {day} other {days}}', - }, { - count: days, - }); + return intl.formatRelativeTime(getDiff(inputDate, 'day'), 'day', {numeric: 'auto'}); } } // Message: Months - if (difference < SECONDS.DAYS_366) { - const months = Math.floor(Math.round((10 * difference) / SECONDS.DAYS_30) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.months', - defaultMessage: 'in {count} {count, plural, one {month} other {months}}', - }, { - count: months, - }); + if (absoluteDifference < SECONDS.DAYS_366) { + return intl.formatRelativeTime(getDiff(inputDate, 'month'), 'month', {numeric: 'auto'}); } // Message: Years - const years = Math.floor(Math.round((10 * difference) / SECONDS.DAYS_365) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.years', - defaultMessage: 'in {count} {count, plural, one {year} other {years}}', - }, { - count: years, - }); -} - -function getFriendlyDateBefore(intl: IntlShape, difference: number, date: Date, today: Date): string { - // Message: Now - if (difference < SECONDS.MINUTE) { - return intl.formatMessage({ - id: 'friendly_date.now', - defaultMessage: 'Now', - }); - } - - // Message: Minutes Ago - if (difference < SECONDS.HOUR) { - const minutes = Math.floor(Math.round((10 * difference) / SECONDS.MINUTE) / 10); - return intl.formatMessage({ - id: 'friendly_date.minsAgo', - defaultMessage: '{count} {count, plural, one {min} other {mins}} ago', - }, { - count: minutes, - }); - } - - // Message: Hours Ago - if (difference < SECONDS.DAY) { - const hours = Math.floor(Math.round((10 * difference) / SECONDS.HOUR) / 10); - return intl.formatMessage({ - id: 'friendly_date.hoursAgo', - defaultMessage: '{count} {count, plural, one {hour} other {hours}} ago', - }, { - count: hours, - }); - } - - // Message: Days Ago - if (difference < SECONDS.DAYS_31) { - if (isYesterday(date)) { - return intl.formatMessage({ - id: 'friendly_date.yesterday', - defaultMessage: 'Yesterday', - }); - } - const completedAMonth = today.getMonth() !== date.getMonth() && today.getDate() >= date.getDate(); - if (!completedAMonth) { - const days = Math.floor(Math.round((10 * difference) / SECONDS.DAY) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.daysAgo', - defaultMessage: '{count} {count, plural, one {day} other {days}} ago', - }, { - count: days, - }); - } - } - - // Message: Months Ago - if (difference < SECONDS.DAYS_366) { - const completedAnYear = today.getFullYear() !== date.getFullYear() && - today.getMonth() >= date.getMonth() && - today.getDate() >= date.getDate(); - if (!completedAnYear) { - const months = Math.floor(Math.round((10 * difference) / SECONDS.DAYS_30) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.monthsAgo', - defaultMessage: '{count} {count, plural, one {month} other {months}} ago', - }, { - count: months, - }); - } - } - - // Message: Years Ago - const years = Math.floor(Math.round((10 * difference) / SECONDS.DAYS_365) / 10) || 1; - return intl.formatMessage({ - id: 'friendly_date.yearsAgo', - defaultMessage: '{count} {count, plural, one {year} other {years}} ago', - }, { - count: years, - }); + return intl.formatRelativeTime(getDiff(inputDate, 'year'), 'year', {numeric: 'auto'}); } export default FriendlyDate; diff --git a/app/i18n/index.ts b/app/i18n/index.ts index c5aad9124..5ba98e21d 100644 --- a/app/i18n/index.ts +++ b/app/i18n/index.ts @@ -24,6 +24,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/bg'); require('@formatjs/intl-datetimeformat/locale-data/bg'); require('@formatjs/intl-listformat/locale-data/bg'); + require('@formatjs/intl-relativetimeformat/locale-data/bg'); translations = require('@assets/i18n/bg.json'); break; @@ -32,6 +33,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/de'); require('@formatjs/intl-datetimeformat/locale-data/de'); require('@formatjs/intl-listformat/locale-data/de'); + require('@formatjs/intl-relativetimeformat/locale-data/de'); translations = require('@assets/i18n/de.json'); break; @@ -40,6 +42,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/en'); require('@formatjs/intl-datetimeformat/locale-data/en'); require('@formatjs/intl-listformat/locale-data/en'); + require('@formatjs/intl-relativetimeformat/locale-data/en'); translations = require('@assets/i18n/en_AU.json'); break; @@ -48,6 +51,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/es'); require('@formatjs/intl-datetimeformat/locale-data/es'); require('@formatjs/intl-listformat/locale-data/es'); + require('@formatjs/intl-relativetimeformat/locale-data/es'); translations = require('@assets/i18n/es.json'); break; @@ -56,6 +60,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/fa'); require('@formatjs/intl-datetimeformat/locale-data/fa'); require('@formatjs/intl-listformat/locale-data/fa'); + require('@formatjs/intl-relativetimeformat/locale-data/fa'); translations = require('@assets/i18n/fa.json'); break; @@ -64,6 +69,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/fr'); require('@formatjs/intl-datetimeformat/locale-data/fr'); require('@formatjs/intl-listformat/locale-data/fr'); + require('@formatjs/intl-relativetimeformat/locale-data/fr'); translations = require('@assets/i18n/fr.json'); break; @@ -72,6 +78,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/hu'); require('@formatjs/intl-datetimeformat/locale-data/hu'); require('@formatjs/intl-listformat/locale-data/hu'); + require('@formatjs/intl-relativetimeformat/locale-data/hu'); translations = require('@assets/i18n/hu.json'); break; @@ -80,6 +87,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/it'); require('@formatjs/intl-datetimeformat/locale-data/it'); require('@formatjs/intl-listformat/locale-data/it'); + require('@formatjs/intl-relativetimeformat/locale-data/it'); translations = require('@assets/i18n/it.json'); break; @@ -88,6 +96,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/ja'); require('@formatjs/intl-datetimeformat/locale-data/ja'); require('@formatjs/intl-listformat/locale-data/ja'); + require('@formatjs/intl-relativetimeformat/locale-data/ja'); translations = require('@assets/i18n/ja.json'); break; @@ -96,6 +105,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/ko'); require('@formatjs/intl-datetimeformat/locale-data/ko'); require('@formatjs/intl-listformat/locale-data/ko'); + require('@formatjs/intl-relativetimeformat/locale-data/ko'); translations = require('@assets/i18n/ko.json'); break; @@ -104,6 +114,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/nl'); require('@formatjs/intl-datetimeformat/locale-data/nl'); require('@formatjs/intl-listformat/locale-data/nl'); + require('@formatjs/intl-relativetimeformat/locale-data/nl'); translations = require('@assets/i18n/nl.json'); break; @@ -112,6 +123,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/pl'); require('@formatjs/intl-datetimeformat/locale-data/pl'); require('@formatjs/intl-listformat/locale-data/pl'); + require('@formatjs/intl-relativetimeformat/locale-data/pl'); translations = require('@assets/i18n/pl.json'); break; @@ -120,6 +132,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/pt'); require('@formatjs/intl-datetimeformat/locale-data/pt'); require('@formatjs/intl-listformat/locale-data/pt'); + require('@formatjs/intl-relativetimeformat/locale-data/pt'); translations = require('@assets/i18n/pt-BR.json'); break; @@ -128,6 +141,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/ro'); require('@formatjs/intl-datetimeformat/locale-data/ro'); require('@formatjs/intl-listformat/locale-data/ro'); + require('@formatjs/intl-relativetimeformat/locale-data/ro'); translations = require('@assets/i18n/ro.json'); break; @@ -136,6 +150,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/ru'); require('@formatjs/intl-datetimeformat/locale-data/ru'); require('@formatjs/intl-listformat/locale-data/ru'); + require('@formatjs/intl-relativetimeformat/locale-data/ru'); translations = require('@assets/i18n/ru.json'); break; @@ -144,6 +159,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/sv'); require('@formatjs/intl-datetimeformat/locale-data/sv'); require('@formatjs/intl-listformat/locale-data/sv'); + require('@formatjs/intl-relativetimeformat/locale-data/sv'); translations = require('@assets/i18n/sv.json'); break; @@ -152,6 +168,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/tr'); require('@formatjs/intl-datetimeformat/locale-data/tr'); require('@formatjs/intl-listformat/locale-data/tr'); + require('@formatjs/intl-relativetimeformat/locale-data/tr'); translations = require('@assets/i18n/tr.json'); break; @@ -160,6 +177,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/uk'); require('@formatjs/intl-datetimeformat/locale-data/uk'); require('@formatjs/intl-listformat/locale-data/uk'); + require('@formatjs/intl-relativetimeformat/locale-data/uk'); translations = require('@assets/i18n/uk.json'); break; @@ -168,6 +186,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/vi'); require('@formatjs/intl-datetimeformat/locale-data/vi'); require('@formatjs/intl-listformat/locale-data/vi'); + require('@formatjs/intl-relativetimeformat/locale-data/vi'); translations = require('@assets/i18n/vi.json'); break; @@ -184,6 +203,7 @@ function loadTranslation(locale?: string): {[x: string]: string} { require('@formatjs/intl-numberformat/locale-data/en'); require('@formatjs/intl-datetimeformat/locale-data/en'); require('@formatjs/intl-listformat/locale-data/en'); + require('@formatjs/intl-relativetimeformat/locale-data/en'); translations = en; break; @@ -201,6 +221,7 @@ function loadChinesePolyfills() { require('@formatjs/intl-numberformat/locale-data/zh'); require('@formatjs/intl-datetimeformat/locale-data/zh'); require('@formatjs/intl-listformat/locale-data/zh'); + require('@formatjs/intl-relativetimeformat/locale-data/zh'); } export function getLocaleFromLanguage(lang: string) { diff --git a/app/products/playbooks/screens/playbook_run/checklist/checklist_item/checklist_item.test.tsx b/app/products/playbooks/screens/playbook_run/checklist/checklist_item/checklist_item.test.tsx index 3bf18f892..458795a88 100644 --- a/app/products/playbooks/screens/playbook_run/checklist/checklist_item/checklist_item.test.tsx +++ b/app/products/playbooks/screens/playbook_run/checklist/checklist_item/checklist_item.test.tsx @@ -239,7 +239,7 @@ describe('ChecklistItem', () => { const {getByTestId, rerender, queryByTestId} = renderWithIntl(); let chip = getByTestId('base-chip-component'); expect(chip).toBeVisible(); - expect(chip.props.label).toBe('Due Tomorrow'); + expect(chip.props.label).toBe('Due tomorrow'); expect(chip.props.type).toBe('normal'); expect(chip.props.boldText).toBe(false); expect(chip.props.prefix).toBeDefined(); @@ -263,7 +263,7 @@ describe('ChecklistItem', () => { rerender(); chip = getByTestId('base-chip-component'); expect(chip).toBeVisible(); - expect(chip.props.label).toBe('Due 1 year ago'); + expect(chip.props.label).toBe('Due last year'); expect(chip.props.type).toBe('danger'); expect(chip.props.boldText).toBe(true); expect(chip.props.prefix).toBeDefined(); diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 39de5d367..62586d032 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -367,19 +367,7 @@ "find_channels.new_channel": "New Channel", "find_channels.open_dm": "Open a DM", "find_channels.title": "Find Channels", - "friendly_date.days": "in {count} {count, plural, one {day} other {days}}", - "friendly_date.daysAgo": "{count} {count, plural, one {day} other {days}} ago", - "friendly_date.hours": "in {count} {count, plural, one {hour} other {hours}}", - "friendly_date.hoursAgo": "{count} {count, plural, one {hour} other {hours}} ago", - "friendly_date.mins": "in {count} {count, plural, one {min} other {mins}}", - "friendly_date.minsAgo": "{count} {count, plural, one {min} other {mins}} ago", - "friendly_date.months": "in {count} {count, plural, one {month} other {months}}", - "friendly_date.monthsAgo": "{count} {count, plural, one {month} other {months}} ago", "friendly_date.now": "Now", - "friendly_date.tomorrow": "Tomorrow", - "friendly_date.years": "in {count} {count, plural, one {year} other {years}}", - "friendly_date.yearsAgo": "{count} {count, plural, one {year} other {years}} ago", - "friendly_date.yesterday": "Yesterday", "gallery.copy_link.failed": "Failed to copy link to clipboard", "gallery.downloading": "Downloading...", "gallery.footer.channel_name": "Shared in {channelName}", diff --git a/index.ts b/index.ts index c94377789..27ac7b193 100644 --- a/index.ts +++ b/index.ts @@ -48,6 +48,7 @@ if (global.HermesInternal) { require('@formatjs/intl-datetimeformat/polyfill-force'); require('@formatjs/intl-datetimeformat/add-all-tz'); require('@formatjs/intl-listformat/polyfill-force'); + require('@formatjs/intl-relativetimeformat/polyfill-force'); } if (Platform.OS === 'android') { diff --git a/package-lock.json b/package-lock.json index 3d807b42e..3dca25b49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@formatjs/intl-locale": "4.2.11", "@formatjs/intl-numberformat": "8.15.4", "@formatjs/intl-pluralrules": "5.4.4", + "@formatjs/intl-relativetimeformat": "11.4.11", "@gorhom/bottom-sheet": "5.1.2", "@mattermost/calls": "github:mattermost/calls-common#ab53c24053b89e4d3d853bbe1244892899517f45", "@mattermost/compass-icons": "0.1.48", @@ -4219,6 +4220,17 @@ "tslib": "^2.8.0" } }, + "node_modules/@formatjs/intl-relativetimeformat": { + "version": "11.4.11", + "resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-11.4.11.tgz", + "integrity": "sha512-EiknGq2z8ZcIDUhf3kkizrPmHHdD0lO6B3OXG6u0o0lAvusSc9gkr33F2S/vzOHM9iTh6oHmzTl21klGsLR9LA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/intl-localematcher": "0.6.1", + "tslib": "^2.8.0" + } + }, "node_modules/@gorhom/bottom-sheet": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-5.1.2.tgz", diff --git a/package.json b/package.json index a0a3223c7..d0e219d39 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@formatjs/intl-locale": "4.2.11", "@formatjs/intl-numberformat": "8.15.4", "@formatjs/intl-pluralrules": "5.4.4", + "@formatjs/intl-relativetimeformat": "11.4.11", "@gorhom/bottom-sheet": "5.1.2", "@mattermost/calls": "github:mattermost/calls-common#ab53c24053b89e4d3d853bbe1244892899517f45", "@mattermost/compass-icons": "0.1.48",