Skip to content

Instantly share code, notes, and snippets.

@davidrios
Created December 8, 2014 17:33
Show Gist options
  • Save davidrios/0725cb692c23871ade23 to your computer and use it in GitHub Desktop.
Save davidrios/0725cb692c23871ade23 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
import gettext
import re
import threading
from datetime import datetime, time
import pytz
from babel import dates, numbers
_WRAPPED_GETTEXT_NAMES = ('gettext', 'ugettext', 'ngettext', 'ungettext')
_WRAPPED_BABEL_NAMES = {
'format_datetime': dates,
'format_date': dates,
'format_time': dates,
'format_timedelta': dates,
'parse_date': dates,
'format_currency': numbers,
'format_decimal': numbers,
'format_number': numbers,
'format_percent': numbers,
'format_scientific': numbers,
'parse_decimal': numbers,
'parse_grouping': numbers,
'parse_number': numbers,
}
class ThreadlocalLocale(object):
def __init__(self, app_name, mo_location, default_locale, default_timezone):
self._app_name = app_name
self._mo_location = mo_location
self._default_locale = default_locale
self._default_timezone = default_timezone
self._thread_local = threading.local()
self.set_locale(default_locale)
self.set_timezone(default_timezone)
gettext.install(True, localedir=None, unicode=1)
gettext.find(self._app_name, self._mo_location)
gettext.textdomain(self._app_name)
gettext.bind_textdomain_codeset(self._app_name, "UTF-8")
self._wrapped_funcs = {}
def _wrap_gettext_func(name):
def wrapped(*args, **kwargs):
return getattr(gettext.translation(self._app_name, self._mo_location, languages=[self._thread_local.locale], fallback=True), name)(*args, **kwargs)
return wrapped
for name in _WRAPPED_GETTEXT_NAMES:
self._wrapped_funcs[name] = _wrap_gettext_func(name)
def _wrap_babel_func(name, module):
if name in ('format_date', 'format_datetime', 'format_time'):
def wrapped(*args):
if isinstance(args[0], datetime):
args = list(args)
if args[0].tzinfo is None:
args[0] = pytz.utc.localize(args[0])
args[0] = args[0].astimezone(self._thread_local.timezone)
return getattr(module, name)(*args, locale=self._thread_local.locale)
return wrapped
else:
def wrapped(*args):
return getattr(module, name)(*args, locale=self._thread_local.locale)
return wrapped
for name, module in _WRAPPED_BABEL_NAMES.items():
self._wrapped_funcs[name] = _wrap_babel_func(name, module)
def set_locale(self, locale):
self._thread_local.locale = locale
def set_timezone(self, timezone):
if isinstance(timezone, basestring):
timezone = pytz.timezone(timezone)
if not (isinstance(timezone, pytz.tzinfo.DstTzInfo) or isinstance(timezone, pytz.tzinfo.StaticTzInfo)):
raise ValueError('must be a valid pytz timezone')
self._thread_local.timezone = timezone
def parse_time(self, string):
format = dates.get_time_format(locale=self._thread_local.locale).pattern.lower()
hour_idx = format.index('h')
if hour_idx < 0:
hour_idx = format.index('k')
min_idx = format.index('m')
sec_idx = format.index('s')
indexes = [(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')]
indexes.sort()
indexes = dict([(item[1], idx) for idx, item in enumerate(indexes)])
numbers = re.findall('(\d+)', string)
hour = int(numbers[indexes['H']])
minute = int(numbers[indexes['M']])
second = 0
if len(numbers) > indexes['S']:
second = int(numbers[indexes['S']])
return time(hour, minute, second)
def parse_datetime(self, val, separator=' '):
dstr, tstr = val.split(separator, 1)
date = self.parse_date(dstr)
time = self.parse_time(tstr)
dt = self._thread_local.timezone.localize(datetime(
date.year, date.month, date.day, time.hour, time.minute, time.second
))
return dt.astimezone(pytz.utc).replace(tzinfo=None)
def format_decimal2(self, number):
return self.format_decimal(number, '#,##0.00')
def __getattr__(self, name):
if name not in _WRAPPED_GETTEXT_NAMES and name not in _WRAPPED_BABEL_NAMES:
raise TypeError('attribute "%s" not supported' % name)
return self._wrapped_funcs[name]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment