Repository: crsmithdev/arrow
Pull request #794 (2020-05-28 18:34:17)

Add weeks translation for Hebrew
## 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!).
- [N/A] 📚 Updated **documentation** for changed code.
- [x] ⏩ Code is **up-to-date** with the `master` branch.

## Description of Changes

Add Hebrew translation for "weeks". Currently I catch the ValueError in my codebase to prevent arrow from crashing when trying to humanize weeks :)

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

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

```diff
@@            Coverage Diff            @@
##            master      #794   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           10        10           
  Lines         1678      1694   +16     
  Branches       289       289           
=========================================
+ Hits          1678      1694   +16     
```


| [Impacted Files](https://codecov.io/gh/crsmithdev/arrow/pull/794?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [arrow/locales.py](https://codecov.io/gh/crsmithdev/arrow/pull/794/diff?src=pr&el=tree#diff-YXJyb3cvbG9jYWxlcy5weQ==) | `100.00% <100.00%> (ø)` | |
| [arrow/arrow.py](https://codecov.io/gh/crsmithdev/arrow/pull/794/diff?src=pr&el=tree#diff-YXJyb3cvYXJyb3cucHk=) | `100.00% <0.00%> (ø)` | |
| [arrow/parser.py](https://codecov.io/gh/crsmithdev/arrow/pull/794/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/794?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/794?src=pr&el=footer). Last update [b8a6011...435b080](https://codecov.io/gh/crsmithdev/arrow/pull/794?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

yammesicka: Sure, done.
yammesicka: There is now support for every edge-case I can think about, and probably more tests than in any other language :)

Patch:
diff --git a/arrow/locales.py b/arrow/locales.py
index 6c8fdd2..e26cef5 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -3077,6 +3077,7 @@ class HebrewLocale(Locale):
 
     past = "לפני {0}"
     future = "בעוד {0}"
+    and_word = "ו"
 
     timeframes = {
         "now": "הרגע",
@@ -3090,6 +3091,9 @@ class HebrewLocale(Locale):
         "day": "יום",
         "days": "{0} ימים",
         "2-days": "יומיים",
+        "week": "שבוע",
+        "weeks": "{0} שבועות",
+        "2-weeks": "שבועיים",
         "month": "חודש",
         "months": "{0} חודשים",
         "2-months": "חודשיים",
@@ -3142,10 +3146,41 @@ class HebrewLocale(Locale):
     def _format_timeframe(self, timeframe, delta):
         """Hebrew couple of <timeframe> aware"""
         couple = "2-{}".format(timeframe)
+        single = timeframe.rstrip("s")
         if abs(delta) == 2 and couple in self.timeframes:
-            return self.timeframes[couple].format(abs(delta))
+            key = couple
+        elif abs(delta) == 1 and single in self.timeframes:
+            key = single
         else:
-            return self.timeframes[timeframe].format(abs(delta))
+            key = timeframe
+
+        return self.timeframes[key].format(trunc(abs(delta)))
+
+    def describe_multi(self, timeframes, only_distance=False):
+        """ Describes a delta within multiple timeframes in plain language.
+        In Hebrew, the and word behaves a bit differently.
+
+        :param timeframes: a list of string, quantity pairs each representing a timeframe and delta.
+        :param only_distance: return only distance eg: "2 hours and 11 seconds" without "in" or "ago" keywords
+        """
+
+        humanized = ""
+        for index, (timeframe, delta) in enumerate(timeframes):
+            last_humanized = self._format_timeframe(timeframe, delta)
+            if index == 0:
+                humanized = last_humanized
+            elif index == len(timeframes) - 1:  # Must have at least 2 items
+                humanized += " " + self.and_word
+                if last_humanized[0].isdecimal():
+                    humanized += "־"
+                humanized += last_humanized
+            else:  # Don't add for the last one
+                humanized += ", " + last_humanized
+
+        if not only_distance:
+            humanized = self._format_relative(humanized, timeframe, delta)
+
+        return humanized
 
 
 class MarathiLocale(Locale):


Test patch:
diff --git a/tests/test_locales.py b/tests/test_locales.py
index 2f543a3..6336889 100644
--- a/tests/test_locales.py
+++ b/tests/test_locales.py
@@ -505,18 +505,50 @@ class TestMacedonianLocale:
         assert self.locale._format_timeframe("minutes", 25) == "25 минути"
 
 
+@pytest.mark.usefixtures("time_2013_01_01")
 @pytest.mark.usefixtures("lang_locale")
 class TestHebrewLocale:
     def test_couple_of_timeframe(self):
-        assert self.locale._format_timeframe("hours", 2) == "שעתיים"
-        assert self.locale._format_timeframe("months", 2) == "חודשיים"
+        assert self.locale._format_timeframe("days", 1) == "יום"
         assert self.locale._format_timeframe("days", 2) == "יומיים"
-        assert self.locale._format_timeframe("years", 2) == "שנתיים"
+        assert self.locale._format_timeframe("days", 3) == "3 ימים"
+
+        assert self.locale._format_timeframe("hours", 1) == "שעה"
+        assert self.locale._format_timeframe("hours", 2) == "שעתיים"
         assert self.locale._format_timeframe("hours", 3) == "3 שעות"
+
+        assert self.locale._format_timeframe("week", 1) == "שבוע"
+        assert self.locale._format_timeframe("weeks", 2) == "שבועיים"
+        assert self.locale._format_timeframe("weeks", 3) == "3 שבועות"
+
+        assert self.locale._format_timeframe("months", 1) == "חודש"
+        assert self.locale._format_timeframe("months", 2) == "חודשיים"
         assert self.locale._format_timeframe("months", 4) == "4 חודשים"
-        assert self.locale._format_timeframe("days", 3) == "3 ימים"
+
+        assert self.locale._format_timeframe("years", 1) == "שנה"
+        assert self.locale._format_timeframe("years", 2) == "שנתיים"
         assert self.locale._format_timeframe("years", 5) == "5 שנים"
 
+    def test_describe_multi(self):
+        describe = self.locale.describe_multi
+
+        fulltest = [("years", 5), ("weeks", 1), ("hours", 1), ("minutes", 6)]
+        assert describe(fulltest) == "בעוד 5 שנים, שבוע, שעה ו־6 דקות"
+        seconds4000_0days = [("days", 0), ("hours", 1), ("minutes", 6)]
+        assert describe(seconds4000_0days) == "בעוד 0 ימים, שעה ו־6 דקות"
+        seconds4000 = [("hours", 1), ("minutes", 6)]
+        assert describe(seconds4000) == "בעוד שעה ו־6 דקות"
+        assert describe(seconds4000, only_distance=True) == "שעה ו־6 דקות"
+        seconds3700 = [("hours", 1), ("minutes", 1)]
+        assert describe(seconds3700) == "בעוד שעה ודקה"
+        seconds300_0hours = [("hours", 0), ("minutes", 5)]
+        assert describe(seconds300_0hours) == "בעוד 0 שעות ו־5 דקות"
+        seconds300 = [("minutes", 5)]
+        assert describe(seconds300) == "בעוד 5 דקות"
+        seconds60 = [("minutes", 1)]
+        assert describe(seconds60) == "בעוד דקה"
+        assert describe(seconds60, only_distance=True) == "דקה"
+
 
 @pytest.mark.usefixtures("lang_locale")
 class TestMarathiLocale: