Skip to content

Commit 4bd9250

Browse files
authored
fix: Update RelativeTime plugin to support function to make additional 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
1 parent 82ce2ba commit 4bd9250

File tree

6 files changed

+133
-16
lines changed

6 files changed

+133
-16
lines changed

src/locale/ru.js

+26-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,26 @@ const monthShortFormat = 'янв._февр._мар._апр._мая_июня_ию
77
const monthShortStandalone = 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_')
88

99
const MONTHS_IN_FORMAT = /D[oD]?(\[[^[\]]*\]|\s)+MMMM?/
10+
11+
function plural(word, num) {
12+
const forms = word.split('_')
13+
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
14+
}
15+
function relativeTimeWithPlural(number, withoutSuffix, key) {
16+
const format = {
17+
mm: withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
18+
hh: 'час_часа_часов',
19+
dd: 'день_дня_дней',
20+
MM: 'месяц_месяца_месяцев',
21+
yy: 'год_года_лет'
22+
}
23+
if (key === 'm') {
24+
return withoutSuffix ? 'минута' : 'минуту'
25+
}
26+
27+
return `${number} ${plural(format[key], +number)}`
28+
}
29+
1030
const locale = {
1131
name: 'ru',
1232
weekdays: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
@@ -37,16 +57,16 @@ const locale = {
3757
future: 'через %s',
3858
past: '%s назад',
3959
s: 'несколько секунд',
40-
m: 'минута',
41-
mm: '%d минут',
60+
m: relativeTimeWithPlural,
61+
mm: relativeTimeWithPlural,
4262
h: 'час',
43-
hh: '%d часов',
63+
hh: relativeTimeWithPlural,
4464
d: 'день',
45-
dd: '%d дней',
65+
dd: relativeTimeWithPlural,
4666
M: 'месяц',
47-
MM: '%d месяцев',
67+
MM: relativeTimeWithPlural,
4868
y: 'год',
49-
yy: '%d лет'
69+
yy: relativeTimeWithPlural
5070
},
5171
ordinal: n => n
5272
}

src/locale/uk.js

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
import dayjs from 'dayjs'
22

3+
function plural(word, num) {
4+
const forms = word.split('_')
5+
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
6+
}
7+
function relativeTimeWithPlural(number, withoutSuffix, key) {
8+
const format = {
9+
ss: withoutSuffix ? 'секунда_секунди_секунд' : 'секунду_секунди_секунд',
10+
mm: withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин',
11+
hh: withoutSuffix ? 'година_години_годин' : 'годину_години_годин',
12+
dd: 'день_дні_днів',
13+
MM: 'місяць_місяці_місяців',
14+
yy: 'рік_роки_років'
15+
}
16+
if (key === 'm') {
17+
return withoutSuffix ? 'хвилина' : 'хвилину'
18+
}
19+
20+
return `${number} ${plural(format[key], +number)}`
21+
}
22+
323
const locale = {
424
name: 'uk',
525
weekdays: 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),
@@ -9,19 +29,19 @@ const locale = {
929
monthsShort: 'сiч_лют_бер_квiт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),
1030
weekStart: 1,
1131
relativeTime: {
12-
future: 'через %s',
32+
future: 'за %s',
1333
past: '%s тому',
1434
s: 'декілька секунд',
15-
m: 'хвилина',
16-
mm: '%d хвилин',
17-
h: 'година',
18-
hh: '%d годин',
35+
m: relativeTimeWithPlural,
36+
mm: relativeTimeWithPlural,
37+
h: 'годину',
38+
hh: relativeTimeWithPlural,
1939
d: 'день',
20-
dd: '%d днів',
40+
dd: relativeTimeWithPlural,
2141
M: 'місяць',
22-
MM: '%d місяців',
42+
MM: relativeTimeWithPlural,
2343
y: 'рік',
24-
yy: '%d роки'
44+
yy: relativeTimeWithPlural
2545
},
2646
ordinal: n => n,
2747
formats: {

src/plugin/relativeTime/index.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default (o, c, d) => {
3535
const Tl = T.length
3636
let result
3737
let out
38+
let isFuture
3839

3940
for (let i = 0; i < Tl; i += 1) {
4041
let t = T[i]
@@ -44,14 +45,20 @@ export default (o, c, d) => {
4445
: instance.diff(input, t.d, true)
4546
}
4647
const abs = Math.round(Math.abs(result))
48+
isFuture = result > 0
4749
if (abs <= t.r || !t.r) {
4850
if (abs === 1 && i > 0) t = T[i - 1] // 1 minutes -> a minute
49-
out = loc[t.l].replace('%d', abs)
51+
const format = loc[t.l]
52+
if (typeof format === 'string') {
53+
out = format.replace('%d', abs)
54+
} else {
55+
out = format(abs, withoutSuffix, t.l, isFuture)
56+
}
5057
break
5158
}
5259
}
5360
if (withoutSuffix) return out
54-
return ((result > 0) ? loc.future : loc.past).replace('%s', out)
61+
return (isFuture ? loc.future : loc.past).replace('%s', out)
5562
}
5663
proto.to = function (input, withoutSuffix) {
5764
return fromTo(input, withoutSuffix, this, true)

test/locale/ru.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import moment from 'moment'
22
import MockDate from 'mockdate'
33
import dayjs from '../../src'
4+
import relativeTime from '../../src/plugin/relativeTime'
45
import '../../src/locale/ru'
56

7+
dayjs.extend(relativeTime)
8+
69
beforeEach(() => {
710
MockDate.set(new Date())
811
})
@@ -23,3 +26,24 @@ it('Format Month with locale function', () => {
2326
expect(dayjsRU.format(testFormat3)).toEqual(momentRU.format(testFormat3))
2427
}
2528
})
29+
30+
it('RelativeTime: Time from X', () => {
31+
const T = [
32+
[44.4, 'second'], // a few seconds
33+
[89.5, 'second'], // a minute
34+
[43, 'minute'], // 44 minutes
35+
[21, 'hour'], // 21 hours
36+
[25, 'day'], // 25 days
37+
[10, 'month'], // 2 month
38+
[18, 'month'] // 2 years
39+
]
40+
41+
T.forEach((t) => {
42+
dayjs.locale('ru')
43+
moment.locale('ru')
44+
expect(dayjs().from(dayjs().add(t[0], t[1])))
45+
.toBe(moment().from(moment().add(t[0], t[1])))
46+
expect(dayjs().from(dayjs().add(t[0], t[1]), true))
47+
.toBe(moment().from(moment().add(t[0], t[1]), true))
48+
})
49+
})

test/locale/uk.test.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import moment from 'moment'
2+
import MockDate from 'mockdate'
3+
import dayjs from '../../src'
4+
import relativeTime from '../../src/plugin/relativeTime'
5+
import '../../src/locale/uk'
6+
7+
dayjs.extend(relativeTime)
8+
9+
beforeEach(() => {
10+
MockDate.set(new Date())
11+
})
12+
13+
afterEach(() => {
14+
MockDate.reset()
15+
})
16+
17+
it('RelativeTime: Time from X', () => {
18+
const T = [
19+
[44.4, 'second'], // a few seconds
20+
[89.5, 'second'], // a minute
21+
[43, 'minute'], // 44 minutes
22+
[21, 'hour'], // 21 hours
23+
[25, 'day'], // 25 days
24+
[10, 'month'], // 2 month
25+
[18, 'month'] // 2 years
26+
]
27+
28+
T.forEach((t) => {
29+
dayjs.locale('uk')
30+
moment.locale('uk')
31+
expect(dayjs().from(dayjs().add(t[0], t[1])))
32+
.toBe(moment().from(moment().add(t[0], t[1])))
33+
expect(dayjs().from(dayjs().add(t[0], t[1]), true))
34+
.toBe(moment().from(moment().add(t[0], t[1]), true))
35+
})
36+
})

test/plugin/relativeTime.test.js

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import moment from 'moment'
33
import dayjs from '../../src'
44
import relativeTime from '../../src/plugin/relativeTime'
55
import utc from '../../src/plugin/utc'
6+
import '../../src/locale/ru'
67

78
dayjs.extend(relativeTime)
89

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

87+
it('Locale Fonction', () => {
88+
// e.g. in ru locale, m: x minute require additional processing
89+
// and provides as a function instead of a string
90+
const str0 = '2020-01-06 15:53:00'
91+
const str = '2020-01-06 15:52:15'
92+
const result = dayjs(str0).locale('ru').to(str)
93+
expect(result).toEqual(expect.any(String))
94+
})
95+
8696
// https://github.com/iamkun/dayjs/issues/646
8797
it('Time from now with UTC', () => {
8898
dayjs.extend(utc)

0 commit comments

Comments
 (0)