i18n_subsites.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. """i18n_subsites plugin creates i18n-ized subsites of the default site"""
  2. import os
  3. import six
  4. import logging
  5. from itertools import chain
  6. from pelican import signals, Pelican
  7. from pelican.contents import Page, Article
  8. from ._regenerate_context_helpers import regenerate_context_articles
  9. # Global vars
  10. _main_site_generated = False
  11. _main_site_lang = "en"
  12. logger = logging.getLogger(__name__)
  13. def disable_lang_vars(pelican_obj):
  14. """Set lang specific url and save_as vars to the non-lang defaults
  15. e.g. ARTICLE_LANG_URL = ARTICLE_URL
  16. They would conflict with this plugin otherwise
  17. """
  18. s = pelican_obj.settings
  19. for content in ['ARTICLE', 'PAGE']:
  20. for meta in ['_URL', '_SAVE_AS']:
  21. s[content + '_LANG' + meta] = s[content + meta]
  22. def create_lang_subsites(pelican_obj):
  23. """For each language create a subsite using the lang-specific config
  24. for each generated lang append language subpath to SITEURL and OUTPUT_PATH
  25. and set DEFAULT_LANG to the language code to change perception of what is translated
  26. and set DELETE_OUTPUT_DIRECTORY to False to prevent deleting output from previous runs
  27. Then generate the subsite using a PELICAN_CLASS instance and its run method.
  28. """
  29. global _main_site_generated, _main_site_lang
  30. if _main_site_generated: # make sure this is only called once
  31. return
  32. else:
  33. _main_site_generated = True
  34. orig_settings = pelican_obj.settings
  35. _main_site_lang = orig_settings['DEFAULT_LANG']
  36. for lang, overrides in orig_settings.get('I18N_SUBSITES', {}).items():
  37. settings = orig_settings.copy()
  38. settings.update(overrides)
  39. settings['SITEURL'] = orig_settings['SITEURL'] + '/' + lang
  40. settings['OUTPUT_PATH'] = os.path.join(orig_settings['OUTPUT_PATH'], lang, '')
  41. settings['DEFAULT_LANG'] = lang # to change what is perceived as translations
  42. settings['DELETE_OUTPUT_DIRECTORY'] = False # prevent deletion of previous runs
  43. cls = settings['PELICAN_CLASS']
  44. if isinstance(cls, six.string_types):
  45. module, cls_name = cls.rsplit('.', 1)
  46. module = __import__(module)
  47. cls = getattr(module, cls_name)
  48. pelican_obj = cls(settings)
  49. logger.debug("Generating i18n subsite for lang '{}' using class '{}'".format(lang, str(cls)))
  50. pelican_obj.run()
  51. def move_translations_links(content_object):
  52. """This function points translations links to the sub-sites
  53. by prepending their location with the language code
  54. or directs an original DEFAULT_LANG translation back to top level site
  55. """
  56. for translation in content_object.translations:
  57. if translation.lang == _main_site_lang:
  58. # cannot prepend, must take to top level
  59. lang_prepend = '../'
  60. else:
  61. lang_prepend = translation.lang + '/'
  62. translation.override_url = lang_prepend + translation.url
  63. def update_generator_contents(generator, *args):
  64. """Update the contents lists of a generator
  65. Empty the (hidden_)translation attribute of article and pages generators
  66. to prevent generating the translations as they will be generated in the lang sub-site
  67. and point the content translations links to the sub-sites
  68. Hide content without a translation for current DEFAULT_LANG
  69. if HIDE_UNTRANSLATED_CONTENT is True
  70. """
  71. generator.translations = []
  72. is_pages_gen = hasattr(generator, 'pages')
  73. if is_pages_gen:
  74. generator.hidden_translations = []
  75. for page in chain(generator.pages, generator.hidden_pages):
  76. move_translations_links(page)
  77. else: # is an article generator
  78. for article in chain(generator.articles, generator.drafts):
  79. move_translations_links(article)
  80. if not generator.settings.get('HIDE_UNTRANSLATED_CONTENT', True):
  81. return
  82. contents = generator.pages if is_pages_gen else generator.articles
  83. hidden_contents = generator.hidden_pages if is_pages_gen else generator.drafts
  84. default_lang = generator.settings['DEFAULT_LANG']
  85. for content_object in contents:
  86. if content_object.lang != default_lang:
  87. if isinstance(content_object, Page):
  88. content_object.status = 'hidden'
  89. elif isinstance(content_object, Article):
  90. content_object.status = 'draft'
  91. contents.remove(content_object)
  92. hidden_contents.append(content_object)
  93. if not is_pages_gen: # regenerate categories, tags, etc. for articles
  94. if hasattr(generator, '_generate_context_aggregate'): # if implemented
  95. # Simulate __init__ for fields that need it
  96. generator.dates = {}
  97. generator.tags = defaultdict(list)
  98. generator.categories = defaultdict(list)
  99. generator.authors = defaultdict(list)
  100. generator._generate_context_aggregate()
  101. else: # fallback for Pelican 3.3.0
  102. regenerate_context_articles(generator)
  103. def register():
  104. signals.initialized.connect(disable_lang_vars)
  105. signals.article_generator_finalized.connect(update_generator_contents)
  106. signals.page_generator_finalized.connect(update_generator_contents)
  107. signals.finalized.connect(create_lang_subsites)