From 2790446906db9f0c15f59ad1e4e5cd98a0ede316 Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Sat, 20 Apr 2013 15:56:07 -0400 Subject: [PATCH 1/4] adds a 'strftime' jinja fiter that uses LOCALE --- docs/themes.rst | 20 +++++++++++++++++++- pelican/generators.py | 5 ++++- pelican/utils.py | 20 ++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/themes.rst b/docs/themes.rst index 1e003967..ddf509f8 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -78,7 +78,7 @@ Sorting ------- URL wrappers (currently categories, tags, and authors), have -comparison methods that allow them to be easily sorted by name: +comparison methods that allow them to be easily sorted by name:: {% for tag, articles in tags|sort %} @@ -87,6 +87,24 @@ command`__ has a number of options. __ http://jinja.pocoo.org/docs/templates/#sort + +Date Formatting +--------------- + +Pelican formats the date with according to your settings and locale +(``DATE_FORMATS``/``DEFAULT_DATE_FORMAT``) and provides a +``locale_date`` attribute. On the other hand, ``date`` attribute will +be a `datetime`_ object. If you need custom formatting for a date +different than your settings, use the Jinja filter ``strftime`` +that comes with Pelican. Usage is same as Python `strftime`_ format, +but the filter will do the right thing and format your date according +to the locale given in your settings:: + + {{ article.date|strftime('%d %B %Y') }} + +.. _datetime: http://docs.python.org/2/library/datetime.html#datetime-objects +.. _strftime: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior + index.html ---------- diff --git a/pelican/generators.py b/pelican/generators.py index 7ce1e28b..f2fa0e33 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -23,7 +23,7 @@ from pelican.contents import ( Article, Page, Category, Static, is_valid_content ) from pelican.readers import read_file -from pelican.utils import copy, process_translations, mkdir_p +from pelican.utils import copy, process_translations, mkdir_p, DateFormatter from pelican import signals import pelican.utils @@ -65,6 +65,9 @@ class Generator(object): logger.debug('template list: {0}'.format(self.env.list_templates())) + # provide utils.strftime as a jinja filter + self.env.filters.update({'strftime': DateFormatter()}) + # get custom Jinja filters from user settings custom_filters = self.settings.get('JINJA_FILTERS', {}) self.env.filters.update(custom_filters) diff --git a/pelican/utils.py b/pelican/utils.py index 39a3f8f4..9e8a779d 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -65,6 +65,26 @@ def strftime(date, date_format): return template % tuple(formatted_candidates) +class DateFormatter(object): + '''A date formatter object used as a jinja filter + + Uses the `strftime` implementation and makes sure jinja uses the locale + defined in LOCALE setting + ''' + + def __init__(self): + self.locale = locale.setlocale(locale.LC_TIME) + + def __call__(self, date, date_format): + old_locale = locale.setlocale(locale.LC_TIME) + locale.setlocale(locale.LC_TIME, self.locale) + + formatted = strftime(date, date_format) + + locale.setlocale(locale.LC_TIME, old_locale) + return formatted + + def python_2_unicode_compatible(klass): """ A decorator that defines __unicode__ and __str__ methods under Python 2. From 62a9b055954c3c4938cb22918994a8296d1482b7 Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Mon, 22 Apr 2013 19:54:52 -0400 Subject: [PATCH 2/4] added tests for DateFormatter --- pelican/tests/test_utils.py | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py index 18babca7..3dafc5f9 100644 --- a/pelican/tests/test_utils.py +++ b/pelican/tests/test_utils.py @@ -7,7 +7,11 @@ import datetime import time import locale from sys import platform +from tempfile import mkdtemp +from pelican.generators import TemplatePagesGenerator +from pelican.writers import Writer +from pelican.settings import read_settings from pelican import utils from .support import get_article, LoggedTestCase, locale_available, unittest @@ -283,3 +287,82 @@ class TestUtils(LoggedTestCase): # restore locale back locale.setlocale(locale.LC_TIME, old_locale) + + +class TestDateFormatter(unittest.TestCase): + '''Tests that the output of DateFormatter jinja filter is same as + utils.strftime''' + + def setUp(self): + # prepare a temp content and output folder + self.temp_content = mkdtemp(prefix='pelicantests.') + self.temp_output = mkdtemp(prefix='pelicantests.') + + # prepare a template file + template_dir = os.path.join(self.temp_content, 'template') + template_path = os.path.join(template_dir, 'source.html') + os.makedirs(template_dir) + with open(template_path, 'w') as template_file: + template_file.write('date = {{ date|strftime("%A, %d %B %Y") }}') + self.date = datetime.date(2012, 8, 29) + + + def tearDown(self): + shutil.rmtree(self.temp_content) + shutil.rmtree(self.temp_output) + + + @unittest.skipUnless(locale_available('fr_FR.UTF-8') or + locale_available('French'), + 'French locale needed') + def test_french_locale(self): + settings = read_settings( + override = {'LOCALE': locale.normalize('fr_FR.UTF-8'), + 'TEMPLATE_PAGES': {'template/source.html': + 'generated/file.html'}}) + + generator = TemplatePagesGenerator({'date': self.date}, settings, + self.temp_content, '', self.temp_output, None) + generator.env.filters.update({'strftime': utils.DateFormatter()}) + + writer = Writer(self.temp_output, settings=settings) + generator.generate_output(writer) + + output_path = os.path.join( + self.temp_output, 'generated', 'file.html') + + # output file has been generated + self.assertTrue(os.path.exists(output_path)) + + # output content is correct + with utils.pelican_open(output_path) as output_file: + self.assertEqual(output_file, + utils.strftime(self.date, 'date = %A, %d %B %Y')) + + + @unittest.skipUnless(locale_available('tr_TR.UTF-8') or + locale_available('Turkish'), + 'Turkish locale needed') + def test_turkish_locale(self): + settings = read_settings( + override = {'LOCALE': locale.normalize('tr_TR.UTF-8'), + 'TEMPLATE_PAGES': {'template/source.html': + 'generated/file.html'}}) + + generator = TemplatePagesGenerator({'date': self.date}, settings, + self.temp_content, '', self.temp_output, None) + generator.env.filters.update({'strftime': utils.DateFormatter()}) + + writer = Writer(self.temp_output, settings=settings) + generator.generate_output(writer) + + output_path = os.path.join( + self.temp_output, 'generated', 'file.html') + + # output file has been generated + self.assertTrue(os.path.exists(output_path)) + + # output content is correct + with utils.pelican_open(output_path) as output_file: + self.assertEqual(output_file, + utils.strftime(self.date, 'date = %A, %d %B %Y')) From f3340c11526e6eb2a11f5e8ca22742e095c2bcdf Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Mon, 22 Apr 2013 20:00:27 -0400 Subject: [PATCH 3/4] added FR and TR locale generation to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 608979c1..fa0c2f0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ python: before_install: - sudo apt-get update -qq - sudo apt-get install -qq --no-install-recommends asciidoc + - sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8 install: - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then ln -s /usr/share/asciidoc/asciidocapi.py ~/virtualenv/python2.7/lib/python2.7/site-packages/; fi - pip install mock --use-mirrors From 09a332aff3865f2e2cf2090d09014df739ac383d Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Mon, 22 Apr 2013 20:07:53 -0400 Subject: [PATCH 4/4] reset locale after DateFormatter test --- pelican/tests/test_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py index 3dafc5f9..8b0dc13e 100644 --- a/pelican/tests/test_utils.py +++ b/pelican/tests/test_utils.py @@ -310,6 +310,8 @@ class TestDateFormatter(unittest.TestCase): def tearDown(self): shutil.rmtree(self.temp_content) shutil.rmtree(self.temp_output) + # reset locale to default + locale.setlocale(locale.LC_ALL, '') @unittest.skipUnless(locale_available('fr_FR.UTF-8') or