diff options
Diffstat (limited to 'nikola')
32 files changed, 462 insertions, 393 deletions
diff --git a/nikola/__init__.py b/nikola/__init__.py index 34396c9..e085f91 100644 --- a/nikola/__init__.py +++ b/nikola/__init__.py @@ -29,7 +29,7 @@ import os import sys -__version__ = '8.1.3' +__version__ = '8.2.0' DEBUG = bool(os.getenv('NIKOLA_DEBUG')) SHOW_TRACEBACKS = bool(os.getenv('NIKOLA_SHOW_TRACEBACKS')) diff --git a/nikola/conf.py.in b/nikola/conf.py.in index fcb2d28..d209eb4 100644 --- a/nikola/conf.py.in +++ b/nikola/conf.py.in @@ -317,6 +317,7 @@ COMPILERS = ${COMPILERS} # Set descriptions for tag pages to make them more interesting. The # default is no description. The value is used in the meta description # and displayed underneath the tag list or index page’s title. +# (translatable) # TAG_DESCRIPTIONS = { # DEFAULT_LANG: { # "blogging": "Meta-blog posts about blogging.", @@ -325,6 +326,7 @@ COMPILERS = ${COMPILERS} # } # Set special titles for tag pages. The default is "Posts about TAG". +# (translatable) # TAG_TITLES = { # DEFAULT_LANG: { # "blogging": "Meta-posts about blogging", @@ -390,6 +392,7 @@ CATEGORY_OUTPUT_FLAT_HIERARCHY = ${CATEGORY_OUTPUT_FLAT_HIERARCHY} # Set descriptions for category pages to make them more interesting. The # default is no description. The value is used in the meta description # and displayed underneath the category list or index page’s title. +# (translatable) # CATEGORY_DESCRIPTIONS = { # DEFAULT_LANG: { # "blogging": "Meta-blog posts about blogging.", @@ -398,6 +401,7 @@ CATEGORY_OUTPUT_FLAT_HIERARCHY = ${CATEGORY_OUTPUT_FLAT_HIERARCHY} # } # Set special titles for category pages. The default is "Posts about CATEGORY". +# (translatable) # CATEGORY_TITLES = { # DEFAULT_LANG: { # "blogging": "Meta-posts about blogging", @@ -478,8 +482,8 @@ HIDDEN_CATEGORIES = [] # If you do not want to display an author publicly, you can mark it as hidden. -# The author will not be displayed on the author list page and posts. -# Tag pages will still be generated. +# The author will not be displayed on the author list page. +# Author pages and links to them will still be generated. HIDDEN_AUTHORS = ['Guest'] # Allow multiple, comma-separated authors for a post? (Requires theme support, present in built-in themes) @@ -570,7 +574,7 @@ REDIRECTIONS = ${REDIRECTIONS} # Presets of commands to execute to deploy. Can be anything, for # example, you may use rsync: -# "rsync -rav --delete output/ joe@my.site:/srv/www/site" +# "rsync -rav --delete --delete-after output/ joe@my.site:/srv/www/site" # And then do a backup, or run `nikola ping` from the `ping` # plugin (`nikola plugin -i ping`). Or run `nikola check -l`. # You may also want to use github_deploy (see below). @@ -580,7 +584,7 @@ REDIRECTIONS = ${REDIRECTIONS} # in a `nikola deploy` command as you like. # DEPLOY_COMMANDS = { # 'default': [ -# "rsync -rav --delete output/ joe@my.site:/srv/www/site", +# "rsync -rav --delete --delete-after output/ joe@my.site:/srv/www/site", # ] # } @@ -765,6 +769,7 @@ GALLERIES_DEFAULT_THUMBNAIL = None # options, but will have to be referenced manually to be visible on the site # (the thumbnail has ``.thumbnail`` added before the file extension by default, # but a different naming template can be configured with IMAGE_THUMBNAIL_FORMAT). +# Panoramas (aspect ratio over 3:1) get 4x larger thumbnails due to scaling issues. IMAGE_FOLDERS = {'images': 'images'} # IMAGE_THUMBNAIL_SIZE = 400 diff --git a/nikola/data/themes/base-jinja/templates/base_helper.tmpl b/nikola/data/themes/base-jinja/templates/base_helper.tmpl index a05abb9..2d8c0c8 100644 --- a/nikola/data/themes/base-jinja/templates/base_helper.tmpl +++ b/nikola/data/themes/base-jinja/templates/base_helper.tmpl @@ -82,7 +82,7 @@ lang="{{ lang }}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.{{ luxon_locales[lang] }}"></script> {% endif %} {% if use_cdn %} - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> {% else %} <script src="/assets/js/luxon.min.js"></script> {% endif %} diff --git a/nikola/data/themes/base-jinja/templates/comments_helper.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper.tmpl index 2a7d8dc..4b50485 100644 --- a/nikola/data/themes/base-jinja/templates/comments_helper.tmpl +++ b/nikola/data/themes/base-jinja/templates/comments_helper.tmpl @@ -1,63 +1,15 @@ {# -*- coding: utf-8 -*- #} -{% import 'comments_helper_disqus.tmpl' as disqus with context %} -{% import 'comments_helper_intensedebate.tmpl' as intensedebate with context %} -{% import 'comments_helper_muut.tmpl' as muut with context %} -{% import 'comments_helper_facebook.tmpl' as facebook with context %} -{% import 'comments_helper_isso.tmpl' as isso with context %} -{% import 'comments_helper_commento.tmpl' as commento with context %} -{% import 'comments_helper_utterances.tmpl' as utterances with context %} +{% import 'comments_helper_%s.tmpl' % comment_system as comments_helper_impl with context %} {% macro comment_form(url, title, identifier) %} - {% if comment_system == 'disqus' %} - {{ disqus.comment_form(url, title, identifier) }} - {% elif comment_system == 'intensedebate' %} - {{ intensedebate.comment_form(url, title, identifier) }} - {% elif comment_system == 'muut' %} - {{ muut.comment_form(url, title, identifier) }} - {% elif comment_system == 'facebook' %} - {{ facebook.comment_form(url, title, identifier) }} - {% elif comment_system == 'isso' %} - {{ isso.comment_form(url, title, identifier) }} - {% elif comment_system == 'commento' %} - {{ commento.comment_form(url, title, identifier) }} - {% elif comment_system == 'utterances' %} - {{ utterances.comment_form(url, title, identifier) }} - {% endif %} + {{ comments_helper_impl.comment_form(url, title, identifier) }} {% endmacro %} {% macro comment_link(link, identifier) %} - {% if comment_system == 'disqus' %} - {{ disqus.comment_link(link, identifier) }} - {% elif comment_system == 'intensedebate' %} - {{ intensedebate.comment_link(link, identifier) }} - {% elif comment_system == 'muut' %} - {{ muut.comment_link(link, identifier) }} - {% elif comment_system == 'facebook' %} - {{ facebook.comment_link(link, identifier) }} - {% elif comment_system == 'isso' %} - {{ isso.comment_link(link, identifier) }} - {% elif comment_system == 'commento' %} - {{ commento.comment_link(link, identifier) }} - {% elif comment_system == 'utterances' %} - {{ utterances.comment_link(link, identifier) }} - {% endif %} + {{ comments_helper_impl.comment_link(link, identifier) }} {% endmacro %} {% macro comment_link_script() %} - {% if comment_system == 'disqus' %} - {{ disqus.comment_link_script() }} - {% elif comment_system == 'intensedebate' %} - {{ intensedebate.comment_link_script() }} - {% elif comment_system == 'muut' %} - {{ muut.comment_link_script() }} - {% elif comment_system == 'facebook' %} - {{ facebook.comment_link_script() }} - {% elif comment_system == 'isso' %} - {{ isso.comment_link_script() }} - {% elif comment_system == 'commento' %} - {{ commento.comment_link_script() }} - {% elif comment_system == 'utterances' %} - {{ utterances.comment_link_script() }} - {% endif %} + {{ comments_helper_impl.comment_link_script() }} {% endmacro %} diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_dummy.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_dummy.tmpl new file mode 100644 index 0000000..5ae1edb --- /dev/null +++ b/nikola/data/themes/base-jinja/templates/comments_helper_dummy.tmpl @@ -0,0 +1,10 @@ +{# -*- coding: utf-8 -*- #} + +{% macro comment_form(url, title, identifier) %} +{% endmacro %} + +{% macro comment_link(link, identifier) %} +{% endmacro %} + +{% macro comment_link_script() %} +{% endmacro %} diff --git a/nikola/data/themes/base/assets/css/rst_base.css b/nikola/data/themes/base/assets/css/rst_base.css index 429f7b5..51f92b4 100644 --- a/nikola/data/themes/base/assets/css/rst_base.css +++ b/nikola/data/themes/base/assets/css/rst_base.css @@ -1,7 +1,7 @@ /* Minimal style sheet for the HTML output of Docutils. */ /* */ /* :Author: Günter Milde, based on html4css1.css by David Goodger */ -/* :Id: $Id: minimal.css 7952 2016-07-26 18:15:59Z milde $ */ +/* :Id: $Id: minimal.css 8642 2021-03-26 13:51:14Z milde $ */ /* :Copyright: © 2015 Günter Milde. */ /* :License: Released under the terms of the `2-Clause BSD license`_, */ /* in short: */ @@ -20,83 +20,66 @@ /* .. _CSS2.1: http://www.w3.org/TR/CSS2 */ /* .. _validates: http://jigsaw.w3.org/css-validator/validator$link */ -/* alignment of text and inline objects inside block objects*/ -.align-left { text-align: left; } -.align-right { text-align: right; } -.align-center { clear: both; text-align: center; } -.align-top { vertical-align: top; } -.align-middle { vertical-align: middle; } -.align-bottom { vertical-align: bottom; } - /* titles */ -h1.title, p.subtitle { - text-align: center; -} -p.admonition-title, p.topic-title, -p.sidebar-title, -p.rubric, +p.admonition-title, p.system-message-title { font-weight: bold; } -h1 + p.subtitle, -h1 + p.section-subtitle { - font-size: 1.6em; +p.sidebar-title, +p.rubric { + font-weight: bold; + font-size: larger; +} +p.rubric { + color: maroon; } -h2 + p.section-subtitle { font-size: 1.28em; } p.subtitle, p.section-subtitle, p.sidebar-subtitle { font-weight: bold; margin-top: -0.5em; } -p.sidebar-title, -p.rubric { - font-size: larger; +h1 + p.subtitle { + font-size: 1.6em; } -p.rubric { color: maroon; } -a.toc-backref { +h2 + p.section-subtitle, a.toc-backref { color: black; - text-decoration: none; } + text-decoration: none; +} /* Warnings, Errors */ -div.caution p.admonition-title, -div.attention p.admonition-title, -div.danger p.admonition-title, -div.error p.admonition-title, -div.warning p.admonition-title, -div.system-messages h1, -div.error, -span.problematic, -p.system-message-title { +.system-messages h2, +.system-message-title, +span.problematic { color: red; } -/* inline literals */ -span.docutils.literal { +/* Inline Literals */ +.docutils.literal { font-family: monospace; white-space: pre-wrap; } -/* do not wraph at hyphens and similar: */ +/* do not wrap at hyphens and similar: */ .literal > span.pre { white-space: nowrap; } /* Lists */ /* compact and simple lists: no margin between items */ -.simple li, .compact li, -.simple ul, .compact ul, -.simple ol, .compact ol, -.simple > li p, .compact > li p, -dl.simple > dd, dl.compact > dd { +.simple li, .simple ul, .simple ol, +.compact li, .compact ul, .compact ol, +.simple > li p, dl.simple > dd, +.compact > li p, dl.compact > dd { margin-top: 0; margin-bottom: 0; } /* Table of Contents */ -/*div.topic.contents { margin: 0; }*/ -ul.auto-toc { +.topic.contents { margin: 0.5em 0; } +.topic.contents ul.auto-toc { list-style-type: none; - padding-left: 1.5em; } + padding-left: 1.5em; +} /* Enumerated Lists */ ol.arabic { list-style: decimal } @@ -105,14 +88,14 @@ ol.upperalpha { list-style: upper-alpha } ol.lowerroman { list-style: lower-roman } ol.upperroman { list-style: upper-roman } -dt span.classifier { font-style: italic } -dt span.classifier:before { +/* Definition Lists and Derivatives */ +dt .classifier { font-style: italic } +dt .classifier:before { font-style: normal; margin: 0.5em; content: ":"; } - -/* Field Lists and drivatives */ +/* Field Lists and similar */ /* bold field name, content starts on the same line */ dl.field-list > dt, dl.option-list > dt, @@ -130,7 +113,7 @@ dl.citation > dt { dl.field-list > dd, dl.option-list > dd, dl.docinfo > dd { - margin-left: 9em; /* ca. 14 chars in the test examples */ + margin-left: 9em; /* ca. 14 chars in the test examples, fit all Docinfo fields */ } /* start field-body on a new line after long field names */ dl.field-list > dd > *:first-child, @@ -147,18 +130,20 @@ dl.docinfo > dt:after { } /* Bibliographic Fields (docinfo) */ -pre.address { font: inherit; } -dd.authors > p { margin: 0; } +dl.docinfo pre.address { + font: inherit; + margin: 0.5em 0; +} +dl.docinfo > dd.authors > p { margin: 0; } /* Option Lists */ -dl.option-list { margin-left: 40px; } dl.option-list > dt { font-weight: normal; } span.option { white-space: nowrap; } /* Footnotes and Citations */ -dl.footnote.superscript > dd {margin-left: 1em; } -dl.footnote.brackets > dd {margin-left: 2em; } -dl > dt.label { font-weight: normal; } +dl.footnote.superscript > dd { margin-left: 1em; } +dl.footnote.brackets > dd { margin-left: 2em; } +dl.footnote > dt { font-weight: normal; } a.footnote-reference.brackets:before, dt.label > span.brackets:before { content: "["; } a.footnote-reference.brackets:after, @@ -166,94 +151,74 @@ dt.label > span.brackets:after { content: "]"; } a.footnote-reference.superscript, dl.footnote.superscript > dt.label { vertical-align: super; - font-size: smaller; + font-size: small; } -dt.label > span.fn-backref { margin-left: 0.2em; } -dt.label > span.fn-backref > a { font-style: italic; } - -/* Line Blocks */ -div.line-block { display: block; } -div.line-block div.line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 40px; +dt.label > span.fn-backref { + margin-left: 0.2em; + font-weight: normal; } +dt.label > span.fn-backref > a { font-style: italic; } -/* Figures, Images, and Tables */ -.figure.align-left, -img.align-left, -object.align-left, -table.align-left { - margin-right: auto; -} -.figure.align-center, -img.align-center, -object.align-center { - margin-left: auto; +/* Alignment */ +.align-left { + text-align: left; margin-right: auto; - display: block; } -table.align-center { +.align-center { + clear: both; + text-align: center; margin-left: auto; margin-right: auto; } -.figure.align-right, -img.align-right, -object.align-right, -table.align-right { +.align-right { + text-align: right; margin-left: auto; } -/* reset inner alignment in figures and tables */ -div.align-left, div.align-center, div.align-right, -table.align-left, table.align-center, table.align-right -{ text-align: inherit } +.align-top { vertical-align: top; } +.align-middle { vertical-align: middle; } +.align-bottom { vertical-align: bottom; } -/* Admonitions and System Messages */ -div.admonition, -div.system-message, -div.sidebar{ - margin: 40px; - border: medium outset; - padding-right: 1em; - padding-left: 1em; +/* reset inner alignment in figures and tables */ +figure.align-left, figure.align-right, +table.align-left, table.align-center, table.align-right { + text-align: inherit; } -/* Sidebar */ -div.sidebar { +/* Text Blocks */ +blockquote, +div.topic, +aside.topic { + margin: 1em 2em; +} +.sidebar, +.admonition, +.system-message { + border: thin solid; + margin: 1em 2em; + padding: 0.5em 1em; +} +.sidebar { width: 30%; max-width: 26em; float: right; clear: right; } +div.line-block { display: block; } +div.line-block div.line-block, pre { margin-left: 2em; } -/* Text Blocks */ -div.topic, -pre.literal-block, -pre.doctest-block, -pre.math, -pre.code { - margin-right: 40px; - margin-left: 40px; +/* Code line numbers: dropped when copying text from the page */ +pre.code .ln { display: none; } +pre.code code:before { + content: attr(data-lineno); /* …, none) fallback not supported by any browser */ + color: gray; } -pre.code .ln { color: gray; } /* line numbers */ /* Tables */ -table.docutils { border-collapse: collapse; } -table.docutils > td, table.docutils > th { - border-style: solid; - border-color: silver; - padding: 0 1ex; - border-width: thin; -} -table.docutils > td > p:first-child, table.docutils > th > p:first-child { margin-top: 0; } -table.docutils > td > p, table.docutils > th > p { margin-bottom: 0; } -table.docutils > caption { - text-align: left; - margin-bottom: 0.25em -} +td > p:first-child, th > p:first-child { margin-top: 0; } +td > p, th > p { margin-bottom: 0; } -table.borderless td, table.borderless th { +.borderless td, .borderless th { border: 0; padding: 0; padding-right: 0.5em /* separate table cells */ @@ -263,7 +228,7 @@ table.borderless td, table.borderless th { /* Rules for easy reading and pre-defined style variants. */ /* */ /* :Author: Günter Milde, based on html4css1.css by David Goodger */ -/* :Id: $Id: plain.css 7952 2016-07-26 18:15:59Z milde $ */ +/* :Id: $Id: plain.css 8636 2021-03-19 00:23:33Z milde $ */ /* :Copyright: © 2015 Günter Milde. */ /* :License: Released under the terms of the `2-Clause BSD license`_, */ /* in short: */ @@ -281,10 +246,7 @@ table.borderless td, table.borderless th { /* Document Structure */ /* ****************** */ -/* Sections */ - /* Transitions */ - hr.docutils { width: 80%; margin-top: 1em; @@ -292,32 +254,19 @@ hr.docutils { clear: both; } -/* Paragraphs */ -/* ========== */ - -/* vertical space (parskip) */ -/*p, ol, ul, dl,*/ -/*div.line-block,*/ -/*table{*/ - /*margin-top: 0.5em;*/ - /*margin-bottom: 0.5em;*/ -/*}*/ -/*h1, h2, h3, h4, h5, h6, */ dl > dd { margin-bottom: 0.5em; } -/* Lists */ -/* ========== */ - -/* Definition Lists */ +/* Lists */ +/* ===== */ -dl > dd p:first-child { margin-top: 0; } -/* :last-child is not part of CSS 2.1 (introduced in CSS 3) */ -/* dl > dd p:last-child { margin-bottom: 0; } */ +/* Separate list entries in compound lists */ +dl > dd, ol > li, -/* lists nested in definition lists */ -/* :only-child is not part of CSS 2.1 (introduced in CSS 3) */ +/* Definition Lists */ +/* Indent lists nested in definition lists */ +/* (:only-child is new in CSS 3) */ dd > ul:only-child, dd > ol:only-child { padding-left: 1em; } /* Description Lists */ @@ -358,31 +307,16 @@ div.dedication p.topic-title { font-style: normal; } -/* Citations */ -dl.citation dt.label { - font-weight: bold; -} -span.fn-backref { - font-weight: normal; -} - -/* Text Blocks */ -/* ============ */ +/* Text Blocks */ +/* =========== */ -/* Literal Blocks */ +/* Literal Blocks */ pre.literal-block, pre.doctest-block, pre.math, pre.code { - margin-left: 1.5em; - margin-right: 1.5em + font-family: monospace; } -/* Block Quotes */ - -blockquote, -div.topic { - margin-left: 1.5em; - margin-right: 1.5em -} +/* Block Quotes */ blockquote > table, div.topic > table { margin-top: 0; @@ -394,8 +328,8 @@ div.topic p.attribution { margin-left: 20%; } -/* Tables */ -/* ====== */ +/* Tables */ +/* ====== */ /* th { vertical-align: bottom; } */ @@ -422,11 +356,11 @@ table.numbered > caption:before { font-weight: bold; } -/* Explicit Markup Blocks */ -/* ====================== */ +/* Explicit Markup Blocks */ +/* ====================== */ -/* Footnotes and Citations */ -/* ----------------------- */ +/* Footnotes and Citations */ +/* ----------------------- */ /* line on the left */ dl.footnote { @@ -435,40 +369,56 @@ dl.footnote { border-left-width: thin; } -/* Directives */ -/* ---------- */ +/* Directives */ +/* ---------- */ -/* Body Elements */ -/* ~~~~~~~~~~~~~ */ +/* Body Elements */ +/* ~~~~~~~~~~~~~ */ /* Images and Figures */ /* let content flow to the side of aligned images and figures */ -.figure.align-left, +figure.align-left, img.align-left, +video.align-left, object.align-left { - display: block; clear: left; float: left; - margin-right: 1em + margin-right: 1em; } -.figure.align-right, +figure.align-right, img.align-right, +video.align-right, object.align-right { - display: block; clear: right; float: right; - margin-left: 1em + margin-left: 1em; } -/* Sidebar */ +/* Numbered figures */ +figure.numbered > figcaption > p:before { + counter-increment: figure; + content: "Figure " counter(figure) ": "; + font-weight: bold; +} -/* Move into the margin. In a layout with fixed margins, */ -/* it can be moved into the margin completely. */ -div.sidebar { +/* Admonitions and System Messages */ +.caution p.admonition-title, +.attention p.admonition-title, +.danger p.admonition-title, +.error p.admonition-title, +.warning p.admonition-title, +div.error { + color: red; +} + +/* Sidebar */ +/* Move right. In a layout with fixed margins, */ +/* it can be moved into the margin. */ +aside.sidebar { width: 30%; max-width: 26em; margin-left: 1em; - margin-right: -5.5%; - background-color: #ffffee ; + margin-right: -2%; + background-color: #ffffee; } diff --git a/nikola/data/themes/base/messages/messages_ca.py b/nikola/data/themes/base/messages/messages_ca.py index 0143a85..c5d8de8 100644 --- a/nikola/data/themes/base/messages/messages_ca.py +++ b/nikola/data/themes/base/messages/messages_ca.py @@ -2,7 +2,7 @@ """Autogenerated file, do not edit. Submit translations on Transifex.""" MESSAGES = { - "%d min remaining to read": "% min restants per a llegir", + "%d min remaining to read": "%d min restants per a llegir", "(active)": "(actiu)", "Also available in:": "També disponible en:", "Archive": "Arxiu", @@ -45,5 +45,5 @@ MESSAGES = { "Write your post here.": "Escriviu la vostra entrada aquí.", "old posts, page %d": "entrades antigues, pàgina %d", "page %d": "pàgina %d", - "updated": "", + "updated": "actualitzat", } diff --git a/nikola/data/themes/base/messages/messages_mi.py b/nikola/data/themes/base/messages/messages_mi.py index 21f9739..853744a 100644 --- a/nikola/data/themes/base/messages/messages_mi.py +++ b/nikola/data/themes/base/messages/messages_mi.py @@ -2,48 +2,48 @@ """Autogenerated file, do not edit. Submit translations on Transifex.""" MESSAGES = { - "%d min remaining to read": "", + "%d min remaining to read": "%d meneti ka toe ki te korero", "(active)": "(mātātoa)", - "Also available in:": "", + "Also available in:": "Kei te wātea ano hoki", "Archive": "Pūranga", - "Atom feed": "", + "Atom feed": "Atom whangai", "Authors": "Kaituhi", "Categories": "Kāwai", - "Comments": "Kōrerohia", + "Comments": "Nga korero", "LANGUAGE": " Māori", "Languages:": "Reo", - "More posts about %s": "", - "Newer posts": "", - "Next post": "", + "More posts about %s": "Ētahi atu pou e pā ana ki %s", + "Newer posts": "Nga pou hou", + "Next post": "Pou muri", "Next": "Panuku", - "No posts found.": "", + "No posts found.": "Kāore i kitea he korero.", "Nothing found.": "Kīhai i kitea", - "Older posts": "", - "Original site": "", - "Posted:": "", - "Posts about %s": "", - "Posts by %s": "", - "Posts for year %s": "", - "Posts for {month_day_year}": "", - "Posts for {month_year}": "", - "Previous post": "", + "Older posts": "Nga pou tawhito", + "Original site": "Pae tukutuku", + "Posted:": "Tukua", + "Posts about %s": "Tuhinga e pā ana ki %s", + "Posts by %s": "Tuhinga na %s", + "Posts for year %s": "Tuhinga mo te tau %s", + "Posts for {month_day_year}": "Tuhinga mo {month_day_year}", + "Posts for {month_year}": "Tuhinga mo {month_year}", + "Previous post": "Tuhinga o mua", "Previous": "Whakamuri", - "Publication date": "", + "Publication date": "Pukapuka tuhi", "RSS feed": "Whāngai RSS", - "Read in English": "", - "Read more": "", - "Skip to main content": "", + "Read in English": "Pānuihia i te Maori", + "Read more": "Pānuihia atu", + "Skip to main content": "Haere ki te ihirangi matua", "Source": "Matapuna", - "Subcategories:": "", + "Subcategories:": "Ngā kōpaki", "Tags and Categories": "Tūtohu me nga kāwai", "Tags": "Tūtohu", - "Toggle navigation": "", - "Uncategorized": "", + "Toggle navigation": "Takahuri whakatere", + "Uncategorized": "Korekorekore", "Up": "Ki runga", "Updates": "Whakahou", - "Write your page here.": "", - "Write your post here.": "", - "old posts, page %d": "", + "Write your page here.": "Tuhia taau whārangi ki konei.", + "Write your post here.": "Tuhia to pou i konei.", + "old posts, page %d": "nga pou tawhito, whārangi %d", "page %d": "whārangi %d", "updated": "whakahoutia", } diff --git a/nikola/data/themes/base/messages/messages_oc.py b/nikola/data/themes/base/messages/messages_oc.py new file mode 100644 index 0000000..a51a9f3 --- /dev/null +++ b/nikola/data/themes/base/messages/messages_oc.py @@ -0,0 +1,49 @@ +# -*- encoding:utf-8 -*- +"""Autogenerated file, do not edit. Submit translations on Transifex.""" + +MESSAGES = { + "%d min remaining to read": "%d min demorantas de lectura", + "(active)": "(actiu)", + "Also available in:": "Tanben disponibla en :", + "Archive": "Archius", + "Atom feed": "Flux Atom", + "Authors": "Autors", + "Categories": "Categorias", + "Comments": "Comentaris", + "LANGUAGE": "Occitan", + "Languages:": "Lengas :", + "More posts about %s": "Mai de publicacion sus %s", + "Newer posts": "Publicacions mai recentas", + "Next post": "Publicacion seguenta", + "Next": "Seguent", + "No posts found.": "Cap de publicacion pas trobada.", + "Nothing found.": "Res pas trobat.", + "Older posts": "Publicacions mai ancianas", + "Original site": "Site original", + "Posted:": "Publicada lo :", + "Posts about %s": "Publicacions tocant %s", + "Posts by %s": "Publicat per %s", + "Posts for year %s": "Publicacions per annada %s", + "Posts for {month_day_year}": "Publicacions per {month_day_year}", + "Posts for {month_year}": "Publicacions per {month_year} ", + "Previous post": "Publicacion precedenta", + "Previous": "Precedent", + "Publication date": "Data de publicacion", + "RSS feed": "Flux RSS", + "Read in English": "Legir en occitan", + "Read more": "Ne legir mai", + "Skip to main content": "Passar al contengut màger", + "Source": "Font", + "Subcategories:": "Jos-categorias :", + "Tags and Categories": "Etiquetas e categorias", + "Tags": "Etiquetas", + "Toggle navigation": "Alternar la navigacion", + "Uncategorized": "Sens categoria", + "Up": "Amont", + "Updates": "Actualizacions", + "Write your page here.": "Escrivètz vòstra pagina aquí.", + "Write your post here.": "Escrivètz vòstra publicacion aquí.", + "old posts, page %d": "publicacions ancianas, pagina %d", + "page %d": "pagina %d", + "updated": "actualizada", +} diff --git a/nikola/data/themes/base/messages/messages_tzm.py b/nikola/data/themes/base/messages/messages_tzm.py new file mode 100644 index 0000000..e9ea75b --- /dev/null +++ b/nikola/data/themes/base/messages/messages_tzm.py @@ -0,0 +1,49 @@ +# -*- encoding:utf-8 -*- +"""Autogenerated file, do not edit. Submit translations on Transifex.""" + +MESSAGES = { + "%d min remaining to read": "", + "(active)": "", + "Also available in:": "", + "Archive": "", + "Atom feed": "", + "Authors": "", + "Categories": "", + "Comments": "Ixfawalen", + "LANGUAGE": "Tamaziɣt", + "Languages:": "", + "More posts about %s": "", + "Newer posts": "", + "Next post": "", + "Next": "", + "No posts found.": "", + "Nothing found.": "", + "Older posts": "", + "Original site": "", + "Posted:": "", + "Posts about %s": "", + "Posts by %s": "", + "Posts for year %s": "", + "Posts for {month_day_year}": "", + "Posts for {month_year}": "", + "Previous post": "", + "Previous": "", + "Publication date": "", + "RSS feed": "", + "Read in English": "Ɣer s tneglizt", + "Read more": "Ɣer uggar", + "Skip to main content": "", + "Source": "Asagem", + "Subcategories:": "", + "Tags and Categories": "", + "Tags": "", + "Toggle navigation": "", + "Uncategorized": "", + "Up": "", + "Updates": "", + "Write your page here.": "", + "Write your post here.": "", + "old posts, page %d": "", + "page %d": "", + "updated": "", +} diff --git a/nikola/data/themes/base/templates/base_helper.tmpl b/nikola/data/themes/base/templates/base_helper.tmpl index 18801ed..684165d 100644 --- a/nikola/data/themes/base/templates/base_helper.tmpl +++ b/nikola/data/themes/base/templates/base_helper.tmpl @@ -82,7 +82,7 @@ lang="${lang}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.${luxon_locales[lang]}"></script> % endif % if use_cdn: - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> % else: <script src="/assets/js/luxon.min.js"></script> % endif diff --git a/nikola/data/themes/base/templates/comments_helper.tmpl b/nikola/data/themes/base/templates/comments_helper.tmpl index 002499e..cfd52f2 100644 --- a/nikola/data/themes/base/templates/comments_helper.tmpl +++ b/nikola/data/themes/base/templates/comments_helper.tmpl @@ -1,63 +1,15 @@ ## -*- coding: utf-8 -*- -<%namespace name="disqus" file="comments_helper_disqus.tmpl"/> -<%namespace name="intensedebate" file="comments_helper_intensedebate.tmpl"/> -<%namespace name="muut" file="comments_helper_muut.tmpl"/> -<%namespace name="facebook" file="comments_helper_facebook.tmpl"/> -<%namespace name="isso" file="comments_helper_isso.tmpl"/> -<%namespace name="commento" file="comments_helper_commento.tmpl"/> -<%namespace name="utterances" file="comments_helper_utterances.tmpl"/> +<%namespace name="comments_helper_impl" file="comments_helper_${context['comment_system']}.tmpl"/> <%def name="comment_form(url, title, identifier)"> - %if comment_system == 'disqus': - ${disqus.comment_form(url, title, identifier)} - % elif comment_system == 'intensedebate': - ${intensedebate.comment_form(url, title, identifier)} - % elif comment_system == 'muut': - ${muut.comment_form(url, title, identifier)} - % elif comment_system == 'facebook': - ${facebook.comment_form(url, title, identifier)} - % elif comment_system == 'isso': - ${isso.comment_form(url, title, identifier)} - % elif comment_system == 'commento': - ${commento.comment_form(url, title, identifier)} - % elif comment_system == 'utterances': - ${utterances.comment_form(url, title, identifier)} - %endif + ${comments_helper_impl.comment_form(url, title, identifier)} </%def> <%def name="comment_link(link, identifier)"> - %if comment_system == 'disqus': - ${disqus.comment_link(link, identifier)} - % elif comment_system == 'intensedebate': - ${intensedebate.comment_link(link, identifier)} - % elif comment_system == 'muut': - ${muut.comment_link(link, identifier)} - % elif comment_system == 'facebook': - ${facebook.comment_link(link, identifier)} - % elif comment_system == 'isso': - ${isso.comment_link(link, identifier)} - % elif comment_system == 'commento': - ${commento.comment_link(link, identifier)} - % elif comment_system == 'utterances': - ${utterances.comment_link(link, identifier)} - %endif + ${comments_helper_impl.comment_link(link, identifier)} </%def> <%def name="comment_link_script()"> - %if comment_system == 'disqus': - ${disqus.comment_link_script()} - % elif comment_system == 'intensedebate': - ${intensedebate.comment_link_script()} - % elif comment_system == 'muut': - ${muut.comment_link_script()} - % elif comment_system == 'facebook': - ${facebook.comment_link_script()} - % elif comment_system == 'isso': - ${isso.comment_link_script()} - % elif comment_system == 'commento': - ${commento.comment_link_script()} - % elif comment_system == 'utterances': - ${utterances.comment_link_script()} - %endif + ${comments_helper_impl.comment_link_script()} </%def> diff --git a/nikola/data/themes/base/templates/comments_helper_dummy.tmpl b/nikola/data/themes/base/templates/comments_helper_dummy.tmpl new file mode 100644 index 0000000..f31a2e0 --- /dev/null +++ b/nikola/data/themes/base/templates/comments_helper_dummy.tmpl @@ -0,0 +1,10 @@ +## -*- coding: utf-8 -*- + +<%def name="comment_form(url, title, identifier)"> +</%def> + +<%def name="comment_link(link, identifier)"> +</%def> + +<%def name="comment_link_script()"> +</%def> diff --git a/nikola/data/themes/bootblog4-jinja/templates/base_helper.tmpl b/nikola/data/themes/bootblog4-jinja/templates/base_helper.tmpl index 7f1bcc8..b35c8d2 100644 --- a/nikola/data/themes/bootblog4-jinja/templates/base_helper.tmpl +++ b/nikola/data/themes/bootblog4-jinja/templates/base_helper.tmpl @@ -64,9 +64,9 @@ lang="{{ lang }}"> {% macro late_load_js() %} {% if use_cdn %} - <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.js" integrity="sha256-ULQV01VS9LCI2ePpLsmka+W0mawFpEA0rtxnezUj4A4=" crossorigin="anonymous"></script> {% endif %} {% if use_bundles and use_cdn %} @@ -86,7 +86,7 @@ lang="{{ lang }}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.{{ luxon_locales[lang] }}"></script> {% endif %} {% if use_cdn %} - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> {% else %} <script src="/assets/js/luxon.min.js"></script> {% endif %} @@ -100,7 +100,7 @@ lang="{{ lang }}"> {% macro html_stylesheets() %} {% if use_cdn %} - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" integrity="sha256-cLMYWYYutHkt+KpNqjg7NVkYSQ+E2VbrXsEvOqU7mL0=" crossorigin="anonymous"> {% endif %} {% if use_bundles and use_cdn %} diff --git a/nikola/data/themes/bootblog4/templates/base_helper.tmpl b/nikola/data/themes/bootblog4/templates/base_helper.tmpl index 2259d4d..33414d8 100644 --- a/nikola/data/themes/bootblog4/templates/base_helper.tmpl +++ b/nikola/data/themes/bootblog4/templates/base_helper.tmpl @@ -64,9 +64,9 @@ lang="${lang}"> <%def name="late_load_js()"> %if use_cdn: - <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.js" integrity="sha256-ULQV01VS9LCI2ePpLsmka+W0mawFpEA0rtxnezUj4A4=" crossorigin="anonymous"></script> % endif %if use_bundles and use_cdn: @@ -86,7 +86,7 @@ lang="${lang}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.${luxon_locales[lang]}"></script> %endif %if use_cdn: - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> %else: <script src="/assets/js/luxon.min.js"></script> %endif @@ -100,7 +100,7 @@ lang="${lang}"> <%def name="html_stylesheets()"> % if use_cdn: - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" integrity="sha256-cLMYWYYutHkt+KpNqjg7NVkYSQ+E2VbrXsEvOqU7mL0=" crossorigin="anonymous"> % endif %if use_bundles and use_cdn: diff --git a/nikola/data/themes/bootstrap4-jinja/templates/base_helper.tmpl b/nikola/data/themes/bootstrap4-jinja/templates/base_helper.tmpl index 2d82147..ff1bfa2 100644 --- a/nikola/data/themes/bootstrap4-jinja/templates/base_helper.tmpl +++ b/nikola/data/themes/bootstrap4-jinja/templates/base_helper.tmpl @@ -64,9 +64,9 @@ lang="{{ lang }}"> {% macro late_load_js() %} {% if use_cdn %} - <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.js" integrity="sha256-ULQV01VS9LCI2ePpLsmka+W0mawFpEA0rtxnezUj4A4=" crossorigin="anonymous"></script> {% endif %} {% if use_bundles and use_cdn %} @@ -86,7 +86,7 @@ lang="{{ lang }}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.{{ luxon_locales[lang] }}"></script> {% endif %} {% if use_cdn %} - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> {% else %} <script src="/assets/js/luxon.min.js"></script> {% endif %} @@ -100,7 +100,7 @@ lang="{{ lang }}"> {% macro html_stylesheets() %} {% if use_cdn %} - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" integrity="sha256-cLMYWYYutHkt+KpNqjg7NVkYSQ+E2VbrXsEvOqU7mL0=" crossorigin="anonymous"> {% endif %} {% if use_bundles and use_cdn %} diff --git a/nikola/data/themes/bootstrap4/templates/base_helper.tmpl b/nikola/data/themes/bootstrap4/templates/base_helper.tmpl index 80dd8f9..32ca42b 100644 --- a/nikola/data/themes/bootstrap4/templates/base_helper.tmpl +++ b/nikola/data/themes/bootstrap4/templates/base_helper.tmpl @@ -64,9 +64,9 @@ lang="${lang}"> <%def name="late_load_js()"> %if use_cdn: - <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.js" integrity="sha256-ULQV01VS9LCI2ePpLsmka+W0mawFpEA0rtxnezUj4A4=" crossorigin="anonymous"></script> % endif %if use_bundles and use_cdn: @@ -86,7 +86,7 @@ lang="${lang}"> <script src="https://polyfill.io/v3/polyfill.js?features=Intl.RelativeTimeFormat.%7Elocale.${luxon_locales[lang]}"></script> %endif %if use_cdn: - <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js" integrity="sha256-OVk2fwTRcXYlVFxr/ECXsakqelJbOg5WCj1dXSIb+nU=" crossorigin="anonymous"></script> + <script src="https://cdn.jsdelivr.net/npm/luxon@1.28.0/build/global/luxon.min.js" integrity="sha256-l1u7Y5ze+ENf/T9ORPa3E642/uMgHUFa1KnqzFCcWEY=" crossorigin="anonymous"></script> %else: <script src="/assets/js/luxon.min.js"></script> %endif @@ -100,7 +100,7 @@ lang="${lang}"> <%def name="html_stylesheets()"> %if use_cdn: - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" integrity="sha256-cLMYWYYutHkt+KpNqjg7NVkYSQ+E2VbrXsEvOqU7mL0=" crossorigin="anonymous"> % endif %if use_bundles and use_cdn: diff --git a/nikola/filters.py b/nikola/filters.py index 5e7ca5e..c2b10e2 100644 --- a/nikola/filters.py +++ b/nikola/filters.py @@ -268,8 +268,11 @@ def minify_lines(data): def _run_typogrify(data, typogrify_filters, ignore_tags=None): """Run typogrify with ignore support.""" + default_ignore_tags = ["title", ".math"] if ignore_tags is None: - ignore_tags = ["title"] + ignore_tags = default_ignore_tags + else: + ignore_tags = ignore_tags + default_ignore_tags data = _normalize_html(data) @@ -328,11 +331,13 @@ def typogrify_sans_widont(data): @apply_to_text_file -def typogrify_custom(data, typogrify_filters, ignore_tags=None): - """Run typogrify with a custom list of fliter functions.""" +def typogrify_custom(data, typogrify_filters=None, ignore_tags=None): + """Run typogrify with a custom list of filter functions.""" if typo is None: req_missing(['typogrify'], 'use the typogrify filter', optional=True) return data + if typogrify_filters is None: + typogrify_filters = [typo.amp, typo.widont, typo.smartypants, typo.caps, typo.initial_quotes] return _run_typogrify(data, typogrify_filters, ignore_tags) diff --git a/nikola/image_processing.py b/nikola/image_processing.py index b1d58c2..4ac6d93 100644 --- a/nikola/image_processing.py +++ b/nikola/image_processing.py @@ -142,7 +142,7 @@ class ImageProcessor(object): if w > max_size or h > max_size: size = max_size, max_size # Panoramas get larger thumbnails because they look *awful* - if bigger_panoramas and w > 2 * h: + if bigger_panoramas and w > 3 * h: size = min(w, max_size * 4), min(w, max_size * 4) try: im.thumbnail(size, Image.ANTIALIAS) @@ -189,7 +189,7 @@ class ImageProcessor(object): # calculate new size preserving aspect ratio. ratio = float(w) / h # Panoramas get larger thumbnails because they look *awful* - if bigger_panoramas and w > 2 * h: + if bigger_panoramas and w > 3 * h: max_size = max_size * 4 if w > h: w = max_size diff --git a/nikola/nikola.py b/nikola/nikola.py index 2ec8f2d..ca8291b 100644 --- a/nikola/nikola.py +++ b/nikola/nikola.py @@ -66,6 +66,7 @@ from .plugin_categories import ( TemplateSystem, SignalHandler, ConfigPlugin, + CommentSystem, PostScanner, Taxonomy, ) @@ -133,10 +134,12 @@ LEGAL_VALUES = { ('ja', '!jp'): 'Japanese', 'ko': 'Korean', 'lt': 'Lithuanian', + 'mi': 'Maori', 'ml': 'Malayalam', 'mr': 'Marathi', 'nb': 'Norwegian (Bokmål)', 'nl': 'Dutch', + 'oc': 'Occitan', 'pa': 'Punjabi', 'pl': 'Polish', 'pt': 'Portuguese', @@ -203,10 +206,12 @@ LEGAL_VALUES = { 'ja': 'ja', 'ko': 'ko', 'lt': 'lt', + 'mi': 'mi', 'ml': 'ml', 'mr': 'mr', 'nb': 'nb', 'nl': 'nl', + 'oc': 'oc', 'pa': 'pa', 'pl': 'pl', 'pt': 'pt', @@ -681,6 +686,10 @@ class Nikola(object): 'FEED_READ_MORE_LINK', 'INDEXES_TITLE', 'CATEGORY_DESTPATH_NAMES', + 'CATEGORY_TITLES', + 'CATEGORY_DESCRIPTIONS', + 'TAG_TITLES', + 'TAG_DESCRIPTIONS', 'INDEXES_PAGES', 'INDEXES_PRETTY_PAGE_URL', 'THEME_CONFIG', @@ -727,6 +736,8 @@ class Nikola(object): 'rss_path', 'rss_filename_base', 'atom_filename_base', + 'index_read_more_link', + 'feed_read_more_link', ) # WARNING: navigation_(alt_)links SHOULD NOT be added to the list above. # Themes ask for [lang] there and we should provide it. @@ -1029,6 +1040,7 @@ class Nikola(object): "ShortcodePlugin": ShortcodePlugin, "SignalHandler": SignalHandler, "ConfigPlugin": ConfigPlugin, + "CommentSystem": CommentSystem, "PostScanner": PostScanner, "Taxonomy": Taxonomy, }) @@ -1172,7 +1184,8 @@ class Nikola(object): self.compilers[plugin_info.name] = \ plugin_info.plugin_object - # Load config plugins and register templated shortcodes + # Load comment systems, config plugins and register templated shortcodes + self._activate_plugins_of_category("CommentSystem") self._activate_plugins_of_category("ConfigPlugin") self._register_templated_shortcodes() @@ -1237,7 +1250,7 @@ class Nikola(object): self._GLOBAL_CONTEXT['translations'] = self.config.get('TRANSLATIONS') self._GLOBAL_CONTEXT['license'] = self.config.get('LICENSE') self._GLOBAL_CONTEXT['search_form'] = self.config.get('SEARCH_FORM') - self._GLOBAL_CONTEXT['comment_system'] = self.config.get('COMMENT_SYSTEM') + self._GLOBAL_CONTEXT['comment_system'] = self.config.get('COMMENT_SYSTEM') or 'dummy' self._GLOBAL_CONTEXT['comment_system_id'] = self.config.get('COMMENT_SYSTEM_ID') self._GLOBAL_CONTEXT['site_has_comments'] = bool(self.config.get('COMMENT_SYSTEM')) self._GLOBAL_CONTEXT['mathjax_config'] = self.config.get( @@ -1309,6 +1322,8 @@ class Nikola(object): self.ALL_PAGE_DEPS['slug_author_path'] = self.config.get('SLUG_AUTHOR_PATH') self.ALL_PAGE_DEPS['slug_tag_path'] = self.config.get('SLUG_TAG_PATH') self.ALL_PAGE_DEPS['locale'] = self.config.get('LOCALE') + self.ALL_PAGE_DEPS['index_read_more_link'] = self.config.get('INDEX_READ_MORE_LINK') + self.ALL_PAGE_DEPS['feed_read_more_link'] = self.config.get('FEED_READ_MORE_LINK') def _activate_plugins_of_category(self, category): """Activate all the plugins of a given category and return them.""" @@ -1668,7 +1683,7 @@ class Nikola(object): context[k] = context[k](context['lang']) output = self.template_system.render_template_to_string(t_data, context) if fname is not None: - dependencies = [fname] + self.template_system.get_deps(fname) + dependencies = [fname] + self.template_system.get_deps(fname, context) else: dependencies = [] return output, dependencies @@ -1709,7 +1724,7 @@ class Nikola(object): for k in self._GLOBAL_CONTEXT_TRANSLATABLE: context[k] = context[k](context['lang']) output = self.template_system.render_template_to_string(t_data, context) - dependencies = self.template_system.get_string_deps(t_data) + dependencies = self.template_system.get_string_deps(t_data, context) return output, dependencies def register_shortcode(self, name, f): @@ -2264,8 +2279,10 @@ class Nikola(object): """ utils.LocaleBorg().set_locale(lang) + template_dep_context = context.copy() + template_dep_context.update(self.GLOBAL_CONTEXT) file_deps = copy(file_deps) if file_deps else [] - file_deps += self.template_system.template_deps(template_name) + file_deps += self.template_system.template_deps(template_name, template_dep_context) file_deps = sorted(list(filter(None, file_deps))) context = copy(context) if context else {} diff --git a/nikola/plugin_categories.py b/nikola/plugin_categories.py index 722e672..0ba5991 100644 --- a/nikola/plugin_categories.py +++ b/nikola/plugin_categories.py @@ -94,7 +94,7 @@ class BasePlugin(IPlugin): """Add 'dependency' to the target task's task_deps.""" self.site.injected_deps[target].append(dependency) - def get_deps(self, filename): + def get_deps(self, filename, context=None): """Find the dependencies for a file.""" return [] @@ -222,15 +222,15 @@ class TemplateSystem(BasePlugin): """Set the list of folders where templates are located and cache.""" raise NotImplementedError() - def template_deps(self, template_name: str): + def template_deps(self, template_name: str, context=None): """Return filenames which are dependencies for a template.""" raise NotImplementedError() - def get_deps(self, filename: str): + def get_deps(self, filename: str, context=None): """Return paths to dependencies for the template loaded from filename.""" raise NotImplementedError() - def get_string_deps(self, text: str): + def get_string_deps(self, text: str, context=None): """Find dependencies for a template string.""" raise NotImplementedError() @@ -475,6 +475,12 @@ class ConfigPlugin(BasePlugin): name = "dummy_config_plugin" +class CommentSystem(BasePlugin): + """A plugn that offers a new comment system.""" + + name = "dummy_comment_system" + + class ShortcodePlugin(BasePlugin): """A plugin that adds a shortcode.""" diff --git a/nikola/plugins/command/auto/__init__.py b/nikola/plugins/command/auto/__init__.py index 9de5622..2c6d0e7 100644 --- a/nikola/plugins/command/auto/__init__.py +++ b/nikola/plugins/command/auto/__init__.py @@ -37,6 +37,7 @@ import sys import typing import webbrowser +import blinker import pkg_resources from nikola.plugin_categories import Command @@ -122,7 +123,8 @@ class CommandAuto(Command): 'long': 'process', 'default': 0, 'type': int, - 'help': 'Number of subprocesses (nikola build argument)' + 'help': 'Number of subprocesses', + 'section': 'Arguments passed to `nikola build`' }, { 'name': 'parallel-type', @@ -130,8 +132,25 @@ class CommandAuto(Command): 'long': 'parallel-type', 'default': 'process', 'type': str, - 'help': "Parallelization mode ('process' or 'thread', nikola build argument)" + 'help': "Parallelization mode ('process' or 'thread')", + 'section': 'Arguments passed to `nikola build`' }, + { + 'name': 'db-file', + 'long': 'db-file', + 'default': '.doit.db', + 'type': str, + 'help': 'Database file', + 'section': 'Arguments passed to `nikola build`' + }, + { + 'name': 'backend', + 'long': 'backend', + 'default': 'dbm', + 'type': str, + 'help': "Database backend ('dbm', 'json', 'sqlite3')", + 'section': 'Arguments passed to `nikola build`' + } ] def _execute(self, options, args): @@ -149,6 +168,8 @@ class CommandAuto(Command): elif Observer is None: req_missing(['watchdog'], 'use the "auto" command') + blinker.signal('auto_command_starting').send(self.site) + if sys.argv[0].endswith('__main__.py'): self.nikola_cmd = [sys.executable, '-m', 'nikola', 'build'] else: @@ -161,6 +182,10 @@ class CommandAuto(Command): self.nikola_cmd += ['--process={}'.format(options['process']), '--parallel-type={}'.format(options['parallel-type'])] + if options: + self.nikola_cmd += ['--db-file={}'.format(options['db-file']), + '--backend={}'.format(options['backend'])] + port = options and options.get('port') self.snippet = '''<script>document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py index 06e00a1..f513e1c 100644 --- a/nikola/plugins/command/import_wordpress.py +++ b/nikola/plugins/command/import_wordpress.py @@ -582,6 +582,11 @@ to def add(our_key, wp_key, is_int=False, ignore_zero=False, is_float=False): if wp_key in image_meta: value = image_meta[wp_key] + if value in ("", b"") and (is_int or is_float): + if ignore_zero: + return + else: + dst_meta[our_key] = 0 if is_int: value = int(value) if ignore_zero and value == 0: diff --git a/nikola/plugins/shortcode/post_list.py b/nikola/plugins/shortcode/post_list.py index 0206cf0..2d8d170 100644 --- a/nikola/plugins/shortcode/post_list.py +++ b/nikola/plugins/shortcode/post_list.py @@ -219,7 +219,7 @@ class PostListShortcode(ShortcodePlugin): posts += [post] - template_deps = site.template_system.template_deps(template) + template_deps = site.template_system.template_deps(template, site.GLOBAL_CONTEXT) if state: # Register template as a dependency (Issue #2391) for d in template_deps: diff --git a/nikola/plugins/task/categories.py b/nikola/plugins/task/categories.py index 3c0ea6b..b140101 100644 --- a/nikola/plugins/task/categories.py +++ b/nikola/plugins/task/categories.py @@ -186,6 +186,8 @@ link://category_rss/dogs => /categories/dogs.xml""", "title": self.site.MESSAGES[lang]["Categories"], "description": self.site.MESSAGES[lang]["Categories"], "pagekind": ["list", "tags_page"], + "category_descriptions": self.site.config['CATEGORY_DESCRIPTIONS'](lang), + "category_titles": self.site.config['CATEGORY_TITLES'](lang), } kw.update(context) return context, kw @@ -209,8 +211,8 @@ link://category_rss/dogs => /categories/dogs.xml""", subcats = [(child.name, self.site.link(self.classification_name, child.classification_name, lang)) for child in children] friendly_name = self.get_classification_friendly_name(classification, lang) context = { - "title": self.site.config['CATEGORY_TITLES'].get(lang, {}).get(classification, self.site.MESSAGES[lang]["Posts about %s"] % friendly_name), - "description": self.site.config['CATEGORY_DESCRIPTIONS'].get(lang, {}).get(classification), + "title": self.site.config['CATEGORY_TITLES'](lang).get(classification, self.site.MESSAGES[lang]["Posts about %s"] % friendly_name), + "description": self.site.config['CATEGORY_DESCRIPTIONS'](lang).get(classification), "pagekind": ["tag_page", "index" if self.show_list_as_index else "list"], "tag": friendly_name, "category": classification, diff --git a/nikola/plugins/task/galleries.py b/nikola/plugins/task/galleries.py index 1c53cbd..c9b1915 100644 --- a/nikola/plugins/task/galleries.py +++ b/nikola/plugins/task/galleries.py @@ -307,10 +307,13 @@ class Galleries(Task, ImageProcessor): context['post'] = post else: context['post'] = None + + template_dep_context = context.copy() + template_dep_context.update(self.site.GLOBAL_CONTEXT) file_dep = self.site.template_system.template_deps( - template_name) + image_list + thumbs + template_name, template_dep_context) + image_list + thumbs file_dep_dest = self.site.template_system.template_deps( - template_name) + dest_img_list + thumbs + template_name, template_dep_context) + dest_img_list + thumbs if post: file_dep += [post.translated_base_path(l) for l in self.kw['translations']] file_dep_dest += [post.translated_base_path(l) for l in self.kw['translations']] diff --git a/nikola/plugins/task/listings.py b/nikola/plugins/task/listings.py index 5f4fca9..d52ddb2 100644 --- a/nikola/plugins/task/listings.py +++ b/nikola/plugins/task/listings.py @@ -179,7 +179,7 @@ class Listings(Task): yield self.group_task() - template_deps = self.site.template_system.template_deps('listing.tmpl') + template_deps = self.site.template_system.template_deps('listing.tmpl', self.site.GLOBAL_CONTEXT) for input_folder, output_folder in self.kw['listings_folders'].items(): for root, dirs, files in os.walk(input_folder, followlinks=True): diff --git a/nikola/plugins/task/tags.py b/nikola/plugins/task/tags.py index a1a6b77..cc2ced8 100644 --- a/nikola/plugins/task/tags.py +++ b/nikola/plugins/task/tags.py @@ -128,6 +128,8 @@ link://tag_rss/cats => /tags/cats.xml""", "title": self.site.MESSAGES[lang]["Tags"], "description": self.site.MESSAGES[lang]["Tags"], "pagekind": ["list", "tags_page"], + "tag_descriptions": self.site.config['TAG_DESCRIPTIONS'](lang), + "tag_titles": self.site.config['TAG_TITLES'](lang), } kw.update(context) return context, kw @@ -143,8 +145,8 @@ link://tag_rss/cats => /tags/cats.xml""", "tag_titles": self.site.config['TAG_TITLES'], } context = { - "title": self.site.config['TAG_TITLES'].get(lang, {}).get(classification, self.site.MESSAGES[lang]["Posts about %s"] % classification), - "description": self.site.config['TAG_DESCRIPTIONS'].get(lang, {}).get(classification), + "title": self.site.config['TAG_TITLES'](lang).get(classification, self.site.MESSAGES[lang]["Posts about %s"] % classification), + "description": self.site.config['TAG_DESCRIPTIONS'](lang).get(classification), "pagekind": ["tag_page", "index" if self.show_list_as_index else "list"], "tag": classification, } diff --git a/nikola/plugins/template/jinja.py b/nikola/plugins/template/jinja.py index 845f4d5..aec6063 100644 --- a/nikola/plugins/template/jinja.py +++ b/nikola/plugins/template/jinja.py @@ -31,10 +31,11 @@ import json import os from nikola.plugin_categories import TemplateSystem -from nikola.utils import makedirs, req_missing, sort_posts, _smartjoin_filter +from nikola.utils import makedirs, req_missing, slugify, sort_posts, _smartjoin_filter try: import jinja2 + import jinja2.nodes from jinja2 import meta except ImportError: jinja2 = None @@ -66,6 +67,7 @@ class JinjaTemplates(TemplateSystem): self.lookup.filters['tojson'] = json.dumps self.lookup.filters['sort_posts'] = sort_posts self.lookup.filters['smartjoin'] = _smartjoin_filter + self.lookup.filters['slugify'] = slugify self.lookup.globals['enumerate'] = enumerate self.lookup.globals['isinstance'] = isinstance self.lookup.globals['tuple'] = tuple @@ -104,29 +106,35 @@ class JinjaTemplates(TemplateSystem): """Render template to a string using context.""" return self.lookup.from_string(template).render(**context) - def get_string_deps(self, text): + def get_string_deps(self, text, context=None): """Find dependencies for a template string.""" deps = set([]) ast = self.lookup.parse(text) - dep_names = [d for d in meta.find_referenced_templates(ast) if d] + simple_dep_names = [d for d in meta.find_referenced_templates(ast) if d] + formatted_dep_names = [ + imp.template.left.value % (context[imp.template.right.name],) + for imp in ast.find_all(jinja2.nodes.Import) + if isinstance(imp.template, jinja2.nodes.Mod) + ] + dep_names = simple_dep_names + formatted_dep_names for dep_name in dep_names: filename = self.lookup.loader.get_source(self.lookup, dep_name)[1] - sub_deps = [filename] + self.get_deps(filename) + sub_deps = [filename] + self.get_deps(filename, context) self.dependency_cache[dep_name] = sub_deps deps |= set(sub_deps) return list(deps) - def get_deps(self, filename): + def get_deps(self, filename, context=None): """Return paths to dependencies for the template loaded from filename.""" with io.open(filename, 'r', encoding='utf-8-sig') as fd: text = fd.read() - return self.get_string_deps(text) + return self.get_string_deps(text, context) - def template_deps(self, template_name): + def template_deps(self, template_name, context=None): """Generate list of dependencies for a template.""" if self.dependency_cache.get(template_name) is None: filename = self.lookup.loader.get_source(self.lookup, template_name)[1] - self.dependency_cache[template_name] = [filename] + self.get_deps(filename) + self.dependency_cache[template_name] = [filename] + self.get_deps(filename, context) return self.dependency_cache[template_name] def get_template_path(self, template_name): diff --git a/nikola/plugins/template/mako.py b/nikola/plugins/template/mako.py index 8066b96..8197518 100644 --- a/nikola/plugins/template/mako.py +++ b/nikola/plugins/template/mako.py @@ -28,6 +28,7 @@ import io import os +import re import shutil from mako import exceptions, util, lexer, parsetree @@ -52,7 +53,7 @@ class MakoTemplates(TemplateSystem): directories = [] cache_dir = None - def get_string_deps(self, text, filename=None): + def get_string_deps(self, text, context=None, *, filename=None): """Find dependencies for a template string.""" lex = lexer.Lexer(text=text, filename=filename, input_encoding='utf-8') lex.parse() @@ -61,7 +62,11 @@ class MakoTemplates(TemplateSystem): for n in lex.template.nodes: keyword = getattr(n, 'keyword', None) if keyword in ["inherit", "namespace"] or isinstance(n, parsetree.IncludeTag): - deps.append(n.attributes['file']) + filename = n.attributes["file"] + if '${' in filename: + # Support for comment helper inclusions + filename = re.sub(r'''\${context\[['"](.*?)['"]]}''', lambda m: context[m.group(1)], filename) + deps.append(filename) # Some templates will include "foo.tmpl" and we need paths, so normalize them # using the template lookup for i, d in enumerate(deps): @@ -73,10 +78,10 @@ class MakoTemplates(TemplateSystem): d, filename) return deps - def get_deps(self, filename): + def get_deps(self, filename, context=None): """Get paths to dependencies for a template.""" text = util.read_file(filename) - return self.get_string_deps(text, filename) + return self.get_string_deps(text, context, filename=filename) def set_directories(self, directories, cache_folder): """Create a new template lookup with set directories.""" @@ -122,17 +127,17 @@ class MakoTemplates(TemplateSystem): context.update(self.filters) return Template(template, lookup=self.lookup).render(**context) - def template_deps(self, template_name): + def template_deps(self, template_name, context=None): """Generate list of dependencies for a template.""" # We can cache here because dependencies should # not change between runs if self.cache.get(template_name, None) is None: template = self.lookup.get_template(template_name) - dep_filenames = self.get_deps(template.filename) + dep_filenames = self.get_deps(template.filename, context) deps = [template.filename] for fname in dep_filenames: # yes, it uses forward slashes on Windows - deps += self.template_deps(fname.split('/')[-1]) + deps += self.template_deps(fname.split('/')[-1], context) self.cache[template_name] = list(set(deps)) return self.cache[template_name] diff --git a/nikola/post.py b/nikola/post.py index 795f9d6..06de222 100644 --- a/nikola/post.py +++ b/nikola/post.py @@ -253,7 +253,7 @@ class Post(object): self.post_name = os.path.splitext(source_path)[0] # posts/blah _relpath = os.path.relpath(self.post_name) if _relpath != self.post_name: - self.post_name = _relpath.replace('..' + os.sep, '_..' + os.sep) + self.post_name = _relpath.replace('..' + os.sep, '__dotdot__' + os.sep) # cache[\/]posts[\/]blah.html self.base_path = os.path.join(self.config['CACHE_FOLDER'], self.post_name + ".html") # cache/posts/blah.html @@ -910,10 +910,7 @@ class Post(object): if self.hyphenate: hyphenate(document, real_lang) - try: - data = lxml.html.tostring(document.body, encoding='unicode') - except Exception: - data = lxml.html.tostring(document, encoding='unicode') + data = utils.html_tostring_fragment(document) if teaser_only: teaser_regexp = self.config.get('TEASER_REGEXP', TEASER_REGEXP) @@ -936,10 +933,7 @@ class Post(object): post_title=self.title(lang)) # This closes all open tags and sanitizes the broken HTML document = lxml.html.fromstring(teaser) - try: - data = lxml.html.tostring(document.body, encoding='unicode') - except IndexError: - data = lxml.html.tostring(document, encoding='unicode') + data = utils.html_tostring_fragment(document) if data and strip_html: try: @@ -952,11 +946,11 @@ class Post(object): if self.demote_headers: # see above try: - document = lxml.html.fromstring(data) + document = lxml.html.fragment_fromstring(data, "body") demote_headers(document, self.demote_headers) - data = lxml.html.tostring(document.body, encoding='unicode') + data = utils.html_tostring_fragment(document) except (lxml.etree.ParserError, IndexError): - data = lxml.html.tostring(document, encoding='unicode') + pass return data diff --git a/nikola/utils.py b/nikola/utils.py index 54cd36f..363ab40 100644 --- a/nikola/utils.py +++ b/nikola/utils.py @@ -30,6 +30,7 @@ import configparser import datetime import hashlib import io +import lxml.html import operator import os import re @@ -656,6 +657,25 @@ def get_theme_chain(theme, themes_dirs): return themes +def html_tostring_fragment(document): + """Convert a HTML snippet to a fragment, ready for insertion elsewhere.""" + try: + doc = lxml.html.tostring(document.body, encoding='unicode').strip() + except Exception: + doc = lxml.html.tostring(document, encoding='unicode').strip() + start_fragments = ["<html>", "<body>"] + end_fragments = ["</body>", "</html>"] + for start in start_fragments: + if doc.startswith(start): + doc = doc[len(start):].strip() + print(repr(doc)) + for end in end_fragments: + if doc.endswith(end): + doc = doc[:-len(end)].strip() + print(repr(doc)) + return doc + + INCOMPLETE_LANGUAGES_WARNED = set() |
