2014-01-31 10:06:52 +01:00
""" i18n_subsites plugin creates i18n-ized subsites of the default site """
import os
import six
import logging
from itertools import chain
2014-02-01 20:13:32 +01:00
from collections import defaultdict
2014-01-31 10:06:52 +01:00
2014-02-01 20:13:32 +01:00
import gettext
from pelican import signals
2014-01-31 10:06:52 +01:00
from pelican . contents import Page , Article
from . _regenerate_context_helpers import regenerate_context_articles
# Global vars
_main_site_generated = False
_main_site_lang = " en "
2014-02-01 20:13:32 +01:00
_main_siteurl = ' '
2014-01-31 10:06:52 +01:00
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
"""
2014-02-01 20:13:32 +01:00
global _main_site_lang , _main_siteurl
2014-01-31 10:06:52 +01:00
s = pelican_obj . settings
for content in [ ' ARTICLE ' , ' PAGE ' ] :
for meta in [ ' _URL ' , ' _SAVE_AS ' ] :
s [ content + ' _LANG ' + meta ] = s [ content + meta ]
2014-02-01 20:13:32 +01:00
if not _main_site_generated :
_main_site_lang = s [ ' DEFAULT_LANG ' ]
_main_siteurl = s [ ' SITEURL ' ]
2014-01-31 10:06:52 +01:00
2014-02-01 20:13:32 +01:00
2014-01-31 10:06:52 +01:00
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 .
"""
2014-02-01 20:13:32 +01:00
global _main_site_generated
2014-01-31 10:06:52 +01:00
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 )
2014-02-01 20:13:32 +01:00
settings [ ' SITEURL ' ] = _main_siteurl + ' / ' + lang
2014-01-31 10:06:52 +01:00
settings [ ' OUTPUT_PATH ' ] = os . path . join ( orig_settings [ ' OUTPUT_PATH ' ] , lang , ' ' )
settings [ ' DEFAULT_LANG ' ] = lang # to change what is perceived as translations
2014-02-01 20:13:32 +01:00
settings [ ' DELETE_OUTPUT_DIRECTORY ' ] = False # prevent deletion of previous runs
2014-01-31 10:06:52 +01:00
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 )
2014-02-01 20:13:32 +01:00
2014-01-31 10:06:52 +01:00
if not generator . settings . get ( ' HIDE_UNTRANSLATED_CONTENT ' , True ) :
return
contents = generator . pages if is_pages_gen else generator . articles
2014-02-01 20:13:32 +01:00
hidden_contents = generator . hidden_pages if is_pages_gen else generator . drafts
2014-01-31 10:06:52 +01:00
default_lang = generator . settings [ ' DEFAULT_LANG ' ]
2014-02-04 14:14:43 +01:00
for content_object in contents [ : ] : # loop over copy for removing
2014-01-31 10:06:52 +01:00
if content_object . lang != default_lang :
2014-02-04 14:14:43 +01:00
if isinstance ( content_object , Article ) :
2014-02-01 20:13:32 +01:00
content_object . status = ' draft '
2014-02-04 14:14:43 +01:00
elif isinstance ( content_object , Page ) :
content_object . status = ' hidden '
2014-01-31 10:06:52 +01:00
contents . remove ( content_object )
hidden_contents . append ( content_object )
if not is_pages_gen : # regenerate categories, tags, etc. for articles
2014-02-01 20:13:32 +01:00
if hasattr ( generator , ' _generate_context_aggregate ' ) : # if implemented
2014-01-31 10:06:52 +01:00
# 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 )
2014-02-01 20:13:32 +01:00
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
2014-02-03 19:23:43 +01:00
current_def_lang = generator . settings [ ' DEFAULT_LANG ' ]
extra_siteurls . pop ( current_def_lang )
2014-02-01 20:13:32 +01:00
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/ ' )
2014-02-03 19:23:43 +01:00
if current_def_lang == generator . settings . get ( ' I18N_TEMPLATES_LANG ' , _main_site_lang ) :
2014-02-01 20:13:32 +01:00
translations = gettext . NullTranslations ( )
2014-02-03 19:23:43 +01:00
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 ( )
2014-02-01 20:13:32 +01:00
newstyle = generator . settings . get ( ' I18N_GETTEXT_NEWSTYLE ' , True )
generator . env . install_gettext_translations ( translations , newstyle )
2014-01-31 10:06:52 +01:00
def register ( ) :
signals . initialized . connect ( disable_lang_vars )
2014-02-01 20:13:32 +01:00
signals . generator_init . connect ( install_templates_translations )
2014-01-31 10:06:52 +01:00
signals . article_generator_finalized . connect ( update_generator_contents )
signals . page_generator_finalized . connect ( update_generator_contents )
signals . finalized . connect ( create_lang_subsites )