Repository: iamkun/dayjs
Pull request #2409 (2023-08-11 14:20:01)

fix(docs): update image tag and formatting 
Hello 👋 @iamkun Thank you for sharing such a great library.

we had a problem with the doc generating for one of our packages used the packages due to `Expected corresponding JSX closing tag for <img>` at readme. also the PR has some polish in the formatting markdown 

jamiehaywood: relates #2343 
moelzanaty3: Hi @awallace, I understand that you have a busy schedule, and I truly appreciate your time and expertise. I wanted to bring to your attention a minor fix that I've submitted as a pull request (PR) to your package.

The reason for reaching out is that this fix is currently causing our project's pipeline to fail, and getting it merged would greatly help unblock our progress. I understand the importance of maintaining the stability and quality of the package, and I believe that this fix aligns with those goals.

Patch:
diff --git a/README.md b/README.md
index 3a855a9..3e514dc 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/R
 
 <p align="center"><a href="https://day.js.org/" target="_blank" rel="noopener noreferrer"><img width="550"
                                                                              src="https://user-images.githubusercontent.com/17680888/39081119-3057bbe2-456e-11e8-862c-646133ad4b43.png"
-                                                                             alt="Day.js"></a></p>
+                                                                             alt="Day.js" /></a></p>
 <p align="center">Fast <b>2kB</b> alternative to Moment.js with the same modern API</p>
 <p align="center">
     <a href="https://unpkg.com/dayjs/dayjs.min.js"><img
@@ -41,7 +41,7 @@ dayjs().startOf('month').add(1, 'day').set('year', 2018).format('YYYY-MM-DD HH:m
 
 ### Documentation
 
-You can find for more details, API, and other docs on [day.js.org](https://day.js.org/) website.
+You can find more details, API, and other docs on [day.js.org](https://day.js.org/) website.
 
 ### Installation
 
@@ -82,6 +82,7 @@ dayjs.locale('es') // use Spanish locale globally
 
 dayjs('2018-05-05').locale('zh-cn').format() // use Chinese Simplified locale in a specific instance
 ```
+
 📚[Internationalization](https://day.js.org/docs/en/i18n/i18n)
 
 ### Plugin
@@ -100,7 +101,7 @@ dayjs().format('Q Do k kk X x') // more available formats
 
 ## Sponsors
 
-Support this project by becoming a sponsor. Your logo will show up here with a link to your website. 
+Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
 
 [[Become a sponsor via Github](https://github.com/sponsors/iamkun/)] [[Become a sponsor via OpenCollective](https://opencollective.com/dayjs#sponsor)]
 
diff --git a/docs/ko/README-ko.md b/docs/ko/README-ko.md
index 4389cc3..cb1f77a 100644
--- a/docs/ko/README-ko.md
+++ b/docs/ko/README-ko.md
@@ -23,7 +23,7 @@
     </a>
 </p>
 
-> 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/locale/ar.js b/src/locale/ar.js
index a7025c4..f418379 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 cbcd13c..cf33827 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 8a8e8ea..7053e83 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 f09e3bf..1e0e4f8 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
-


Test patch:
diff --git a/test/locale/ar.test.js b/test/locale/ar.test.js
index 3f9f60f..2b5a57d 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 0000000..672d606
--- /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])
+  })
+})