diff --git a/README.md b/README.md index 3a855a9c3..3e514dc88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/R
+ alt="Day.js" />Fast 2kB alternative to Moment.js with the same modern API
-> Day.js는 Moment.js와 호환되는 대부분의 API를 사용하며, 최신 브라우저에서 날짜와 시간에 대한 구문 분석, 유효성 검사, 조작, 출력하는 경량 JavaScript 라이브러리입니다. Moment.js를 사용하고 있다면, Day.js는 껌입니다. +> Day.js는 대부분의 API가 Moment.js와 호환되며 최신 브라우저에서 날짜와 시간에 대한 구문 분석, 유효성 검사, 조작, 출력을 간편하게 처리하는 경량 JavaScript 라이브러리 입니다. Moment.js를 사용해본 경험이 있다면, Day.js도 쉽게 사용하실 수 있습니다. ```js dayjs() @@ -46,7 +46,7 @@ dayjs() ### 문서 -더 많은 세부 사항과 API, 그리고 다른 문서를 [day.js.org](https://day.js.org/) 웹사이트에서 볼 수 있습니다. +더 많은 세부 사항과 API 및 다른 문서는 [day.js.org](https://day.js.org/) 웹사이트에서 확인하실 수 있습니다. ### 설치 @@ -58,7 +58,7 @@ npm install dayjs --save ### API -Day.js API를 사용해서 날짜와 시간에 대한 구문 분석, 유효성 검사, 조작, 출력을 쉽게 할 수 있습니다. +Day.js API를 사용하여 날짜와 시간의 구문 분석, 검증, 조작, 출력을 간편하게 처리할 수 있습니다. ```javascript dayjs('2018-08-08') // parse @@ -78,9 +78,9 @@ dayjs().isBefore(dayjs()) // query ### I18n -Day.js는 국제화에 대해 많은 지원을 합니다. +Day.js는 국제화에 대한 많은 지원을 제공하고 있습니다. -그러나 그것을 사용하지 않는다면, 그 누구도 당신의 빌드에 포함되지 않습니다. +하지만 이 기능을 사용하지 않는 경우, 빌드에 포함되지 않습니다. ```javascript import 'dayjs/locale/es' // load on demand @@ -96,7 +96,7 @@ dayjs('2018-05-05') ### Plugin -플러그인은 기능을 확장하거나 새로운 기능을 추가하기 위해 Day.js에 추가할 수 있는 독립적인 모듈입니다. +플러그인은 Day.js의 기능을 확장하거나 새로운 기능을 도입하기 위한 독립적인 모듈입니다. ```javascript import advancedFormat from 'dayjs/plugin/advancedFormat' // load on demand diff --git a/src/index.js b/src/index.js index d26a401a6..061ade178 100644 --- a/src/index.js +++ b/src/index.js @@ -86,12 +86,12 @@ class Dayjs { constructor(cfg) { this.$L = parseLocale(cfg.locale, null, true) this.parse(cfg) // for plugin + this.$x = this.$x || cfg.x || {} this[IS_DAYJS] = true } parse(cfg) { this.$d = parseDate(cfg) - this.$x = cfg.x || {} this.init() } diff --git a/src/locale/ar.js b/src/locale/ar.js index a7025c442..f418379c8 100644 --- a/src/locale/ar.js +++ b/src/locale/ar.js @@ -2,6 +2,7 @@ import dayjs from 'dayjs' const months = 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_') + const symbolMap = { 1: '١', 2: '٢', @@ -36,6 +37,7 @@ const locale = { months, monthsShort: months, weekStart: 6, + meridiem: hour => (hour > 12 ? 'م' : 'ص'), relativeTime: { future: 'بعد %s', past: 'منذ %s', diff --git a/src/locale/fa.js b/src/locale/fa.js index cbcd13c1e..cf338279f 100644 --- a/src/locale/fa.js +++ b/src/locale/fa.js @@ -4,11 +4,11 @@ import dayjs from 'dayjs' const locale = { name: 'fa', weekdays: 'یکشنبه_دوشنبه_سهشنبه_چهارشنبه_پنجشنبه_جمعه_شنبه'.split('_'), - weekdaysShort: 'یک_دو_سه_چه_پن_جم_شن'.split('_'), + weekdaysShort: 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'), weekdaysMin: 'ی_د_س_چ_پ_ج_ش'.split('_'), weekStart: 6, - months: 'فروردین_اردیبهشت_خرداد_تیر_مرداد_شهریور_مهر_آبان_آذر_دی_بهمن_اسفند'.split('_'), - monthsShort: 'فرو_ارد_خرد_تیر_مرد_شهر_مهر_آبا_آذر_دی_بهم_اسف'.split('_'), + months: 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), + monthsShort: 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), ordinal: n => n, formats: { LT: 'HH:mm', @@ -20,7 +20,7 @@ const locale = { }, relativeTime: { future: 'در %s', - past: '%s قبل', + past: '%s پیش', s: 'چند ثانیه', m: 'یک دقیقه', mm: '%d دقیقه', diff --git a/src/locale/ko.js b/src/locale/ko.js index 8a8e8ea9b..7053e83f3 100644 --- a/src/locale/ko.js +++ b/src/locale/ko.js @@ -8,7 +8,7 @@ const locale = { weekdaysMin: '일_월_화_수_목_금_토'.split('_'), months: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), monthsShort: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), - ordinal: n => n, + ordinal: n => `${n}일`, formats: { LT: 'A h:mm', LTS: 'A h:mm:ss', diff --git a/src/locale/sl.js b/src/locale/sl.js index f09e3bfce..1e0e4f885 100644 --- a/src/locale/sl.js +++ b/src/locale/sl.js @@ -1,6 +1,71 @@ // Slovenian [sl] import dayjs from 'dayjs' +function dual(n) { + return (n % 100) == 2 // eslint-disable-line +} + +function threeFour(n) { + return (n % 100) == 3 || (n % 100) == 4 // eslint-disable-line +} + +/* eslint-disable */ +function translate(number, withoutSuffix, key, isFuture) { + const result = `${number} ` + switch (key) { + case 's': // a few seconds / in a few seconds / a few seconds ago + return (withoutSuffix || isFuture) ? 'nekaj sekund' : 'nekaj sekundami' + case 'm': // a minute / in a minute / a minute ago + return withoutSuffix ? 'ena minuta' : 'eno minuto' + case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago + if (dual(number)) { + return result + ((withoutSuffix || isFuture) ? 'minuti' : 'minutama') + } + if (threeFour(number)) { + return result + ((withoutSuffix || isFuture) ? 'minute' : 'minutami') + } + return result + ((withoutSuffix || isFuture) ? 'minut' : 'minutami') + case 'h': // an hour / in an hour / an hour ago + return withoutSuffix ? 'ena ura' : (isFuture ? 'eno uro' : 'eno uro') + case 'hh': // 9 hours / in 9 hours / 9 hours ago + if (dual(number)) { + return result + ((withoutSuffix || isFuture) ? 'uri' : 'urama') + } + if (threeFour(number)) { + return result + ((withoutSuffix || isFuture) ? 'ure' : 'urami') + } + return result + ((withoutSuffix || isFuture) ? 'ur' : 'urami') + case 'd': // a day / in a day / a day ago + return (withoutSuffix || isFuture) ? 'en dan' : 'enim dnem' + case 'dd': // 9 days / in 9 days / 9 days ago + if (dual(number)) { + return result + ((withoutSuffix || isFuture) ? 'dneva' : 'dnevoma') + } + return result + ((withoutSuffix || isFuture) ? 'dni' : 'dnevi') + case 'M': // a month / in a month / a month ago + return (withoutSuffix || isFuture) ? 'en mesec' : 'enim mesecem' + case 'MM': // 9 months / in 9 months / 9 months ago + if (dual(number)) { // 2 minutes / in 2 minutes + return result + ((withoutSuffix || isFuture) ? 'meseca' : 'mesecema') + } + if (threeFour(number)) { + return result + ((withoutSuffix || isFuture) ? 'mesece' : 'meseci') + } + return result + ((withoutSuffix || isFuture) ? 'mesecev' : 'meseci') + case 'y': // a year / in a year / a year ago + return (withoutSuffix || isFuture) ? 'eno leto' : 'enim letom' + case 'yy': // 9 years / in 9 years / 9 years ago + if (dual(number)) { // 2 minutes / in 2 minutes + return result + ((withoutSuffix || isFuture) ? 'leti' : 'letoma') + } + if (threeFour(number)) { + return result + ((withoutSuffix || isFuture) ? 'leta' : 'leti') + } + return result + ((withoutSuffix || isFuture) ? 'let' : 'leti') + } +} + +/* eslint-enable */ const locale = { name: 'sl', weekdays: 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'), @@ -16,26 +81,26 @@ const locale = { L: 'DD.MM.YYYY', LL: 'D. MMMM YYYY', LLL: 'D. MMMM YYYY H:mm', - LLLL: 'dddd, D. MMMM YYYY H:mm' + LLLL: 'dddd, D. MMMM YYYY H:mm', + l: 'D. M. YYYY' }, relativeTime: { future: 'čez %s', past: 'pred %s', - s: 'nekaj sekund', - m: 'minuta', - mm: '%d minut', - h: 'ura', - hh: '%d ur', - d: 'dan', - dd: '%d dni', - M: 'mesec', - MM: '%d mesecev', - y: 'leto', - yy: '%d let' + s: translate, + m: translate, + mm: translate, + h: translate, + hh: translate, + d: translate, + dd: translate, + M: translate, + MM: translate, + y: translate, + yy: translate } } dayjs.locale(locale, null, true) export default locale - diff --git a/src/locale/uz-latn.js b/src/locale/uz-latn.js index 220d5d44c..7d6021921 100644 --- a/src/locale/uz-latn.js +++ b/src/locale/uz-latn.js @@ -20,7 +20,7 @@ const locale = { }, relativeTime: { future: 'Yaqin %s ichida', - past: 'Bir necha %s oldin', + past: '%s oldin', s: 'soniya', m: 'bir daqiqa', mm: '%d daqiqa', diff --git a/src/locale/uz.js b/src/locale/uz.js index 23f4042eb..e705f68bd 100644 --- a/src/locale/uz.js +++ b/src/locale/uz.js @@ -20,7 +20,7 @@ const locale = { }, relativeTime: { future: 'Якин %s ичида', - past: 'Бир неча %s олдин', + past: '%s олдин', s: 'фурсат', m: 'бир дакика', mm: '%d дакика', diff --git a/src/plugin/timezone/index.js b/src/plugin/timezone/index.js index c8f8a4675..832fb4a73 100644 --- a/src/plugin/timezone/index.js +++ b/src/plugin/timezone/index.js @@ -97,7 +97,7 @@ export default (o, c, d) => { const date = this.toDate() const target = date.toLocaleString('en-US', { timeZone: timezone }) const diff = Math.round((date - new Date(target)) / 1000 / 60) - let ins = d(target).$set(MS, this.$ms) + let ins = d(target, { locale: this.$L }).$set(MS, this.$ms) .utcOffset((-Math.round(date.getTimezoneOffset() / 15) * 15) - diff, true) if (keepLocalTime) { const newOffset = ins.utcOffset() @@ -120,7 +120,7 @@ export default (o, c, d) => { return oldStartOf.call(this, units, startOf) } - const withoutTz = d(this.format('YYYY-MM-DD HH:mm:ss:SSS')) + const withoutTz = d(this.format('YYYY-MM-DD HH:mm:ss:SSS'), { locale: this.$L }) const startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf) return startOfWithoutTz.tz(this.$x.$timezone, true) } diff --git a/test/locale/ar.test.js b/test/locale/ar.test.js index 3f9f60f0c..2b5a57d29 100644 --- a/test/locale/ar.test.js +++ b/test/locale/ar.test.js @@ -50,3 +50,13 @@ it('RelativeTime: Time from X gets formatted', () => { .toBe(t[2]) }) }) + +it('Format meridiem with locale function', () => { + for (let i = 0; i <= 23; i += 1) { + const hour = dayjs() + .startOf('day') + .add(i, 'hour') + const meridiem = i > 12 ? 'م' : 'ص' + expect(hour.locale('ar').format('A')).toBe(`${meridiem}`) + } +}) diff --git a/test/locale/sl.test.js b/test/locale/sl.test.js new file mode 100644 index 000000000..672d6064b --- /dev/null +++ b/test/locale/sl.test.js @@ -0,0 +1,82 @@ +import MockDate from 'mockdate' +import dayjs from '../../src' +import relativeTime from '../../src/plugin/relativeTime' +import '../../src/locale/sl' + +dayjs.extend(relativeTime) + +beforeEach(() => { + MockDate.set(new Date()) +}) + +afterEach(() => { + MockDate.reset() +}) + +it('Slovenian locale relative time in past and future', () => { + const cases = [ + [1, 's', 'čez nekaj sekund', 'nekaj sekund'], + [-1, 's', 'pred nekaj sekundami', 'nekaj sekund'], + [1, 'm', 'čez eno minuto', 'ena minuta'], + [-1, 'm', 'pred eno minuto', 'ena minuta'], + [2, 'm', 'čez 2 minuti', '2 minuti'], + [-2, 'm', 'pred 2 minutama', '2 minuti'], + [3, 'm', 'čez 3 minute', '3 minute'], + [-3, 'm', 'pred 3 minutami', '3 minute'], + [5, 'm', 'čez 5 minut', '5 minut'], + [-5, 'm', 'pred 5 minutami', '5 minut'], + [1, 'h', 'čez eno uro', 'ena ura'], + [-1, 'h', 'pred eno uro', 'ena ura'], + [2, 'h', 'čez 2 uri', '2 uri'], + [-2, 'h', 'pred 2 urama', '2 uri'], + [3, 'h', 'čez 3 ure', '3 ure'], + [-3, 'h', 'pred 3 urami', '3 ure'], + [5, 'h', 'čez 5 ur', '5 ur'], + [-5, 'h', 'pred 5 urami', '5 ur'], + [1, 'd', 'čez en dan', 'en dan'], + [-1, 'd', 'pred enim dnem', 'en dan'], + [2, 'd', 'čez 2 dneva', '2 dneva'], + [-2, 'd', 'pred 2 dnevoma', '2 dneva'], + [3, 'd', 'čez 3 dni', '3 dni'], + [-3, 'd', 'pred 3 dnevi', '3 dni'], + [5, 'd', 'čez 5 dni', '5 dni'], + [-5, 'd', 'pred 5 dnevi', '5 dni'], + [1, 'M', 'čez en mesec', 'en mesec'], + [-1, 'M', 'pred enim mesecem', 'en mesec'], + [2, 'M', 'čez 2 meseca', '2 meseca'], + [-2, 'M', 'pred 2 mesecema', '2 meseca'], + [3, 'M', 'čez 3 mesece', '3 mesece'], + [-3, 'M', 'pred 3 meseci', '3 mesece'], + [5, 'M', 'čez 5 mesecev', '5 mesecev'], + [-5, 'M', 'pred 5 meseci', '5 mesecev'], + [1, 'y', 'čez eno leto', 'eno leto'], + [-1, 'y', 'pred enim letom', 'eno leto'], + [2, 'y', 'čez 2 leti', '2 leti'], + [-2, 'y', 'pred 2 letoma', '2 leti'], + [3, 'y', 'čez 3 leta', '3 leta'], + [-3, 'y', 'pred 3 leti', '3 leta'], + [5, 'y', 'čez 5 let', '5 let'], + [-5, 'y', 'pred 5 leti', '5 let'] + // these are rounded + // if user decides to change rounding then it would be good to test them also + // [102, 's', 'čez 102 sekundi', '102 sekundi'], + // [-102, 's', 'pred 102 sekundama', '102 sekundi'], + // [103, 's', 'čez 103 sekunde', '103 sekunde'], + // [-103, 's', 'pred 103 sekundami', '103 sekunde'], + // [114, 's', 'čez 114 sekund', '114 sekund'], + // [-114, 's', 'pred 114 sekundami', '114 sekund'], + // [-102, 'm', 'čez 102 minuti', '102 minuti'], + // [-102, 'm', 'pred 102 minutama', '102 minuti'], + // [103, 'm', 'čez 103 minute', '103 minute'], + // [-103, 'm', 'pred 103 minutami', '103 minute'], + // [114, 'm', 'čez 114 minut', '114 minut'], + // [-114, 'm', 'pred 114 minutami', '114 minut'] + ] + + cases.forEach((c) => { + // With suffix + expect(dayjs().add(c[0], c[1]).locale('sl').fromNow()).toBe(c[2]) + // Without suffix + expect(dayjs().add(c[0], c[1]).locale('sl').fromNow(true)).toBe(c[3]) + }) +}) diff --git a/test/plugin/timezone.test.js b/test/plugin/timezone.test.js index 2b28cc309..c4529c6c8 100644 --- a/test/plugin/timezone.test.js +++ b/test/plugin/timezone.test.js @@ -318,4 +318,15 @@ describe('startOf and endOf', () => { const endOfDay = originalDay.endOf('day') expect(endOfDay.valueOf()).toEqual(originalDay.valueOf()) }) + + it('preserves locality when tz is called', () => { + const tzWithoutLocality = dayjs.tz('2023-02-17 00:00:00', NY) + const tzWithLocality = dayjs.tz('2023-02-17 00:00:00', NY).locale({ + name: 'locale_test', + weekStart: 3 + }) + + expect(tzWithoutLocality.startOf('week').format('YYYY-MM-DD')).toEqual('2023-02-12') + expect(tzWithLocality.startOf('week').format('YYYY-MM-DD')).toEqual('2023-02-15') + }) })