pelican-i18n_subsites/i18n_subsites.py
Ondrej Grover 0c172ba023 i18n_subsites: consider templates lang, expand docs
this commit removes the need to make a dummy translation for
the language in which the templates are written.
This only affects themes using jinja2.ext.i18n.
The I18N_THEMES_LANG is introduced to address this issue.

Also expanded the docs for making gettext .po files with babel.
2014-02-03 20:04:40 +01:00

182 lines
7.1 KiB
Python

"""i18n_subsites plugin creates i18n-ized subsites of the default site"""
import os
import six
import logging
from itertools import chain
from collections import defaultdict
import gettext
from pelican import signals
from pelican.contents import Page, Article
from ._regenerate_context_helpers import regenerate_context_articles
# Global vars
_main_site_generated = False
_main_site_lang = "en"
_main_siteurl = ''
logger = logging.getLogger(__name__)
def disable_lang_vars(pelican_obj):
"""Set lang specific url and save_as vars to the non-lang defaults
e.g. ARTICLE_LANG_URL = ARTICLE_URL
They would conflict with this plugin otherwise
"""
global _main_site_lang, _main_siteurl
s = pelican_obj.settings
for content in ['ARTICLE', 'PAGE']:
for meta in ['_URL', '_SAVE_AS']:
s[content + '_LANG' + meta] = s[content + meta]
if not _main_site_generated:
_main_site_lang = s['DEFAULT_LANG']
_main_siteurl = s['SITEURL']
def create_lang_subsites(pelican_obj):
"""For each language create a subsite using the lang-specific config
for each generated lang append language subpath to SITEURL and OUTPUT_PATH
and set DEFAULT_LANG to the language code to change perception of what is translated
and set DELETE_OUTPUT_DIRECTORY to False to prevent deleting output from previous runs
Then generate the subsite using a PELICAN_CLASS instance and its run method.
"""
global _main_site_generated
if _main_site_generated: # make sure this is only called once
return
else:
_main_site_generated = True
orig_settings = pelican_obj.settings
for lang, overrides in orig_settings.get('I18N_SUBSITES', {}).items():
settings = orig_settings.copy()
settings.update(overrides)
settings['SITEURL'] = _main_siteurl + '/' + lang
settings['OUTPUT_PATH'] = os.path.join(orig_settings['OUTPUT_PATH'], lang, '')
settings['DEFAULT_LANG'] = lang # to change what is perceived as translations
settings['DELETE_OUTPUT_DIRECTORY'] = False # prevent deletion of previous runs
cls = settings['PELICAN_CLASS']
if isinstance(cls, six.string_types):
module, cls_name = cls.rsplit('.', 1)
module = __import__(module)
cls = getattr(module, cls_name)
pelican_obj = cls(settings)
logger.debug("Generating i18n subsite for lang '{}' using class '{}'".format(lang, str(cls)))
pelican_obj.run()
def move_translations_links(content_object):
"""This function points translations links to the sub-sites
by prepending their location with the language code
or directs an original DEFAULT_LANG translation back to top level site
"""
for translation in content_object.translations:
if translation.lang == _main_site_lang:
# cannot prepend, must take to top level
lang_prepend = '../'
else:
lang_prepend = translation.lang + '/'
translation.override_url = lang_prepend + translation.url
def update_generator_contents(generator, *args):
"""Update the contents lists of a generator
Empty the (hidden_)translation attribute of article and pages generators
to prevent generating the translations as they will be generated in the lang sub-site
and point the content translations links to the sub-sites
Hide content without a translation for current DEFAULT_LANG
if HIDE_UNTRANSLATED_CONTENT is True
"""
generator.translations = []
is_pages_gen = hasattr(generator, 'pages')
if is_pages_gen:
generator.hidden_translations = []
for page in chain(generator.pages, generator.hidden_pages):
move_translations_links(page)
else: # is an article generator
for article in chain(generator.articles, generator.drafts):
move_translations_links(article)
if not generator.settings.get('HIDE_UNTRANSLATED_CONTENT', True):
return
contents = generator.pages if is_pages_gen else generator.articles
hidden_contents = generator.hidden_pages if is_pages_gen else generator.drafts
default_lang = generator.settings['DEFAULT_LANG']
for content_object in contents:
if content_object.lang != default_lang:
if isinstance(content_object, Page):
content_object.status = 'hidden'
elif isinstance(content_object, Article):
content_object.status = 'draft'
contents.remove(content_object)
hidden_contents.append(content_object)
if not is_pages_gen: # regenerate categories, tags, etc. for articles
if hasattr(generator, '_generate_context_aggregate'): # if implemented
# Simulate __init__ for fields that need it
generator.dates = {}
generator.tags = defaultdict(list)
generator.categories = defaultdict(list)
generator.authors = defaultdict(list)
generator._generate_context_aggregate()
else: # fallback for Pelican 3.3.0
regenerate_context_articles(generator)
def install_templates_translations(generator):
"""Install gettext translations for current DEFAULT_LANG in the jinja2.Environment
if the 'jinja2.ext.i18n' jinja2 extension is enabled
adds some useful variables into the template context
"""
generator.context['main_siteurl'] = _main_siteurl
generator.context['main_lang'] = _main_site_lang
extra_siteurls = { lang: _main_siteurl + '/' + lang for lang in generator.settings.get('I18N_SUBSITES', {}).keys() }
extra_siteurls[_main_site_lang] = _main_siteurl
current_def_lang = generator.settings['DEFAULT_LANG']
extra_siteurls.pop(current_def_lang)
generator.context['extra_siteurls'] = extra_siteurls
if 'jinja2.ext.i18n' not in generator.settings['JINJA_EXTENSIONS']:
return
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/')
if current_def_lang == generator.settings.get('I18N_TEMPLATES_LANG', _main_site_lang):
translations = gettext.NullTranslations()
else:
languages = [current_def_lang]
try:
translations = gettext.translation(domain, localedir, languages)
except (IOError, OSError):
logger.error("Cannot find translations for language '{}' in '{}' with domain '{}'. Installing NullTranslations.".format(languages[0], localedir, domain))
translations = gettext.NullTranslations()
newstyle = generator.settings.get('I18N_GETTEXT_NEWSTYLE', True)
generator.env.install_gettext_translations(translations, newstyle)
def register():
signals.initialized.connect(disable_lang_vars)
signals.generator_init.connect(install_templates_translations)
signals.article_generator_finalized.connect(update_generator_contents)
signals.page_generator_finalized.connect(update_generator_contents)
signals.finalized.connect(create_lang_subsites)