Repository: crsmithdev/arrow
Pull request #804 (2020-06-09 08:41:33)

Add week timeframe to Korean locale
It fixes #808 that weeks timeframe can not be formatted in korean.
And it also adds special plurlized words in korean.

## Pull Request Checklist

Thank you for taking the time to improve Arrow! Before submitting your pull request, please check all *appropriate* boxes:

<!-- Check boxes by placing an x in the brackets: [x] -->
- [x] 🧪 Added **tests** for changed code.
- [x] 🛠️ All tests **pass** when run locally (run `tox` or `make test` to find out!).
- [x] 🧹 All linting checks **pass** when run locally (run `tox -e lint` or `make lint` to find out!).
- [ ] 📚 Updated **documentation** for changed code.
- [x] ⏩ Code is **up-to-date** with the `master` branch.

If you have *any* questions about your code changes or any of the points above, please submit your questions along with the pull request and we will try our best to help!

## Description of Changes
Related: https://github.com/crsmithdev/arrow/issues/803
Closes: #803

codecov-commenter: # [Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=h1) Report
> Merging [#804](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=desc) into [master](https://codecov.io/gh/crsmithdev/arrow/commit/6e17e229a90aed28732c6526eb93e94853a41029&el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/crsmithdev/arrow/pull/804/graphs/tree.svg?width=650&height=150&src=pr&token=4EkGnFsIGn)](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master      #804   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         1724      1726    +2     
  Branches       295       300    +5     
=========================================
+ Hits          1724      1726    +2     
```


| [Impacted Files](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [arrow/locales.py](https://codecov.io/gh/crsmithdev/arrow/pull/804/diff?src=pr&el=tree#diff-YXJyb3cvbG9jYWxlcy5weQ==) | `100.00% <100.00%> (ø)` | |
| [arrow/arrow.py](https://codecov.io/gh/crsmithdev/arrow/pull/804/diff?src=pr&el=tree#diff-YXJyb3cvYXJyb3cucHk=) | `100.00% <0.00%> (ø)` | |
| [arrow/parser.py](https://codecov.io/gh/crsmithdev/arrow/pull/804/diff?src=pr&el=tree#diff-YXJyb3cvcGFyc2VyLnB5) | `100.00% <0.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=footer). Last update [6e17e22...fe325bc](https://codecov.io/gh/crsmithdev/arrow/pull/804?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

comfuture: @krisfremen Thank you for your kind review of my clumsy contributions. I just improved the code by realizing where I was misunderstanding the behavior of locale handling internal methods.

In addition, I added special Korean date/year frame expression. Although there is a feeling of excessiveness compared to other locales, the expressions commonly used in Windows and OS X.
systemcatch: I'll leave it for @krisfremen to approve but I'm happy with the PR.

Patch:
diff --git a/arrow/locales.py b/arrow/locales.py
index 783e642..b453f82 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -1061,20 +1061,34 @@ class KoreanLocale(Locale):
 
     timeframes = {
         "now": "지금",
-        "second": "두 번째",
-        "seconds": "{0}몇 초",
+        "second": "1초",
+        "seconds": "{0}초",
         "minute": "1분",
         "minutes": "{0}분",
-        "hour": "1시간",
+        "hour": "한시간",
         "hours": "{0}시간",
-        "day": "1일",
+        "day": "하루",
         "days": "{0}일",
-        "month": "1개월",
+        "week": "1주",
+        "weeks": "{0}주",
+        "month": "한달",
         "months": "{0}개월",
         "year": "1년",
         "years": "{0}년",
     }
 
+    special_dayframes = {
+        -3: "그끄제",
+        -2: "그제",
+        -1: "어제",
+        1: "내일",
+        2: "모레",
+        3: "글피",
+        4: "그글피",
+    }
+
+    special_yearframes = {-2: "제작년", -1: "작년", 1: "내년", 2: "내후년"}
+
     month_names = [
         "",
         "1월",
@@ -1109,6 +1123,24 @@ class KoreanLocale(Locale):
     day_names = ["", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"]
     day_abbreviations = ["", "월", "화", "수", "목", "금", "토", "일"]
 
+    def _ordinal_number(self, n):
+        ordinals = ["0", "첫", "두", "세", "네", "다섯", "여섯", "일곱", "여덟", "아홉", "열"]
+        if n < len(ordinals):
+            return "{}번째".format(ordinals[n])
+        return "{}번째".format(n)
+
+    def _format_relative(self, humanized, timeframe, delta):
+        if timeframe in ("day", "days"):
+            special = self.special_dayframes.get(delta)
+            if special:
+                return special
+        elif timeframe in ("year", "years"):
+            special = self.special_yearframes.get(delta)
+            if special:
+                return special
+
+        return super(KoreanLocale, self)._format_relative(humanized, timeframe, delta)
+
 
 # derived locale types & implementations.
 class DutchLocale(Locale):


Test patch:
diff --git a/tests/test_locales.py b/tests/test_locales.py
index 13949ba..189fa6a 100644
--- a/tests/test_locales.py
+++ b/tests/test_locales.py
@@ -1108,3 +1108,79 @@ class TestSwahiliLocale:
     def test_format_relative_future(self):
         result = self.locale._format_relative("saa moja", "hour", -1)
         assert result == "saa moja iliyopita"
+
+
+@pytest.mark.usefixtures("lang_locale")
+class TestKoreanLocale:
+    def test_format_timeframe(self):
+        assert self.locale._format_timeframe("now", 0) == "지금"
+        assert self.locale._format_timeframe("second", 1) == "1초"
+        assert self.locale._format_timeframe("seconds", 2) == "2초"
+        assert self.locale._format_timeframe("minute", 1) == "1분"
+        assert self.locale._format_timeframe("minutes", 2) == "2분"
+        assert self.locale._format_timeframe("hour", 1) == "한시간"
+        assert self.locale._format_timeframe("hours", 2) == "2시간"
+        assert self.locale._format_timeframe("day", 1) == "하루"
+        assert self.locale._format_timeframe("days", 2) == "2일"
+        assert self.locale._format_timeframe("week", 1) == "1주"
+        assert self.locale._format_timeframe("weeks", 2) == "2주"
+        assert self.locale._format_timeframe("month", 1) == "한달"
+        assert self.locale._format_timeframe("months", 2) == "2개월"
+        assert self.locale._format_timeframe("year", 1) == "1년"
+        assert self.locale._format_timeframe("years", 2) == "2년"
+
+    def test_format_relative(self):
+        assert self.locale._format_relative("지금", "now", 0) == "지금"
+
+        assert self.locale._format_relative("1초", "second", 1) == "1초 후"
+        assert self.locale._format_relative("2초", "seconds", 2) == "2초 후"
+        assert self.locale._format_relative("1분", "minute", 1) == "1분 후"
+        assert self.locale._format_relative("2분", "minutes", 2) == "2분 후"
+        assert self.locale._format_relative("한시간", "hour", 1) == "한시간 후"
+        assert self.locale._format_relative("2시간", "hours", 2) == "2시간 후"
+        assert self.locale._format_relative("하루", "day", 1) == "내일"
+        assert self.locale._format_relative("2일", "days", 2) == "모레"
+        assert self.locale._format_relative("3일", "days", 3) == "글피"
+        assert self.locale._format_relative("4일", "days", 4) == "그글피"
+        assert self.locale._format_relative("5일", "days", 5) == "5일 후"
+        assert self.locale._format_relative("1주", "week", 1) == "1주 후"
+        assert self.locale._format_relative("2주", "weeks", 2) == "2주 후"
+        assert self.locale._format_relative("한달", "month", 1) == "한달 후"
+        assert self.locale._format_relative("2개월", "months", 2) == "2개월 후"
+        assert self.locale._format_relative("1년", "year", 1) == "내년"
+        assert self.locale._format_relative("2년", "years", 2) == "내후년"
+        assert self.locale._format_relative("3년", "years", 3) == "3년 후"
+
+        assert self.locale._format_relative("1초", "second", -1) == "1초 전"
+        assert self.locale._format_relative("2초", "seconds", -2) == "2초 전"
+        assert self.locale._format_relative("1분", "minute", -1) == "1분 전"
+        assert self.locale._format_relative("2분", "minutes", -2) == "2분 전"
+        assert self.locale._format_relative("한시간", "hour", -1) == "한시간 전"
+        assert self.locale._format_relative("2시간", "hours", -2) == "2시간 전"
+        assert self.locale._format_relative("하루", "day", -1) == "어제"
+        assert self.locale._format_relative("2일", "days", -2) == "그제"
+        assert self.locale._format_relative("3일", "days", -3) == "그끄제"
+        assert self.locale._format_relative("4일", "days", -4) == "4일 전"
+        assert self.locale._format_relative("1주", "week", -1) == "1주 전"
+        assert self.locale._format_relative("2주", "weeks", -2) == "2주 전"
+        assert self.locale._format_relative("한달", "month", -1) == "한달 전"
+        assert self.locale._format_relative("2개월", "months", -2) == "2개월 전"
+        assert self.locale._format_relative("1년", "year", -1) == "작년"
+        assert self.locale._format_relative("2년", "years", -2) == "제작년"
+        assert self.locale._format_relative("3년", "years", -3) == "3년 전"
+
+    def test_ordinal_number(self):
+        assert self.locale.ordinal_number(0) == "0번째"
+        assert self.locale.ordinal_number(1) == "첫번째"
+        assert self.locale.ordinal_number(2) == "두번째"
+        assert self.locale.ordinal_number(3) == "세번째"
+        assert self.locale.ordinal_number(4) == "네번째"
+        assert self.locale.ordinal_number(5) == "다섯번째"
+        assert self.locale.ordinal_number(6) == "여섯번째"
+        assert self.locale.ordinal_number(7) == "일곱번째"
+        assert self.locale.ordinal_number(8) == "여덟번째"
+        assert self.locale.ordinal_number(9) == "아홉번째"
+        assert self.locale.ordinal_number(10) == "열번째"
+        assert self.locale.ordinal_number(11) == "11번째"
+        assert self.locale.ordinal_number(12) == "12번째"
+        assert self.locale.ordinal_number(100) == "100번째"