Skip to content

Commit

Permalink
fix: fix Serbian locale grammar (sr, sr-cyrl) (#1108)
Browse files Browse the repository at this point in the history
  • Loading branch information
dusansimic authored Oct 13, 2020
1 parent be505c2 commit cc87eff
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 30 deletions.
66 changes: 51 additions & 15 deletions src/locale/sr-cyrl.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
// Serbian Cyrillic [sr-cyrl]
import dayjs from 'dayjs'

const translator = {
words: {
m: ['један минут', 'једног минута'],
mm: ['%d минут', '%d минута', '%d минута'],
h: ['један сат', 'једног сата'],
hh: ['%d сат', '%d сата', '%d сати'],
d: ['један дан', 'једног дана'],
dd: ['%d дан', '%d дана', '%d дана'],
M: ['један месец', 'једног месеца'],
MM: ['%d месец', '%d месеца', '%d месеци'],
y: ['једну годину', 'једне године'],
yy: ['%d годину', '%d године', '%d година']
},
correctGrammarCase(number, wordKey) {
if (number % 10 >= 1 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20)) {
return number % 10 === 1 ? wordKey[0] : wordKey[1]
}
return wordKey[2]
},
relativeTimeFormatter(number, withoutSuffix, key, isFuture) {
const wordKey = translator.words[key]

if (key.length === 1) {
// Nominativ
if (key === 'y' && withoutSuffix) return 'једна година'
return isFuture || withoutSuffix ? wordKey[0] : wordKey[1]
}

const word = translator.correctGrammarCase(number, wordKey)
// Nominativ
if (key === 'yy' && withoutSuffix && word === '%d годину') return `${number} година`

return word.replace('%d', number)
}
}

const locale = {
name: 'sr-cyrl',
weekdays: 'Недеља_Понедељак_Уторак_Среда_Четвртак_Петак_Субота'.split('_'),
Expand All @@ -12,26 +48,26 @@ const locale = {
relativeTime: {
future: 'за %s',
past: 'пре %s',
s: 'секунда',
m: 'минут',
mm: '%d минута',
h: 'сат',
hh: '%d сати',
d: 'дан',
dd: '%d дана',
M: 'месец',
MM: '%d месеци',
y: 'година',
yy: '%d године'
s: 'неколико секунди',
m: translator.relativeTimeFormatter,
mm: translator.relativeTimeFormatter,
h: translator.relativeTimeFormatter,
hh: translator.relativeTimeFormatter,
d: translator.relativeTimeFormatter,
dd: translator.relativeTimeFormatter,
M: translator.relativeTimeFormatter,
MM: translator.relativeTimeFormatter,
y: translator.relativeTimeFormatter,
yy: translator.relativeTimeFormatter
},
ordinal: n => `${n}.`,
formats: {
LT: 'H:mm',
LTS: 'H:mm:ss',
L: 'DD.MM.YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY H:mm',
LLLL: 'dddd, D. MMMM YYYY H:mm'
L: 'D. M. YYYY.',
LL: 'D. MMMM YYYY.',
LLL: 'D. MMMM YYYY. H:mm',
LLLL: 'dddd, D. MMMM YYYY. H:mm'
}
}

Expand Down
66 changes: 51 additions & 15 deletions src/locale/sr.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
// Serbian [sr]
import dayjs from 'dayjs'

const translator = {
words: {
m: ['jedan minut', 'jednog minuta'],
mm: ['%d minut', '%d minuta', '%d minuta'],
h: ['jedan sat', 'jednog sata'],
hh: ['%d sat', '%d sata', '%d sati'],
d: ['jedan dan', 'jednog dana'],
dd: ['%d dan', '%d dana', '%d dana'],
M: ['jedan mesec', 'jednog meseca'],
MM: ['%d mesec', '%d meseca', '%d meseci'],
y: ['jednu godinu', 'jedne godine'],
yy: ['%d godinu', '%d godine', '%d godina']
},
correctGrammarCase(number, wordKey) {
if (number % 10 >= 1 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20)) {
return number % 10 === 1 ? wordKey[0] : wordKey[1]
}
return wordKey[2]
},
relativeTimeFormatter(number, withoutSuffix, key, isFuture) {
const wordKey = translator.words[key]

if (key.length === 1) {
// Nominativ
if (key === 'y' && withoutSuffix) return 'jedna godina'
return isFuture || withoutSuffix ? wordKey[0] : wordKey[1]
}

const word = translator.correctGrammarCase(number, wordKey)
// Nominativ
if (key === 'yy' && withoutSuffix && word === '%d godinu') return `${number} godina`

return word.replace('%d', number)
}
}

const locale = {
name: 'sr',
weekdays: 'Nedelja_Ponedeljak_Utorak_Sreda_Četvrtak_Petak_Subota'.split('_'),
Expand All @@ -12,26 +48,26 @@ const locale = {
relativeTime: {
future: 'za %s',
past: 'pre %s',
s: 'sekunda',
m: 'minut',
mm: '%d minuta',
h: 'sat',
hh: '%d sati',
d: 'dan',
dd: '%d dana',
M: 'mesec',
MM: '%d meseci',
y: 'godina',
yy: '%d godine'
s: 'nekoliko sekundi',
m: translator.relativeTimeFormatter,
mm: translator.relativeTimeFormatter,
h: translator.relativeTimeFormatter,
hh: translator.relativeTimeFormatter,
d: translator.relativeTimeFormatter,
dd: translator.relativeTimeFormatter,
M: translator.relativeTimeFormatter,
MM: translator.relativeTimeFormatter,
y: translator.relativeTimeFormatter,
yy: translator.relativeTimeFormatter
},
ordinal: n => `${n}.`,
formats: {
LT: 'H:mm',
LTS: 'H:mm:ss',
L: 'DD.MM.YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY H:mm',
LLLL: 'dddd, D. MMMM YYYY H:mm'
L: 'D. M. YYYY.',
LL: 'D. MMMM YYYY.',
LLL: 'D. MMMM YYYY. H:mm',
LLLL: 'dddd, D. MMMM YYYY. H:mm'
}
}

Expand Down
54 changes: 54 additions & 0 deletions test/locale/sr-cyrl.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import MockDate from 'mockdate'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import '../../src/locale/sr-cyrl'

dayjs.extend(relativeTime)

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

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

it('Serbian cyrillic locale relative time in past and future', () => {
const cases = [
[1, 's', 'за неколико секунди', 'неколико секунди'],
[-1, 's', 'пре неколико секунди', 'неколико секунди'],
[4, 's', 'за неколико секунди', 'неколико секунди'],
[1, 'm', 'за један минут', 'један минут'],
[-1, 'm', 'пре једног минута', 'један минут'],
[4, 'm', 'за 4 минута', '4 минута'],
[5, 'm', 'за 5 минута', '5 минута'],
[21, 'm', 'за 21 минут', '21 минут'],
[1, 'h', 'за један сат', 'један сат'],
[-1, 'h', 'пре једног сата', 'један сат'],
[4, 'h', 'за 4 сата', '4 сата'],
[5, 'h', 'за 5 сати', '5 сати'],
[21, 'h', 'за 21 сат', '21 сат'],
[1, 'd', 'за један дан', 'један дан'],
[-1, 'd', 'пре једног дана', 'један дан'],
[4, 'd', 'за 4 дана', '4 дана'],
[5, 'd', 'за 5 дана', '5 дана'],
[21, 'd', 'за 21 дан', '21 дан'],
[1, 'M', 'за један месец', 'један месец'],
[-1, 'M', 'пре једног месеца', 'један месец'],
[4, 'M', 'за 4 месеца', '4 месеца'],
[5, 'M', 'за 5 месеци', '5 месеци'],
[10, 'M', 'за 10 месеци', '10 месеци'],
[1, 'y', 'за једну годину', 'једна година'],
[-1, 'y', 'пре једне године', 'једна година'],
[4, 'y', 'за 4 године', '4 године'],
[5, 'y', 'за 5 година', '5 година'],
[21, 'y', 'за 21 годину', '21 година']
]

cases.forEach((c) => {
expect(dayjs().add(c[0], c[1]).locale('sr-cyrl').fromNow()).toBe(c[2])
expect(dayjs().add(c[0], c[1]).locale('sr-cyrl').fromNow(true)).toBe(c[3])
// TODO: compare to momentjs once logic and grammar are fixed there
})
})

55 changes: 55 additions & 0 deletions test/locale/sr.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import MockDate from 'mockdate'
import dayjs from '../../src'
import relativeTime from '../../src/plugin/relativeTime'
import '../../src/locale/sr'

dayjs.extend(relativeTime)

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

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

it('Serbian locale relative time in past and future', () => {
const cases = [
[1, 's', 'za nekoliko sekundi', 'nekoliko sekundi'],
[-1, 's', 'pre nekoliko sekundi', 'nekoliko sekundi'],
[4, 's', 'za nekoliko sekundi', 'nekoliko sekundi'],
[1, 'm', 'za jedan minut', 'jedan minut'],
[-1, 'm', 'pre jednog minuta', 'jedan minut'],
[4, 'm', 'za 4 minuta', '4 minuta'],
[5, 'm', 'za 5 minuta', '5 minuta'],
[21, 'm', 'za 21 minut', '21 minut'],
[1, 'h', 'za jedan sat', 'jedan sat'],
[-1, 'h', 'pre jednog sata', 'jedan sat'],
[4, 'h', 'za 4 sata', '4 sata'],
[5, 'h', 'za 5 sati', '5 sati'],
[21, 'h', 'za 21 sat', '21 sat'],
[1, 'd', 'za jedan dan', 'jedan dan'],
[-1, 'd', 'pre jednog dana', 'jedan dan'],
[4, 'd', 'za 4 dana', '4 dana'],
[5, 'd', 'za 5 dana', '5 dana'],
[21, 'd', 'za 21 dan', '21 dan'],
[1, 'M', 'za jedan mesec', 'jedan mesec'],
[-1, 'M', 'pre jednog meseca', 'jedan mesec'],
[4, 'M', 'za 4 meseca', '4 meseca'],
[5, 'M', 'za 5 meseci', '5 meseci'],
[10, 'M', 'za 10 meseci', '10 meseci'],
[1, 'y', 'za jednu godinu', 'jedna godina'],
[-1, 'y', 'pre jedne godine', 'jedna godina'],
[4, 'y', 'za 4 godine', '4 godine'],
[5, 'y', 'za 5 godina', '5 godina'],
[21, 'y', 'za 21 godinu', '21 godina']
]

cases.forEach((c) => {
// With suffix
expect(dayjs().add(c[0], c[1]).locale('sr').fromNow()).toBe(c[2])
// Without suffix
expect(dayjs().add(c[0], c[1]).locale('sr').fromNow(true)).toBe(c[3])
// TODO: compare to momentjs once logic and grammar are fixed there
})
})

0 comments on commit cc87eff

Please sign in to comment.