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

Added locale validation and translation request on untranslated timeframes #646

Merged
merged 11 commits into from
Aug 24, 2019
Prev Previous commit
Next Next commit
added validation test and handled key error for new week granularity
  • Loading branch information
jadchaar committed Aug 20, 2019
commit 92238641c7afbdcf2ba128bdc97d4be6c7162919
155 changes: 84 additions & 71 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ def humanize(

"""

locale_name = locale
locale = locales.get_locale(locale)

if other is None:
Expand All @@ -854,80 +855,92 @@ def humanize(
diff = abs(delta)
delta = diff

if granularity == "auto":
if diff < 10:
return locale.describe("now", only_distance=only_distance)

if diff < 45:
seconds = sign * delta
return locale.describe("seconds", seconds, only_distance=only_distance)

elif diff < 90:
return locale.describe("minute", sign, only_distance=only_distance)
elif diff < 2700:
minutes = sign * int(max(delta / 60, 2))
return locale.describe("minutes", minutes, only_distance=only_distance)

elif diff < 5400:
return locale.describe("hour", sign, only_distance=only_distance)
elif diff < 79200:
hours = sign * int(max(delta / 3600, 2))
return locale.describe("hours", hours, only_distance=only_distance)

elif diff < 129600:
return locale.describe("day", sign, only_distance=only_distance)
elif diff < 554400:
days = sign * int(max(delta / 86400, 2))
return locale.describe("days", days, only_distance=only_distance)

elif diff < 907200:
return locale.describe("week", sign, only_distance=only_distance)
elif diff < 2419200:
weeks = sign * int(max(delta / 604800, 2))
return locale.describe("weeks", weeks, only_distance=only_distance)

elif diff < 3888000:
return locale.describe("month", sign, only_distance=only_distance)
elif diff < 29808000:
self_months = self._datetime.year * 12 + self._datetime.month
other_months = dt.year * 12 + dt.month

months = sign * int(max(abs(other_months - self_months), 2))

return locale.describe("months", months, only_distance=only_distance)

elif diff < 47260800:
return locale.describe("year", sign, only_distance=only_distance)
else:
years = sign * int(max(delta / 31536000, 2))
return locale.describe("years", years, only_distance=only_distance)

else:
if granularity == "second":
delta = sign * delta
if abs(delta) < 2:
try:
if granularity == "auto":
if diff < 10:
return locale.describe("now", only_distance=only_distance)
elif granularity == "minute":
delta = sign * delta / float(60)
elif granularity == "hour":
delta = sign * delta / float(60 * 60)
elif granularity == "day":
delta = sign * delta / float(60 * 60 * 24)
elif granularity == "week":
delta = sign * delta / float(60 * 60 * 24 * 7)
elif granularity == "month":
delta = sign * delta / float(60 * 60 * 24 * 30.5)
elif granularity == "year":
delta = sign * delta / float(60 * 60 * 24 * 365.25)

if diff < 45:
seconds = sign * delta
return locale.describe(
"seconds", seconds, only_distance=only_distance
)

elif diff < 90:
return locale.describe("minute", sign, only_distance=only_distance)
elif diff < 2700:
minutes = sign * int(max(delta / 60, 2))
return locale.describe(
"minutes", minutes, only_distance=only_distance
)

elif diff < 5400:
return locale.describe("hour", sign, only_distance=only_distance)
elif diff < 79200:
hours = sign * int(max(delta / 3600, 2))
return locale.describe("hours", hours, only_distance=only_distance)

elif diff < 129600:
return locale.describe("day", sign, only_distance=only_distance)
elif diff < 554400:
days = sign * int(max(delta / 86400, 2))
return locale.describe("days", days, only_distance=only_distance)

elif diff < 907200:
return locale.describe("week", sign, only_distance=only_distance)
elif diff < 2419200:
weeks = sign * int(max(delta / 604800, 2))
return locale.describe("weeks", weeks, only_distance=only_distance)

elif diff < 3888000:
return locale.describe("month", sign, only_distance=only_distance)
elif diff < 29808000:
self_months = self._datetime.year * 12 + self._datetime.month
other_months = dt.year * 12 + dt.month

months = sign * int(max(abs(other_months - self_months), 2))

return locale.describe(
"months", months, only_distance=only_distance
)

elif diff < 47260800:
return locale.describe("year", sign, only_distance=only_distance)
else:
years = sign * int(max(delta / 31536000, 2))
return locale.describe("years", years, only_distance=only_distance)

else:
raise AttributeError(
'Error. Could not understand your level of granularity. Please select between \
"second", "minute", "hour", "day", "week", "month" or "year"'
if granularity == "second":
delta = sign * delta
if abs(delta) < 2:
return locale.describe("now", only_distance=only_distance)
elif granularity == "minute":
delta = sign * delta / float(60)
elif granularity == "hour":
delta = sign * delta / float(60 * 60)
elif granularity == "day":
delta = sign * delta / float(60 * 60 * 24)
elif granularity == "week":
delta = sign * delta / float(60 * 60 * 24 * 7)
elif granularity == "month":
delta = sign * delta / float(60 * 60 * 24 * 30.5)
elif granularity == "year":
delta = sign * delta / float(60 * 60 * 24 * 365.25)
else:
raise AttributeError(
"Invalid level of granularity. Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'"
)

if trunc(abs(delta)) != 1:
granularity += "s"
return locale.describe(granularity, delta, only_distance=only_distance)
except KeyError as e:
raise ValueError(
"Humanization of the {} granularity is not currently translated in the '{}' locale. Please consider making a contribution to this locale.".format(
e, locale_name
)

if trunc(abs(delta)) != 1:
granularity += "s"
return locale.describe(granularity, delta, only_distance=only_distance)
)

# query functions

Expand Down
8 changes: 4 additions & 4 deletions arrow/locales.py
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ class UkrainianLocale(SlavicBaseLocale):
day_abbreviations = ["", "пн", "вт", "ср", "чт", "пт", "сб", "нд"]


class _DeutschLocaleCommonMixin(object):
class DeutschBaseLocale(Locale):

past = "vor {0}"
future = "in {0}"
Expand Down Expand Up @@ -1529,12 +1529,12 @@ def describe(self, timeframe, delta=0, only_distance=False):
return humanized


class GermanLocale(_DeutschLocaleCommonMixin, Locale):
class GermanLocale(DeutschBaseLocale, Locale):

names = ["de", "de_de"]


class AustrianLocale(_DeutschLocaleCommonMixin, Locale):
class AustrianLocale(DeutschBaseLocale, Locale):

names = ["de_at"]

Expand Down Expand Up @@ -3072,7 +3072,7 @@ def _map_locales():
locales = {}

for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
if issubclass(cls, Locale):
if issubclass(cls, Locale): # pragma: no cover
for name in cls.names:
locales[name.lower()] = cls

Expand Down
28 changes: 28 additions & 0 deletions tests/locales_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@
from arrow import arrow, locales


class LocaleValidationTests(Chai):
def setUp(self):
super(LocaleValidationTests, self).setUp()

self.locales = locales._locales

def test_locale_validation(self):

for _, locale_cls in self.locales.items():
# 7 days + 1 spacer to allow for 1-indexing of months
self.assertEqual(len(locale_cls.day_names), 8)
self.assertTrue(locale_cls.day_names[0] == "")

self.assertEqual(len(locale_cls.day_abbreviations), 8)
self.assertTrue(locale_cls.day_abbreviations[0] == "")

# 12 months + 1 spacer to allow for 1-indexing of months
self.assertEqual(len(locale_cls.month_names), 13)
self.assertTrue(locale_cls.month_names[0] == "")

self.assertEqual(len(locale_cls.month_abbreviations), 13)
self.assertTrue(locale_cls.month_abbreviations[0] == "")

self.assertTrue(len(locale_cls.names) > 0)
self.assertTrue(locale_cls.past is not None)
self.assertTrue(locale_cls.future is not None)


class ModuleTests(Chai):
def test_get_locale(self):

Expand Down