Skip to content

Commit

Permalink
fix: Update RelativeTime plugin to support function to make additiona…
Browse files Browse the repository at this point in the history
…l processing (#767)

* fix: Update RelativeTime plugin to support function to make additional processing

* chore update fix

* fix: Update ru && uk locale file to support relativeTime with plural
  • Loading branch information
andrewhood125ruhuc committed Jul 3, 2027
1 parent a08bf59 commit 558b90e
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 16 deletions.
32 changes: 26 additions & 6 deletions src/locale/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ const monthShortFormat = 'янв._февр._мар._апр._мая_июня_ию
const monthShortStandalone = 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')

const MONTHS_IN_FORMAT = /D[oD]?(\[[^[\]]*\]|\s)+MMMM?/

function plural(word, num) {
const forms = word.split('_')
return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]) // eslint-disable-line
}
function relativeTimeWithPlural(number, withoutSuffix, key) {
const format = {
mm: withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
hh: 'час_часа_часов',
dd: 'день_дня_дней',
MM: 'месяц_месяца_месяцев',
yy: 'год_года_лет'
}
if (key === 'm') {
return withoutSuffix ? 'минута' : 'минуту'
}

return `${number} ${plural(format[key], +number)}`
}

const locale = {
name: 'ru',
weekdays: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
Expand Down Expand Up @@ -37,16 +57,16 @@ const locale = {
future: 'через %s',
past: '%s назад',
s: 'несколько секунд',
m: 'минута',
mm: '%d минут',
m: relativeTimeWithPlural,
mm: relativeTimeWithPlural,
h: 'час',
hh: '%d часов',
hh: relativeTimeWithPlural,
d: 'день',
dd: '%d дней',
dd: relativeTimeWithPlural,
M: 'месяц',
MM: '%d месяцев',
MM: relativeTimeWithPlural,
y: 'год',
yy: '%d лет'
yy: relativeTimeWithPlural
},
ordinal: n => n
}
Expand Down
36 changes: 28 additions & 8 deletions src/locale/uk.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import dayjs from 'dayjs'

function plural(word, num) {
const forms = word.split('_')
return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]) // eslint-disable-line
}
function relativeTimeWithPlural(number, withoutSuffix, key) {
const format = {
ss: withoutSuffix ? 'секунда_секунди_секунд' : 'секунду_секунди_секунд',
mm: withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
hh: withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
dd: 'день_дні_днів',
MM: 'місяць_місяці_місяців',
yy: 'рік_роки_років'
}
if (key === 'm') {
return withoutSuffix ? 'хвилина' : 'хвилину'
}

return `${number} ${plural(format[key], +number)}`
}

const locale = {
name: 'uk',
weekdays: 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
Expand All @@ -9,19 +29,19 @@ const locale = {
monthsShort: 'сiч_лют_бер_квiт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
weekStart: 1,
relativeTime: {
future: 'через %s',
future: 'за %s',
past: '%s тому',
s: 'декілька секунд',
m: 'хвилина',
mm: '%d хвилин',
h: 'година',
hh: '%d годин',
m: relativeTimeWithPlural,
mm: relativeTimeWithPlural,
h: 'годину',
hh: relativeTimeWithPlural,
d: 'день',
dd: '%d днів',
dd: relativeTimeWithPlural,
M: 'місяць',
MM: '%d місяців',
MM: relativeTimeWithPlural,
y: 'рік',
yy: '%d роки'
yy: relativeTimeWithPlural
},
ordinal: n => n,
formats: {
Expand Down
11 changes: 9 additions & 2 deletions src/plugin/relativeTime/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default (o, c, d) => {
const Tl = T.length
let result
let out
let isFuture

for (let i = 0; i < Tl; i += 1) {
let t = T[i]
Expand All @@ -44,14 +45,20 @@ export default (o, c, d) => {
: instance.diff(input, t.d, true)
}
const abs = Math.round(Math.abs(result))
isFuture = result > 0
if (abs <= t.r || !t.r) {
if (abs === 1 && i > 0) t = T[i - 1] // 1 minutes -> a minute
out = loc[t.l].replace('%d', abs)
const format = loc[t.l]
if (typeof format === 'string') {
out = format.replace('%d', abs)
} else {
out = format(abs, withoutSuffix, t.l, isFuture)
}
break
}
}
if (withoutSuffix) return out
return ((result > 0) ? loc.future : loc.past).replace('%s', out)
return (isFuture ? loc.future : loc.past).replace('%s', out)
}
proto.to = function (input, withoutSuffix) {
return fromTo(input, withoutSuffix, this, true)
Expand Down
24 changes: 24 additions & 0 deletions test/locale/ru.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import moment from 'moment'
import MockDate from 'mockdate'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import '../../src/locale/ru'

dayjs.extend(relativeTime)

beforeEach(() => {
MockDate.set(new Date())
})
Expand All @@ -23,3 +26,24 @@ it('Format Month with locale function', () => {
expect(dayjsRU.format(testFormat3)).toEqual(momentRU.format(testFormat3))
}
})

it('RelativeTime: Time from X', () => {
const T = [
[44.4, 'second'], // a few seconds
[89.5, 'second'], // a minute
[43, 'minute'], // 44 minutes
[21, 'hour'], // 21 hours
[25, 'day'], // 25 days
[10, 'month'], // 2 month
[18, 'month'] // 2 years
]

T.forEach((t) => {
dayjs.locale('ru')
moment.locale('ru')
expect(dayjs().from(dayjs().add(t[0], t[1])))
.toBe(moment().from(moment().add(t[0], t[1])))
expect(dayjs().from(dayjs().add(t[0], t[1]), true))
.toBe(moment().from(moment().add(t[0], t[1]), true))
})
})
36 changes: 36 additions & 0 deletions test/locale/uk.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import moment from 'moment'
import MockDate from 'mockdate'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import '../../src/locale/uk'

dayjs.extend(relativeTime)

beforeEach(() => {
MockDate.set(new Date())
})

afterEach(() => {
MockDate.reset()
})

it('RelativeTime: Time from X', () => {
const T = [
[44.4, 'second'], // a few seconds
[89.5, 'second'], // a minute
[43, 'minute'], // 44 minutes
[21, 'hour'], // 21 hours
[25, 'day'], // 25 days
[10, 'month'], // 2 month
[18, 'month'] // 2 years
]

T.forEach((t) => {
dayjs.locale('uk')
moment.locale('uk')
expect(dayjs().from(dayjs().add(t[0], t[1])))
.toBe(moment().from(moment().add(t[0], t[1])))
expect(dayjs().from(dayjs().add(t[0], t[1]), true))
.toBe(moment().from(moment().add(t[0], t[1]), true))
})
})
10 changes: 10 additions & 0 deletions test/plugin/relativeTime.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import moment from 'moment'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import utc from '../../src/plugin/utc'
import '../../src/locale/ru'

dayjs.extend(relativeTime)

Expand Down Expand Up @@ -83,6 +84,15 @@ it('Time to X', () => {
expect(dayjs().to(dayjs().subtract(3, 'year'))).toBe(moment().to(moment().subtract(3, 'year')))
})

it('Locale Fonction', () => {
// e.g. in ru locale, m: x minute require additional processing
// and provides as a function instead of a string
const str0 = '2020-01-06 15:53:00'
const str = '2020-01-06 15:52:15'
const result = dayjs(str0).locale('ru').to(str)
expect(result).toEqual(expect.any(String))
})

// https://github.com/iamkun/dayjs/issues/646
it('Time from now with UTC', () => {
dayjs.extend(utc)
Expand Down

0 comments on commit 558b90e

Please sign in to comment.