[gimp-web/gimp-web-static] Testing i18n_subsites to produce gimp.org/de/about...



commit 39a84ee744dffa8290de593dee3d7f1229a2d7c9
Author: Pat David <patdavid gmail com>
Date:   Fri Aug 21 11:32:09 2015 -0500

    Testing i18n_subsites to produce gimp.org/de/about...

 content/about/irc.md                   |    1 +
 content/about/meta/building/index.md   |    1 +
 content/about/meta/index.md            |    1 +
 content/screenshots/index.md           |    4 +-
 pelicanconf.py                         |   12 +-
 plugins/i18n_subsites/__init__.py      |    1 +
 plugins/i18n_subsites/i18n_subsites.py |  444 ++++++++++++++++++++++++++++++++
 themes/newgimp/templates/base.html     |    6 +
 themes/newgimp/templates/home.html     |    4 +-
 themes/newgimp/templates/page.html     |    5 +-
 10 files changed, 471 insertions(+), 8 deletions(-)
---
diff --git a/content/about/irc.md b/content/about/irc.md
index 952a61f..e07246d 100644
--- a/content/about/irc.md
+++ b/content/about/irc.md
@@ -4,6 +4,7 @@ Author: Pat David
 url: irc.html
 save_as: irc.html
 status: hidden
+lang: en
 
 
 Several IRC channels and [mailing lists](/mail_lists.html) are available for discussing GIMP-related topics. 
IRC offers real-time communication, but be aware that there may be long periods of silence in the channels 
when other users are busy or away from their keyboards. When you join the GIMP IRC channels, please do not 
ask if somebody can help you. If you have a question, ask directly and then wait patiently to see if someone 
answers. Other recommendations can be found [at the bottom of this page](#rules).
diff --git a/content/about/meta/building/index.md b/content/about/meta/building/index.md
index 9f616fb..1e59b0b 100644
--- a/content/about/meta/building/index.md
+++ b/content/about/meta/building/index.md
@@ -3,6 +3,7 @@ Date: 2015-08-11T11:56:58-05:00
 Modified: 2015-08-11T11:57:04-05:00
 Author: Pat David
 Summary: A page about the new site.
+lang: en
 
 
 So you want to contribute?
diff --git a/content/about/meta/index.md b/content/about/meta/index.md
index 7293f71..3dae768 100644
--- a/content/about/meta/index.md
+++ b/content/about/meta/index.md
@@ -3,6 +3,7 @@ Date: 2015-07-29T14:40:35-05:00
 Modified: 2015-08-10T14:53:46-05:00
 Author: Pat David
 Summary: A page about the new site.
+lang: en
 
 
 I (Pat David) am creating this page to keep notes and information for building/maintaining the new site.
diff --git a/content/screenshots/index.md b/content/screenshots/index.md
index d79d8f5..560b31a 100644
--- a/content/screenshots/index.md
+++ b/content/screenshots/index.md
@@ -9,14 +9,14 @@ Status: hidden
 ## GNU/Linux Screenshots
 
 <figure>
-<img src="linux_fullscreen.jpg" alt="" />
+<img src="linux_fullscreen.jpg" alt="Linux Fullscreen" />
 <figcaption>
 GIMP running fullscreen, side by side with F-Spot.
 </figcaption>
 </figure>
 
 <figure>
-<img src="linux_mixer.jpg" alt="" />
+<img src="linux_mixer.jpg" alt="Linux Mixer" />
 <figcaption>
 Full control over B/W process using the channel mixer.
 </figcaption>
diff --git a/pelicanconf.py b/pelicanconf.py
index e7d6225..f70fc36 100644
--- a/pelicanconf.py
+++ b/pelicanconf.py
@@ -5,7 +5,17 @@ from __future__ import unicode_literals
 #Plugins
 PLUGIN_PATHS = ["plugins"]
 #PLUGINS = ["page_hierarchy_gimp"]
-PLUGINS = ["mimic_hierarchy"]
+PLUGINS = ["mimic_hierarchy", "i18n_subsites"]
+
+# mapping: language_code -> settings_overrides_dict
+I18N_SUBSITES = {
+        'fr': {
+            'SITENAME': 'GIMP FR',
+            },
+        'de': {
+            'SITENAME': 'GIMP DE',
+            }
+        }
 
 AUTHOR = u'Pat David'
 SITENAME = u'GIMP'
diff --git a/plugins/i18n_subsites/__init__.py b/plugins/i18n_subsites/__init__.py
new file mode 100644
index 0000000..7dfbde0
--- /dev/null
+++ b/plugins/i18n_subsites/__init__.py
@@ -0,0 +1 @@
+from .i18n_subsites import *
diff --git a/plugins/i18n_subsites/i18n_subsites.py b/plugins/i18n_subsites/i18n_subsites.py
new file mode 100644
index 0000000..7361d16
--- /dev/null
+++ b/plugins/i18n_subsites/i18n_subsites.py
@@ -0,0 +1,444 @@
+"""i18n_subsites plugin creates i18n-ized subsites of the default site
+
+This plugin is designed for Pelican 3.4 and later
+"""
+
+
+import os
+import six
+import logging
+import posixpath
+
+from copy import copy
+from itertools import chain
+from operator import attrgetter
+from collections import OrderedDict
+from contextlib import contextmanager
+from six.moves.urllib.parse import urlparse
+
+import gettext
+import locale
+
+from pelican import signals
+from pelican.generators import ArticlesGenerator, PagesGenerator
+from pelican.settings import configure_settings
+from pelican.contents import Draft
+
+
+# Global vars
+_MAIN_SETTINGS = None     # settings dict of the main Pelican instance
+_MAIN_LANG = None         # lang of the main Pelican instance
+_MAIN_SITEURL = None      # siteurl of the main Pelican instance
+_MAIN_STATIC_FILES = None # list of Static instances the main Pelican instance
+_SUBSITE_QUEUE = {}   # map: lang -> settings overrides
+_SITE_DB = OrderedDict()           # OrderedDict: lang -> siteurl
+_SITES_RELPATH_DB = {}       # map: (lang, base_lang) -> relpath
+# map: generator -> list of removed contents that need interlinking
+_GENERATOR_DB = {}
+_NATIVE_CONTENT_URL_DB = {} # map: source_path -> content in its native lang
+_LOGGER = logging.getLogger(__name__)
+
+
+ contextmanager
+def temporary_locale(temp_locale=None):
+    '''Enable code to run in a context with a temporary locale
+
+    Resets the locale back when exiting context.
+    Can set a temporary locale if provided
+    '''
+    orig_locale = locale.setlocale(locale.LC_ALL)
+    if temp_locale is not None:
+        locale.setlocale(locale.LC_ALL, temp_locale)
+    yield
+    locale.setlocale(locale.LC_ALL, orig_locale)
+
+
+def initialize_dbs(settings):
+    '''Initialize internal DBs using the Pelican settings dict
+
+    This clears the DBs for e.g. autoreload mode to work
+    '''
+    global _MAIN_SETTINGS, _MAIN_SITEURL, _MAIN_LANG, _SUBSITE_QUEUE
+    _MAIN_SETTINGS = settings
+    _MAIN_LANG = settings['DEFAULT_LANG']
+    _MAIN_SITEURL = settings['SITEURL']
+    _SUBSITE_QUEUE = settings.get('I18N_SUBSITES', {}).copy()
+    prepare_site_db_and_overrides()
+    # clear databases in case of autoreload mode
+    _SITES_RELPATH_DB.clear()
+    _NATIVE_CONTENT_URL_DB.clear()
+    _GENERATOR_DB.clear()
+
+
+def prepare_site_db_and_overrides():
+    '''Prepare overrides and create _SITE_DB
+
+    _SITE_DB.keys() need to be ready for filter_translations
+    '''
+    _SITE_DB.clear()
+    _SITE_DB[_MAIN_LANG] = _MAIN_SITEURL
+    # make sure it works for both root-relative and absolute
+    main_siteurl = '/' if _MAIN_SITEURL == '' else _MAIN_SITEURL
+    for lang, overrides in _SUBSITE_QUEUE.items():
+        if 'SITEURL' not in overrides:
+            overrides['SITEURL'] = posixpath.join(main_siteurl, lang)
+        _SITE_DB[lang] = overrides['SITEURL']
+        # default subsite hierarchy
+        if 'OUTPUT_PATH' not in overrides:
+            overrides['OUTPUT_PATH'] = os.path.join(
+                _MAIN_SETTINGS['OUTPUT_PATH'], lang)
+        if 'CACHE_PATH' not in overrides:
+            overrides['CACHE_PATH'] = os.path.join(
+                _MAIN_SETTINGS['CACHE_PATH'], lang)
+        if 'STATIC_PATHS' not in overrides:
+            overrides['STATIC_PATHS'] = []
+        if ('THEME' not in overrides and 'THEME_STATIC_DIR' not in overrides and
+                'THEME_STATIC_PATHS' not in overrides):
+            relpath = relpath_to_site(lang, _MAIN_LANG)
+            overrides['THEME_STATIC_DIR'] = posixpath.join(
+                relpath, _MAIN_SETTINGS['THEME_STATIC_DIR'])
+            overrides['THEME_STATIC_PATHS'] = []
+        # to change what is perceived as translations
+        overrides['DEFAULT_LANG'] = lang
+
+
+def subscribe_filter_to_signals(settings):
+    '''Subscribe content filter to requested signals'''
+    for sig in settings.get('I18N_FILTER_SIGNALS', []):
+        sig.connect(filter_contents_translations)
+
+
+def initialize_plugin(pelican_obj):
+    '''Initialize plugin variables and Pelican settings'''
+    if _MAIN_SETTINGS is None:
+        initialize_dbs(pelican_obj.settings)
+        subscribe_filter_to_signals(pelican_obj.settings)
+
+
+def get_site_path(url):
+    '''Get the path component of an url, excludes siteurl
+
+    also normalizes '' to '/' for relpath to work,
+    otherwise it could be interpreted as a relative filesystem path
+    '''
+    path = urlparse(url).path
+    if path == '':
+        path = '/'
+    return path
+
+
+def relpath_to_site(lang, target_lang):
+    '''Get relative path from siteurl of lang to siteurl of base_lang
+
+    the output is cached in _SITES_RELPATH_DB
+    '''
+    path = _SITES_RELPATH_DB.get((lang, target_lang), None)
+    if path is None:
+        siteurl = _SITE_DB.get(lang, _MAIN_SITEURL)
+        target_siteurl = _SITE_DB.get(target_lang, _MAIN_SITEURL)
+        path = posixpath.relpath(get_site_path(target_siteurl),
+                                 get_site_path(siteurl))
+        _SITES_RELPATH_DB[(lang, target_lang)] = path
+    return path
+
+
+def save_generator(generator):
+    '''Save the generator for later use
+
+    initialize the removed content list
+    '''
+    _GENERATOR_DB[generator] = []
+
+
+def article2draft(article):
+    '''Transform an Article to Draft'''
+    draft = Draft(article._content, article.metadata, article.settings,
+                  article.source_path, article._context)
+    draft.status = 'draft'
+    return draft
+
+
+def page2hidden_page(page):
+    '''Transform a Page to a hidden Page'''
+    page.status = 'hidden'
+    return page
+
+
+class GeneratorInspector(object):
+    '''Inspector of generator instances'''
+
+    generators_info = {
+        ArticlesGenerator: {
+            'translations_lists': ['translations', 'drafts_translations'],
+            'contents_lists': [('articles', 'drafts')],
+            'hiding_func': article2draft,
+            'policy': 'I18N_UNTRANSLATED_ARTICLES',
+        },
+        PagesGenerator: {
+            'translations_lists': ['translations', 'hidden_translations'],
+            'contents_lists': [('pages', 'hidden_pages')],
+            'hiding_func': page2hidden_page,
+            'policy': 'I18N_UNTRANSLATED_PAGES',
+        },
+    }
+
+    def __init__(self, generator):
+        '''Identify the best known class of the generator instance
+
+        The class '''
+        self.generator = generator
+        self.generators_info.update(generator.settings.get(
+            'I18N_GENERATORS_INFO', {}))
+        for cls in generator.__class__.__mro__:
+            if cls in self.generators_info:
+                self.info = self.generators_info[cls]
+                break
+        else:
+            self.info = {}
+
+    def translations_lists(self):
+        '''Iterator over lists of content translations'''
+        return (getattr(self.generator, name) for name in
+                self.info.get('translations_lists', []))
+
+    def contents_list_pairs(self):
+        '''Iterator over pairs of normal and hidden contents'''
+        return (tuple(getattr(self.generator, name) for name in names)
+                for names in self.info.get('contents_lists', []))
+
+    def hiding_function(self):
+        '''Function for transforming content to a hidden version'''
+        hiding_func = self.info.get('hiding_func', lambda x: x)
+        return hiding_func
+
+    def untranslated_policy(self, default):
+        '''Get the policy for untranslated content'''
+        return self.generator.settings.get(self.info.get('policy', None),
+                                           default)
+
+    def all_contents(self):
+        '''Iterator over all contents'''
+        translations_iterator = chain(*self.translations_lists())
+        return chain(translations_iterator,
+                     *(pair[i] for pair in self.contents_list_pairs()
+                       for i in (0, 1)))
+
+
+def filter_contents_translations(generator):
+    '''Filter the content and translations lists of a generator
+
+    Filters out
+        1) translations which will be generated in a different site
+        2) content that is not in the language of the currently
+        generated site but in that of a different site, content in a
+        language which has no site is generated always. The filtering
+        method bay be modified by the respective untranslated policy
+    '''
+    inspector = GeneratorInspector(generator)
+    current_lang = generator.settings['DEFAULT_LANG']
+    langs_with_sites = _SITE_DB.keys()
+    removed_contents = _GENERATOR_DB[generator]
+
+    for translations in inspector.translations_lists():
+        for translation in translations[:]:    # copy to be able to remove
+            if translation.lang in langs_with_sites:
+                translations.remove(translation)
+                removed_contents.append(translation)
+
+    hiding_func = inspector.hiding_function()
+    untrans_policy = inspector.untranslated_policy(default='hide')
+    for (contents, other_contents) in inspector.contents_list_pairs():
+        for content in other_contents: # save any hidden native content first
+            if content.lang == current_lang: # in native lang
+                # save the native URL attr formatted in the current locale
+                _NATIVE_CONTENT_URL_DB[content.source_path] = content.url
+        for content in contents[:]:        # copy for removing in loop
+            if content.lang == current_lang: # in native lang
+                # save the native URL attr formatted in the current locale
+                _NATIVE_CONTENT_URL_DB[content.source_path] = content.url
+            elif content.lang in langs_with_sites and untrans_policy != 'keep':
+                contents.remove(content)
+                if untrans_policy == 'hide':
+                    other_contents.append(hiding_func(content))
+                elif untrans_policy == 'remove':
+                    removed_contents.append(content)
+
+
+def install_templates_translations(generator):
+    '''Install gettext translations in the jinja2.Environment
+
+    Only if the 'jinja2.ext.i18n' jinja2 extension is enabled
+    the translations for the current DEFAULT_LANG are installed.
+    '''
+    if 'jinja2.ext.i18n' in generator.settings['JINJA_EXTENSIONS']:
+        domain = generator.settings.get('I18N_GETTEXT_DOMAIN', 'messages')
+        localedir = generator.settings.get('I18N_GETTEXT_LOCALEDIR')
+        if localedir is None:
+            localedir = os.path.join(generator.theme, 'translations')
+        current_lang = generator.settings['DEFAULT_LANG']
+        if current_lang == generator.settings.get('I18N_TEMPLATES_LANG',
+                                                  _MAIN_LANG):
+            translations = gettext.NullTranslations()
+        else:
+            langs = [current_lang]
+            try:
+                translations = gettext.translation(domain, localedir, langs)
+            except (IOError, OSError):
+                _LOGGER.error((
+                    "Cannot find translations for language '{}' in '{}' with "
+                    "domain '{}'. Installing NullTranslations.").format(
+                        langs[0], localedir, domain))
+                translations = gettext.NullTranslations()
+        newstyle = generator.settings.get('I18N_GETTEXT_NEWSTYLE', True)
+        generator.env.install_gettext_translations(translations, newstyle)
+
+
+def add_variables_to_context(generator):
+    '''Adds useful iterable variables to template context'''
+    context = generator.context             # minimize attr lookup
+    context['relpath_to_site'] = relpath_to_site
+    context['main_siteurl'] = _MAIN_SITEURL
+    context['main_lang'] = _MAIN_LANG
+    context['lang_siteurls'] = _SITE_DB
+    current_lang = generator.settings['DEFAULT_LANG']
+    extra_siteurls = _SITE_DB.copy()
+    extra_siteurls.pop(current_lang)
+    context['extra_siteurls'] = extra_siteurls
+
+
+def interlink_translations(content):
+    '''Link content to translations in their main language
+
+    so the URL (including localized month names) of the different subsites
+    will be honored
+    '''
+    lang = content.lang
+    # sort translations by lang
+    content.translations.sort(key=attrgetter('lang'))
+    for translation in content.translations:
+        relpath = relpath_to_site(lang, translation.lang)
+        url = _NATIVE_CONTENT_URL_DB[translation.source_path]
+        translation.override_url = posixpath.join(relpath, url)
+
+
+def interlink_translated_content(generator):
+    '''Make translations link to the native locations
+
+    for generators that may contain translated content
+    '''
+    inspector = GeneratorInspector(generator)
+    for content in inspector.all_contents():
+        interlink_translations(content)
+
+
+def interlink_removed_content(generator):
+    '''For all contents removed from generation queue update interlinks
+
+    link to the native location
+    '''
+    current_lang = generator.settings['DEFAULT_LANG']
+    for content in _GENERATOR_DB[generator]:
+        url = _NATIVE_CONTENT_URL_DB[content.source_path]
+        relpath = relpath_to_site(current_lang, content.lang)
+        content.override_url = posixpath.join(relpath, url)
+
+
+def interlink_static_files(generator):
+    '''Add links to static files in the main site if necessary'''
+    if generator.settings['STATIC_PATHS'] != []:
+        return                               # customized STATIC_PATHS
+    filenames = generator.context['filenames'] # minimize attr lookup
+    relpath = relpath_to_site(generator.settings['DEFAULT_LANG'], _MAIN_LANG)
+    for staticfile in _MAIN_STATIC_FILES:
+        if staticfile.get_relative_source_path() not in filenames:
+            staticfile = copy(staticfile) # prevent override in main site
+            staticfile.override_url = posixpath.join(relpath, staticfile.url)
+            generator.add_source_path(staticfile)
+
+
+def save_main_static_files(static_generator):
+    '''Save the static files generated for the main site'''
+    global _MAIN_STATIC_FILES
+    # test just for current lang as settings change in autoreload mode
+    if static_generator.settings['DEFAULT_LANG'] == _MAIN_LANG:
+        _MAIN_STATIC_FILES = static_generator.staticfiles
+
+
+def update_generators():
+    '''Update the context of all generators
+
+    Ads useful variables and translations into the template context
+    and interlink translations
+    '''
+    for generator in _GENERATOR_DB.keys():
+        install_templates_translations(generator)
+        add_variables_to_context(generator)
+        interlink_static_files(generator)
+        interlink_removed_content(generator)
+        interlink_translated_content(generator)
+
+
+def get_pelican_cls(settings):
+    '''Get the Pelican class requested in settings'''
+    cls = settings['PELICAN_CLASS']
+    if isinstance(cls, six.string_types):
+        module, cls_name = cls.rsplit('.', 1)
+        module = __import__(module)
+        cls = getattr(module, cls_name)
+    return cls
+
+
+def create_next_subsite(pelican_obj):
+    '''Create the next subsite using the lang-specific config
+
+    If there are no more subsites in the generation queue, update all
+    the generators (interlink translations and removed content, add
+    variables and translations to template context). Otherwise get the
+    language and overrides for next the subsite in the queue and apply
+    overrides.  Then generate the subsite using a PELICAN_CLASS
+    instance and its run method. Finally, restore the previous locale.
+    '''
+    global _MAIN_SETTINGS
+    if len(_SUBSITE_QUEUE) == 0:
+        _LOGGER.debug(
+            'i18n: Updating cross-site links and context of all generators.')
+        update_generators()
+        _MAIN_SETTINGS = None             # to initialize next time
+    else:
+        with temporary_locale():
+            settings = _MAIN_SETTINGS.copy()
+            lang, overrides = _SUBSITE_QUEUE.popitem()
+            settings.update(overrides)
+            settings = configure_settings(settings)      # to set LOCALE, etc.
+            cls = get_pelican_cls(settings)
+
+            new_pelican_obj = cls(settings)
+            _LOGGER.debug(("Generating i18n subsite for language '{}' "
+                           "using class {}").format(lang, cls))
+            new_pelican_obj.run()
+
+
+# map: signal name -> function name
+_SIGNAL_HANDLERS_DB = {
+    'get_generators': initialize_plugin,
+    'article_generator_pretaxonomy': filter_contents_translations,
+    'page_generator_finalized': filter_contents_translations,
+    'get_writer': create_next_subsite,
+    'static_generator_finalized': save_main_static_files,
+    'generator_init': save_generator,
+}
+
+
+def register():
+    '''Register the plugin only if required signals are available'''
+    for sig_name in _SIGNAL_HANDLERS_DB.keys():
+        if not hasattr(signals, sig_name):
+            _LOGGER.error((
+                'The i18n_subsites plugin requires the {} '
+                'signal available for sure in Pelican 3.4.0 and later, '
+                'plugin will not be used.').format(sig_name))
+            return
+
+    for sig_name, handler in _SIGNAL_HANDLERS_DB.items():
+        sig = getattr(signals, sig_name)
+        sig.connect(handler)
diff --git a/themes/newgimp/templates/base.html b/themes/newgimp/templates/base.html
index bca908e..7afc99d 100644
--- a/themes/newgimp/templates/base.html
+++ b/themes/newgimp/templates/base.html
@@ -6,10 +6,16 @@
         <meta charset="utf-8" />
         <meta name="viewport" content="width=device-width, initial-scale=1" />
         <link rel="icon" href="/images/wilber16.png" type="image/png" />
+        {# SITEURL gets odd when using i18n, using better paths just below
         <link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/normalize.css" />
         <link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/grid.css" />
         <link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/gimp.css" />
         <link rel="stylesheet" type="text/css" href="{{ SITEURL 
}}/theme/css/font-awesome-4.4.0/css/font-awesome.min.css" />
+        #}
+        <link rel="stylesheet" type="text/css" href="/theme/css/normalize.css" />
+        <link rel="stylesheet" type="text/css" href="/theme/css/grid.css" />
+        <link rel="stylesheet" type="text/css" href="/theme/css/gimp.css" />
+        <link rel="stylesheet" type="text/css" href="/theme/css/font-awesome-4.4.0/css/font-awesome.min.css" 
/>
 
         {% if FEED_ALL_ATOM %}
         <link href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" type="application/atom+xml" rel="alternate" 
title="{{ SITENAME }} Full Atom Feed" />
diff --git a/themes/newgimp/templates/home.html b/themes/newgimp/templates/home.html
index b9726a7..ffca13a 100644
--- a/themes/newgimp/templates/home.html
+++ b/themes/newgimp/templates/home.html
@@ -4,7 +4,7 @@
 
 {% block head %}
 {{ super() }}
-<link rel='stylesheet' type='text/css' href="{{ SITEURL }}/theme/css/home.css" />
+<link rel='stylesheet' type='text/css' href="/theme/css/home.css" />
 {% endblock head %}
 
 
@@ -13,7 +13,7 @@
             <div class="container">
                 <div class="intro row">
 
-                    <img id='WilberLogo' src="{{ SITEURL }}/theme/images/wilber-big.png" alt="GIMP Wilber" 
width='200' height='150'/>
+                    <img id='WilberLogo' src="/theme/images/wilber-big.png" alt="GIMP Wilber" width='200' 
height='150'/>
                     <h1>
                         <a href="{{ SITEURL }}/">GIMP</a>
                         {#<a href="{{ SITEURL }}/">{{ SITENAME }} <strong>{{ SITESUBTITLE }}</strong></a> #}
diff --git a/themes/newgimp/templates/page.html b/themes/newgimp/templates/page.html
index b5468b5..7503663 100644
--- a/themes/newgimp/templates/page.html
+++ b/themes/newgimp/templates/page.html
@@ -4,8 +4,8 @@
 
 {% block head %}
 {{ super() }}
-<link rel='stylesheet' type='text/css' href="{{ SITEURL }}/theme/css/page.css" />
-<link rel='stylesheet' type='text/css' href="{{ SITEURL }}/theme/css/pygments-default.css" />
+<link rel='stylesheet' type='text/css' href="/theme/css/page.css" />
+<link rel='stylesheet' type='text/css' href="/theme/css/pygments-default.css" />
 
 {% endblock head %}
 
@@ -44,7 +44,6 @@
         <small>
             <p>
                 url: {{ page.url }} <br/>
-                metadata regex test: {{ page.test }}<br/>
                 slug: {{ page.slug }}<br/>
                 {% if page.parent %}
                 page parent: {{ page.parent }}<br/>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]