Skip to content

Commit

Permalink
Merge pull request #2036 from getnikola/add-locale-handlers
Browse files Browse the repository at this point in the history
Add locale handlers for month names and formatted dates. (fixes #2029)
  • Loading branch information
felixfontein committed Sep 8, 2015
2 parents a6cc45c + da5f350 commit b0e9b64
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
2 changes: 1 addition & 1 deletion nikola/nikola.py
Expand Up @@ -1836,7 +1836,7 @@ def atom_link(link_rel, link_type, link_href):
feed_id = lxml.etree.SubElement(feed_root, "id")
feed_id.text = self.abs_link(context["feedlink"])
feed_updated = lxml.etree.SubElement(feed_root, "updated")
feed_updated.text = utils.formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
feed_updated.text = utils.LocaleBorg().formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
feed_author = lxml.etree.SubElement(feed_root, "author")
feed_author_name = lxml.etree.SubElement(feed_author, "name")
feed_author_name.text = self.config["BLOG_AUTHOR"](lang)
Expand Down
2 changes: 1 addition & 1 deletion nikola/post.py
Expand Up @@ -323,7 +323,7 @@ def template_name(self):

def formatted_date(self, date_format, date=None):
"""Return the formatted date as unicode."""
return utils.formatted_date(date_format, date if date else self.date)
return utils.LocaleBorg().formatted_date(date_format, date if date else self.date)

def formatted_updated(self, date_format):
"""Return the updated date as unicode."""
Expand Down
68 changes: 52 additions & 16 deletions nikola/utils.py
Expand Up @@ -71,7 +71,7 @@
'adjust_name_for_index_path', 'adjust_name_for_index_link',
'NikolaPygmentsHTML', 'create_redirect', 'TreeNode',
'flatten_tree_structure', 'parse_escaped_hierarchical_category_name',
'join_hierarchical_category_path', 'indent', 'formatted_date')
'join_hierarchical_category_path', 'indent')

# Are you looking for 'generic_rss_renderer'?
# It's defined in nikola.nikola.Nikola (the site object).
Expand Down Expand Up @@ -1041,6 +1041,8 @@ def initialize(cls, locales, initial_lang):
assert initial_lang is not None and initial_lang in locales
cls.reset()
cls.locales = locales
cls.month_name_handlers = []
cls.formatted_date_handlers = []

# needed to decode some localized output in py2x
encodings = {}
Expand All @@ -1063,6 +1065,29 @@ def reset(cls):
cls.encodings = {}
cls.__shared_state = {'current_lang': None}
cls.initialized = False
cls.month_name_handlers = []
cls.formatted_date_handlers = []

@classmethod
def add_handler(cls, month_name_handler=None, formatted_date_handler=None):
"""Allow to add month name and formatted date handlers.
If month_name_handler is not None, it is expected to be a callable
which accepts (month_no, lang) and returns either a string or None.
If formatted_date_handler is not None, it is expected to be a callable
which accepts (date_format, date, lang) and returns either a string or
None.
A handler is expected to either return the correct result for the given
language and data, or return None to indicate it is not able to do the
job. In that case, the next handler is asked, and finally the default
implementation is used.
"""
if month_name_handler is not None:
cls.month_name_handlers.append(month_name_handler)
if formatted_date_handler is not None:
cls.formatted_date_handlers.append(formatted_date_handler)

def __init__(self):
"""Initialize."""
Expand All @@ -1088,6 +1113,10 @@ def set_locale(self, lang):

def get_month_name(self, month_no, lang):
"""Return localized month name in an unicode string."""
for handler in self.month_name_handlers:
res = handler(month_no, lang)
if res is not None:
return res
if sys.version_info[0] == 3: # Python 3
with calendar.different_locale(self.locales[lang]):
s = calendar.month_name[month_no]
Expand All @@ -1104,6 +1133,28 @@ def get_month_name(self, month_no, lang):
self.set_locale(self.current_lang)
return s

def formatted_date(self, date_format, date):
"""Return the formatted date as unicode."""
fmt_date = None
# First check handlers
for handler in self.formatted_date_handlers:
fmt_date = handler(date_format, date, self.__shared_state['current_lang'])
if fmt_date is not None:
break
# If no handler was able to format the date, ask Python
if fmt_date is None:
if date_format == 'webiso':
# Formatted after RFC 3339 (web ISO 8501 profile) with Zulu
# zone desgignator for times in UTC and no microsecond precision.
fmt_date = date.replace(microsecond=0).isoformat().replace('+00:00', 'Z')
else:
fmt_date = date.strftime(date_format)

# Issue #383, this changes from py2 to py3
if isinstance(fmt_date, bytes_str):
fmt_date = fmt_date.decode('utf8')
return fmt_date


class ExtendedRSS2(rss.RSS2):

Expand Down Expand Up @@ -1732,18 +1783,3 @@ def prefixed_lines():
for line in text.splitlines(True):
yield (prefix + line if predicate(line) else line)
return ''.join(prefixed_lines())


def formatted_date(date_format, date):
"""Return the formatted date as unicode."""
if date_format == 'webiso':
# Formatted after RFC 3339 (web ISO 8501 profile) with Zulu
# zone desgignator for times in UTC and no microsecond precision.
fmt_date = date.replace(microsecond=0).isoformat().replace('+00:00', 'Z')
else:
fmt_date = date.strftime(date_format)

# Issue #383, this changes from py2 to py3
if isinstance(fmt_date, bytes_str):
fmt_date = fmt_date.decode('utf8')
return fmt_date

0 comments on commit b0e9b64

Please sign in to comment.