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

fix: Serbian locale grammar (sr, sr-cyrl) #1108

Merged
merged 4 commits into from
Oct 13, 2020
Merged
Show file tree
Hide file tree
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
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
})
})