Skip to content

Commit

Permalink
i18n: Handle missing babel locale on timesince formatting
Browse files Browse the repository at this point in the history
LocalDate is dropped since the right babel locale formatter can
be already retrieved by using the more reliable get_locale_formats
function which provides sane defaults to fall back to in case of
locale being missing in babel.

The leftover code after this refactoring is simple enough to be folded
into the timesince function. Also did minor refactor to get_locale_formats
in order to allow telling to retrieve a specific locale, which eases
testing specific locales formatting.

Fixes: 'UnknownLocaleError: unknown locale 'son'
  • Loading branch information
unho committed Feb 13, 2017
1 parent 9f0bece commit 898316d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 51 deletions.
43 changes: 3 additions & 40 deletions pootle/i18n/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,12 @@
# or later license. See the LICENSE file for a copy of the license and the
# AUTHORS file for copyright and authorship information.

import locale as system_locale
import os
from datetime import datetime

from babel.dates import format_timedelta

from django.utils import translation


class LocalDate(object):

def __init__(self):
if not self.locale_code and not os.name == "nt":
self.set_locale()

@property
def default_locale(self):
return translation.to_locale(translation.get_language())

def set_locale(self):
system_locale.setlocale(
system_locale.LC_ALL,
(self.default_locale, 'UTF-8'))

@property
def locale_code(self):
return system_locale.getlocale()[0]

def format_timesince(self, timestamp, locale=None):
return format_timedelta(
datetime.now()
- datetime.fromtimestamp(
timestamp),
locale=(
locale
or self.locale_code
or self.default_locale))


localdate = LocalDate()
from .formatter import get_locale_formats


def timesince(timestamp, locale=None):
if locale:
locale = translation.to_locale(locale)
return localdate.format_timesince(timestamp, locale=locale)
timedelta = datetime.now() - datetime.fromtimestamp(timestamp)
return get_locale_formats(locale).timedelta(timedelta, format='long')
6 changes: 4 additions & 2 deletions pootle/i18n/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
from django.utils.translation import get_language, to_locale


def get_locale_formats():
for language in [get_language(), settings.LANGUAGE_CODE, 'en-us']:
def get_locale_formats(locale=None):
languages = [locale] if locale else []
languages += [get_language(), settings.LANGUAGE_CODE, 'en-us']
for language in languages:
try:
locale = babel_core.Locale.parse(to_locale(language))
break
Expand Down
32 changes: 23 additions & 9 deletions tests/i18n/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@
# or later license. See the LICENSE file for a copy of the license and the
# AUTHORS file for copyright and authorship information.

import pytest
import time
from datetime import datetime

from babel.dates import format_timedelta

from pootle.i18n.dates import localdate, timesince
from pootle.i18n.dates import timesince
from pootle.i18n.formatter import get_locale_formats


def test_local_date_timesince(settings):
timestamp = time.time() - 1000000
assert (
timesince(timestamp)
== format_timedelta(
datetime.now()
- datetime.fromtimestamp(timestamp),
locale=(
localdate.locale_code
or localdate.default_locale)))
timedelta = datetime.now() - datetime.fromtimestamp(timestamp)
language = str(get_locale_formats().locale)
assert timesince(timestamp) == format_timedelta(timedelta, locale=language)


@pytest.mark.parametrize('language,fallback', [
# Normal
('af', 'af'),
('en-za', 'en-za'),
('en-us', 'en-us'),
# Code from ISO 639 reserved range (cannot be used to represent a language)
# so we know for sure it has to fall back.
('qbb', 'en-us'),
])
def test_local_date_timesince_wrong_locale(language, fallback):
timestamp = time.time() - 1000000
timedelta = datetime.now() - datetime.fromtimestamp(timestamp)
fallback_format = get_locale_formats(fallback)
fallback_timedelta = fallback_format.timedelta(timedelta, format='long')
assert timesince(timestamp, locale=language) == fallback_timedelta

0 comments on commit 898316d

Please sign in to comment.