Compare commits

...

518 commits

Author SHA1 Message Date
Justin Mayer
b7408cbfe9
Merge pull request #3491 from clockback/enable-flake8-unused-arguments 2025-07-22 19:18:09 +02:00
Justin Mayer
87e3b60da7 Update tests for dark mode & GitHub link changes 2025-07-22 17:41:50 +02:00
Jacki
f95466c8fe Implement dark mode for template
Signed-off-by: Jacki <jacki@thejackimonster.de>
2025-07-22 17:41:50 +02:00
Jacki
4cac1ab5f1 Drop loading external image from Github
Signed-off-by: Jacki <jacki@thejackimonster.de>
2025-07-22 17:41:50 +02:00
Ilya Simpson
6df3cfc6e3 Enable flake8-unused-arguments Ruff rule. 2025-07-22 15:39:30 +12:00
Justin Mayer
162d2b8318
Merge pull request #3477 from clockback/document-feed-domain-default 2025-07-21 20:25:08 +02:00
Ilya Simpson
595713b91a Fix default FEED_DOMAIN: None -> SITEURL.
This is similar to how `AUTHOR_REGEX_SUBSTITUTIONS` is described, for
instance.
2025-07-21 20:22:27 +02:00
Justin Mayer
7ef5eae639 Update feed functional tests for FeedGenerator 2.2 2025-07-21 20:14:15 +02:00
Justin Mayer
eb0d4deb01
Merge pull request #3488 from GeorgeHu6/chinese-translation 2025-07-13 13:06:21 +02:00
GeorgeHu6
f92b2a27ab Doc: update Chinese translation 2025-07-13 16:40:13 +08:00
Justin Mayer
95965459f2 docs: Fix linter errors with invoke lint --fix 2025-07-09 09:15:40 +02:00
Justin Mayer
3efb0817e3 Ignore Ruff 0.12 rule compliance in git blame 2025-07-08 08:13:44 +02:00
Justin Mayer
f4ee3b7946
Merge pull request #3483 from boxydog/ruff_0_12_2 2025-07-08 08:10:18 +02:00
Justin Mayer
939434b4ab
Merge pull request #3482 from getpelican/limit-dependabot 2025-07-07 08:25:47 +02:00
boxydog
4dedf17958 Move ruff to 0.12.2 and fix new complaints 2025-07-05 10:09:08 -05:00
Justin Mayer
a29857ac19
Merge pull request #3467 from nkr0/bump-pygments-version 2025-07-05 08:39:01 +02:00
Justin Mayer
bfd1068b82
Merge pull request #3474 from clockback/use-lists-not-tuples 2025-07-05 07:48:57 +02:00
Justin Mayer
0e358c611c
Merge pull request #3479 from clockback/fix-default-slug-regex-substitutions 2025-07-05 07:45:13 +02:00
Ilya Simpson
fca2fde2ed Change lists, not tuples, in config settings
In the documentation, both `SOCIAL` and `LINKS` are described as a list
of tuples, but all examples show them as tuples of tuples. It makes the
most sense for them to be lists, so the examples should match the docs
going forward.

Similarly, `LOCALE` is described as a list, but the examples show it as
a tuple. Likewise, the examples should be lists, in line with the
description.
2025-07-04 20:06:44 +12:00
Justin Mayer
ff4460c3d7 Limit Dependabot scope to GitHub Actions only
Sometimes we intentionally pin specific package versions -- such as for
Pygments, Jinja2, and Markdown -- and thus automated Dependabot PRs for
those packages are spurious and unwanted.
2025-07-01 09:31:01 +02:00
Ilya Simpson
b2ac0e93aa Fixing default SLUG_REGEX_SUBSTITUTIONS in docs.
Backslashes should not have been doubled, given the defaults are raw
strings.
2025-06-07 22:12:46 +12:00
Justin Mayer
9e3e1325c0
Merge pull request #3475 from clockback/enable-flake8-builtins 2025-06-02 15:11:00 +02:00
Ilya Simpson
f44ec52427 Enable flake8-builtins Ruff rule. 2025-06-02 17:22:50 +12:00
Justin Mayer
9f6cc9f0d7
Merge pull request #3473 from clockback/main 2025-05-30 09:42:26 +02:00
Ilya Simpson
ffe22e3c59 Fixing documented default for ARTICLE_SAVE_AS. 2025-05-29 22:29:33 +12:00
Justin Mayer
487486138f
Merge pull request #3470 from emmanuel-ferdman/main
fix: Resolve `datetime` warnings
2025-05-14 09:48:34 +02:00
Emmanuel Ferdman
07f32c1a09
fix: resolve datetime warnings
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-05-13 06:40:14 -07:00
n
ca32b1b77c bump pygments version to <2.20.0 2025-05-10 12:41:57 +02:00
Justin Mayer
f9711fa10a
Merge pull request #3462 from Kristinita/KiraValidPathMetadataValue
docs: Use raw string for the `PATH_METADATA` setting
2025-04-19 12:28:16 +02:00
Kristinita
7fd66d8a95
docs: Use raw string for the PATH_METADATA setting 2025-04-19 11:00:42 +03:00
Al Sweigart
9c7749a298
docs: Move default values to fix settings anchor links (#3458)
* Fix anchor links for settings by moving default value text down.
* Fix typos in default values.

---------

Co-authored-by: Justin Mayer <entroP@gmail.com>
2025-04-12 12:38:30 +02:00
Justin Mayer
88a6f57940 Upgrade Beautiful Soup & adjust tests to conform 2025-04-11 21:13:41 +02:00
Justin Mayer
5338f4fac2
Merge pull request #3447 from ceyusa/update-docs
docs: Update install from sources using setuptools
2025-03-25 09:51:00 -07:00
Víctor Manuel Jáquez Leal
b71159a11e docs: Update install from sources using setuptools 2025-01-27 06:18:55 +01:00
botpub
69e24fa82f Release Pelican 4.11.0 2025-01-15 17:01:09 +00:00
Justin Mayer
ec95a2c855 Prepare release 2025-01-15 17:53:09 +01:00
Yashas Lokesh
543424aa41
fix: Fix auto-reload with globs in IGNORE_FILES (#3441)
The default `IGNORE_FILES` value of `'.*'` was being compiled to a regular expression and then passed into `watchfiles.DefaultFilter` to filter out files when auto-reload is enabled.

This commit compares the patterns from `IGNORE_FILES` directly with the filename to match the usage of `fnmatch` elsewhere in the codebase. The new filtering class will continue working as expected for custom `IGNORE_FILES` settings.
2025-01-15 17:40:27 +01:00
Vincent Cheng
5be013d9d2
Make build reproducible by reading envvar SOURCE_DATE_EPOCH if set (#3430)
Co-authored-by: Justin Mayer <entroP@gmail.com>
2025-01-15 17:36:52 +01:00
Justin Mayer
64be147463
Merge pull request #3405 from frederik-elwert/improve-simple-theme
Add more blocks to Simple theme's base template
2025-01-15 12:32:12 +01:00
Frederik Elwert
4fcc24ddfe Add test for simple theme and inheritance 2025-01-15 12:00:16 +01:00
Frederik Elwert
af3c2ed0cf Add block name in endblock 2025-01-15 11:58:05 +01:00
Frederik Elwert
d813c5148e Add more blocks to simple base template
This change makes it easier to create new themes by inheriting from the
simple theme. It allows customization of the whole body (while still
making use of the theme’s head), or individual parts of the body like
header, menu, or footer.
2025-01-15 11:58:05 +01:00
Alvin Mites
4878fc82a7
chore: Update link to re-directed example settings file (#3445) 2025-01-15 11:43:52 +01:00
Justin Mayer
8a1c55ed07 docs: Clarify namespace plugin loading order 2025-01-14 12:49:34 +01:00
David Lesieur
9207e1ff62
feat: Add setting to omit selected Typogrify filters. Fixes #3436 (#3439) 2025-01-14 12:48:39 +01:00
Justin Mayer
fa0af6d221
Merge pull request #3438 from davidlesieur/typogrify-test-ignore-tags
test:  Fix `test_typogrify_ignore_tags` due to Typogrify 2.1 changes
2025-01-14 12:41:17 +01:00
Justin Mayer
b3ef32bcf1 test: Require Typogrify 2.1+ to pass updated test 2025-01-14 12:35:17 +01:00
David Lesieur
b4fcb7f4e3 Remove obsolete comment regarding widont. 2025-01-14 12:30:06 +01:00
David Lesieur
7a4c89f64a Adjust test following changes in Typogrify.
Typogrify's 'widont' filter used to ignore the list of 'ignore_tags', but this got fixed in Typogrify.
2025-01-14 12:30:06 +01:00
Justin Mayer
74d76ca0da Pin Pygments due to indentation changes in 2.19 2025-01-14 12:26:35 +01:00
Justin Mayer
a17521b6f7
Merge pull request #3435 from hugovk/add-3.13 2024-12-22 11:45:12 +01:00
Hugo van Kemenade
5bb39c4f6f Replace deprecated logger.warn with logger.warning 2024-12-21 15:53:56 +02:00
Hugo van Kemenade
714a3d53a1 Drop support for EOL Python 3.8 2024-12-21 15:53:13 +02:00
Hugo van Kemenade
7d4adfce3f Add support for Python 3.13 2024-12-21 15:45:35 +02:00
botpub
07c7eacab9 Release Pelican 4.10.2
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
2024-11-27 19:53:23 +00:00
Scott Colby
d9652ef109
fix: SUMMARY_MAX_PARAGRAPHS not respected in some combinations with SUMMARY_MAX_LENGTH (#3427) 2024-11-27 20:51:03 +01:00
Justin Mayer
7096b0a168
Merge pull request #3424 from projectgus/settings/ignore_files 2024-11-27 20:37:49 +01:00
Justin Mayer
ac28ddb9bf
Merge pull request #3425 from mart-e/replacement-indicator-log-full 2024-11-27 20:30:00 +01:00
Martin
31538d1578 [IMP] add information in error message
Not always clear what was the issue with only the keyword
2024-11-11 14:54:48 +01:00
Angus Gratton
1edca55253 settings: Change the default IGNORE_FILES to all "hidden" files.
This is to avoid subtle behaviour that contributed to root cause of
https://github.com/pelican-plugins/sitemap/issues/36

Specifically: if installing Pelican into a local virtualenv with the pdm or uv
default name ".venv", then subdirectories of .venv will contain all of the test
.rst and .md files.

If you then run Pelican in that same root directory using the default PATH
value (".") then it will add those content files to the site.
2024-11-10 12:05:02 +11:00
Justin Mayer
882cd16e11
Merge pull request #3423 from GeorgeHu6/chinese-translation
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
Docs: Update Chinese translation
2024-11-08 10:57:37 +01:00
GeorgeHu6
60261b8c99 Doc: update Chinese translation 2024-11-07 16:31:32 +08:00
Justin Mayer
4ca1454293
Merge pull request #3421 from boxydog/precommit_update_202411
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
2024-11-03 20:57:55 +01:00
boxydog
075542721c pre-commit autoupdate and fix new issues pointed out by ruff 2024-11-03 13:32:32 -06:00
Noel Miller
0da2530d9b
De-couple build workflow from GitHub Pages publication (#3404)
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
2024-10-22 09:59:19 -07:00
Justin Mayer
31264498e1
Add FAQ entry about theme overrides (#3406)
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
2024-10-17 09:13:39 -07:00
Frederik Elwert
92050d90bc Add FAQ regarding theme overrides
Currently, the documentation refers to creating new themes a lot.
It is much less apparent how one can customize an existing theme by
overriding individual templates or adding new ones. This commit adds
an FAQ for this, and also mentions the mechanism in the FAQ on custom
templates.
2024-10-10 14:35:07 +02:00
Justin Mayer
b02abf0220 Improve GitHub issue templates
Some checks failed
build / Test - 3.10 - macos (push) Has been cancelled
build / Test - 3.11 - macos (push) Has been cancelled
build / Test - 3.12 - macos (push) Has been cancelled
build / Test - 3.10 - ubuntu (push) Has been cancelled
build / Test - 3.11 - ubuntu (push) Has been cancelled
build / Test - 3.12 - ubuntu (push) Has been cancelled
build / Test - 3.8 - ubuntu (push) Has been cancelled
build / Test - 3.9 - ubuntu (push) Has been cancelled
build / Test - 3.10 - windows (push) Has been cancelled
build / Test - 3.11 - windows (push) Has been cancelled
build / Test - 3.12 - windows (push) Has been cancelled
build / Lint (push) Has been cancelled
build / Test build (push) Has been cancelled
build / Build docs (push) Has been cancelled
build / Deploy (push) Has been cancelled
2024-10-04 15:06:11 +02:00
Justin Mayer
f5dc4d4b96 Disable blank GitHub issues
Existing issue template categories should cover most any case.
2024-10-04 15:04:13 +02:00
Justin Mayer
478012e0d0 Clarify _include_path() parameter docstring 2024-10-02 19:08:26 +02:00
botpub
b86383fb28 Release Pelican 4.10.1 2024-09-28 17:02:04 +00:00
Justin Mayer
fe45094545 Prepare release 2024-09-28 18:59:03 +02:00
Frederik Elwert
08283b4915
Fix symbolic link handling in pelican-themes -s/-c (#3392) 2024-09-28 18:55:22 +02:00
Justin Mayer
0cb445c813
Don't store a RichHandler object in the argparse namespace (#3394) (#3398) 2024-09-28 18:50:54 +02:00
Clément Pit-Claudel
6c6b940ffc Don't store a RichHandler object in the argparse namespace (#3394) 2024-09-20 18:49:23 +02:00
Lioman
84db21c724
Match actual version instead of regex in build CI job (#3396) 2024-09-20 14:46:29 +02:00
Justin Mayer
2f9d382c56
Fix build job failure in GitHub CI workflow (#3395) 2024-09-20 14:35:07 +02:00
Lioman
86bf9230b4 test: fix build test
the regex, searching for the builded files was not stable to changes for two digit versions.

fixes: Build test failures in GitHub CI workflow #3393
2024-09-19 14:25:01 +02:00
botpub
a5db130e1d Release Pelican 4.10.0 2024-09-16 13:23:38 +00:00
Justin Mayer
9e8af627b5 Prepare release 2024-09-16 15:16:43 +02:00
Justin Mayer
44db258f59 Adjust list of Git-ignored files 2024-09-16 15:11:14 +02:00
GeorgeHu
e609b4d78a
Translate documentation into Simplified Chinese (#3346) 2024-09-15 14:29:01 +02:00
Egbert
5687883d4b
Bump Pygments to 2.16.1 in test requirements; fixes #3385 (#3386) 2024-09-12 14:21:12 +02:00
Justin Mayer
84f2995b38
Merge pull request #3387 from gagath/optimize-taskspy-template 2024-09-12 13:33:38 +02:00
GiovanH
4201256a5b
Add disabled status for #3304 (#3305) 2024-09-12 13:28:51 +02:00
Agathe Porte
2d375bc135 tasks.py.jinja2: optimize imports
When opening the generated tasks.py file with a Python linter enabled,
some imports will be marked as unecessary depending on the options
passed to pelican-quickstart.

Add if statements around the optional imports so they are used
only when necessary.
2024-08-04 22:39:50 +09:00
Justin Mayer
bb0ed26fdd Document how to have same source & output hierarchy 2024-07-30 10:00:36 +02:00
Justin Mayer
d85f493ee3 Add initial configuration for Vale prose linter
Vale: <https://github.com/errata-ai/vale>
2024-07-30 09:56:27 +02:00
Agathe
513abbfdc6
Introduce paragraph count summary (#2761)
Co-authored-by: Justin Mayer <entroP@gmail.com>
2024-06-25 15:07:41 +02:00
Justin Mayer
ef501a3d89
Merge pull request #3345 from getpelican/main-default-branch 2024-06-25 11:40:03 +02:00
Justin Mayer
36ebe91af7 Rename default branch to main 2024-06-25 11:33:28 +02:00
Justin Mayer
28e54106f2 Update Ruff linter 2024-06-25 11:00:41 +02:00
Justin Mayer
bdd4e45628 Enforce 75% code coverage in CI via Tox 2024-06-25 10:54:24 +02:00
Justin Mayer
6a50191728 Tweak Markdown-not-installed console warnings
Adding single-quotation marks should cause 'markdown' to be highlighted
in green, presumably via Rich.
2024-06-25 10:49:07 +02:00
Justin Mayer
f89f8894cc
Merge pull request #3321 from boxydog/warn_about_markdown 2024-06-25 10:10:34 +02:00
Justin Mayer
6fec5786d0
Merge pull request #3339 from tpwo/patch-1 2024-06-19 22:52:20 +02:00
Tomasz Wojdat
5171631dec
chore: update URLs of GitHub Ribbons
Old URLs are no longer active. New ones were taken from GitHub blog:
https://github.blog/2008-12-19-github-ribbons/

Also update output in functional tests.
2024-06-19 19:11:41 +02:00
Justin Mayer
8d63d1ced8
Merge pull request #3338 from getpelican/remove-sphinx-ifconfig 2024-06-18 09:27:03 +02:00
Justin Mayer
49723e6daf Docs: Remove ifconfig Sphinx extension
Originally added in #815, something about this seems to be causing an
obscure ReadTheDocs build error.
2024-06-18 09:08:45 +02:00
Justin Mayer
993c75103b Generate social cards in Sphinx documentation
Without `matplotlib` installed, Sphinx output says that social cards
cannot be generated.
2024-06-18 09:04:59 +02:00
Justin Mayer
7a2c72e604
Merge pull request #3337 from getpelican/document-feed-domain-optional 2024-06-17 22:22:59 +02:00
Justin Mayer
05535c7d6c Docs: GitHub Pages workflow is now supported 2024-06-17 22:19:21 +02:00
Sean Hammond
853e9e6b8a
Document that feed_domain is not required 2024-06-17 20:46:28 +01:00
dependabot[bot]
617aba077f Bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 21:14:49 +02:00
dependabot[bot]
487877f206 Bump actions/deploy-pages from 2 to 4
Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 2 to 4.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 21:14:31 +02:00
dependabot[bot]
750a1f8bfa Bump actions/configure-pages from 3 to 5
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 3 to 5.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](https://github.com/actions/configure-pages/compare/v3...v5)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 21:14:18 +02:00
dependabot[bot]
d03ae2a41f Bump actions/upload-pages-artifact from 2 to 3
Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 21:13:54 +02:00
Justin Mayer
b17182ece1
Merge pull request #3330 from seanh/gha-theme-support 2024-06-17 20:43:09 +02:00
Justin Mayer
50f77b42b2 Add CODEOWNERS file to project 2024-06-17 20:36:18 +02:00
Sean Hammond
135c61f769
Add Dependabot to GitHub Actions workflow docs 2024-06-17 16:38:10 +01:00
boxydog
f19de98b9e Log warnings about files that would have been processed by disabled readers 2024-06-17 09:30:55 -05:00
Sean Hammond
e46595cdac
Add theme, Python version, siteurl and feed_domain to GitHub Pages deployment workflow
Add theme, Python version, siteurl and feed_domain support to the
reusable GitHub Actions workflow for deploying a Pelican site to GitHub
Pages:

1. Add a new `theme` option to the workflow that callers can use to
   specify an external theme to be checked out and used

2. Add a new `python` option to the workflow that callers can use to
   specify the Python version, in case they need to build their site
   with a particular version of Python

3. Pass `--extra-settings FEED_DOMAIN='"${{ steps.pages.outputs.base_url }}"'`
   to the `pelican` command to set the value of Pelican's `FEED_DOMAIN`
   setting for feed URLs.

4. Add a `feed_domain` input to the workflow so that users can override
   the feed domain if they need to.

5. Add a `siteurl` input to the workflow so that users can override the
   site URL if they need to.

6. Add a note to the docs about GitHub Pages generating http:// URLs for
   https:// sites, and how to fix it

7. Some light editing of the docs for the workflow
2024-06-17 13:57:10 +01:00
Justin Mayer
79d37ba491
Merge pull request #3328 from seanh/gha-dependabot 2024-06-17 13:43:27 +02:00
Sean Hammond
dc40474e29
Use Dependabot to keep GitHub Actions up to date
Configure Dependabot to send automated PRs to update the version numbers
in `.github/workflows/*.yml` when new versions of actions are released.

See:

https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
2024-06-17 12:39:07 +01:00
Justin Mayer
5c7e4bbac4
Merge pull request #3325 from boxydog/master 2024-06-16 20:22:59 +02:00
Justin Mayer
b80a592d30 Lower minimum coverage required in invoke coverage 2024-06-16 19:37:23 +02:00
Justin Mayer
d83c5029b8
Merge pull request #3323 from boxydog/coverage 2024-06-16 19:30:10 +02:00
Justin Mayer
e262990c68 Tweak docs about test coverage and git blame 2024-06-16 19:23:46 +02:00
Justin Mayer
fd955ba054 Show missing line numbers via invoke coverage
Also includes a change that causes this command to return a failing
status when coverage drops below its current value of 74.8%.
2024-06-16 19:16:58 +02:00
boxydog
8c7c29e4f2
Add dependabot checking (#5) 2024-06-02 14:03:56 -05:00
Justin Mayer
657ad64f49
Merge pull request #3322 from boxydog/more_ruff5 2024-06-02 09:05:29 +02:00
Justin Mayer
af9865d317 Ignore Ruff UP031 fixes in git blame 2024-06-02 09:01:21 +02:00
boxydog
b77bb690e2 Improve test coverage, docs, and .gitignore 2024-06-01 18:51:46 -05:00
boxydog
30bde3823f ruff UP031 in files: use format specifiers instead of percent format 2024-06-01 16:00:17 -05:00
boxydog
3e81af966a ruff UP031: use format specifiers instead of percent format 2024-06-01 16:00:07 -05:00
Justin Mayer
8fd94ea025
Merge pull request #3320 from boxydog/d_more_ruff4 2024-05-31 18:35:59 +02:00
boxydog
82b48fcfa1 Fixes in files for ruff T201, RUF001, PLR2004, B904, SLOT000, PYI024, PIE800 2024-05-31 10:41:24 -05:00
boxydog
fc45791da4 Fix or ignore ruff T201, RUF001, PLR2004, B904, SLOT000, PYI024, PIE800 2024-05-31 10:41:09 -05:00
Justin Mayer
2687475fba
Merge pull request #3318 from boxydog/more_ruff_fixes3 2024-05-31 16:56:47 +02:00
boxydog
9b77a9027b File fixes for ruff B007, RUF015, PLR1722 2024-05-31 08:48:44 -05:00
boxydog
cbe6c08f44 Don't ignore ruff B007, RUF015, PLR1722 2024-05-31 08:48:32 -05:00
Justin Mayer
ccb4e58882
Merge pull request #3315 from boxydog/jinja_precommit 2024-05-31 14:50:46 +02:00
Justin Mayer
37ba4fc21a Ignore DjHTML indentation changes in git blame 2024-05-31 14:46:06 +02:00
boxydog
4af40e8077 pre-commit filter auto-indents templates, css, js 2024-05-31 07:34:01 -05:00
boxydog
7f07c220de Add pre-commit djhtml, djcss, djjs to indent templates 2024-05-31 07:33:03 -05:00
Justin Mayer
270fd4edcc
Merge pull request #3316 from boxydog/apply_filters_to_test_output 2024-05-31 14:28:47 +02:00
boxydog
98bdd87dae Apply pre-commit filters to the files in pelican/tests/output 2024-05-31 07:21:40 -05:00
boxydog
308af1912e Apply pre-commit filters to pelican/tests/output 2024-05-31 07:21:13 -05:00
Justin Mayer
59756f8faf
Merge pull request #3314 from boxydog/more_ruff_fixes2 2024-05-30 21:45:55 +02:00
Justin Mayer
3569dede01 Ignore more Ruff fixes in git blame 2024-05-30 21:40:27 +02:00
boxydog
7577dd7603 More ruff fixes in files: stop ignoring C408, UP007, PLR5501, B006 2024-05-30 13:21:12 -05:00
boxydog
3624bcdbf4 More ruff fixes: stop ignoring C408, UP007, PLR5501, B006 2024-05-30 13:20:51 -05:00
Justin Mayer
880e9769e8
Merge pull request #3312 from boxydog/more_ruff_fixes 2024-05-30 19:46:58 +02:00
Justin Mayer
144b2edf88 Ignore more Ruff fixes in git blame 2024-05-30 19:40:45 +02:00
boxydog
9d30c5608a Code changes for more ruff checks 2024-05-30 12:21:52 -05:00
boxydog
b6d3b65899 More ruff checks 2024-05-30 12:21:52 -05:00
Justin Mayer
425f302880
Merge pull request #3313 from boxydog/upgrade_ruff 2024-05-30 19:20:32 +02:00
Justin Mayer
9d46a94d6d Ignore Ruff 0.4.x fixes in git blame 2024-05-30 19:15:56 +02:00
boxydog
54ac03fca6 change ruff version in pyproject.toml 2024-05-30 10:56:06 -05:00
boxydog
0bd02c00c0 Ruff v0.4.6 auto-fixes 2024-05-30 10:53:38 -05:00
boxydog
800f22b3ba Upgrade ruff to v0.4.6, pre-commit-hooks to v4.6.0 2024-05-30 10:49:57 -05:00
Clément Pit-Claudel
39c964450c
Choose logging handler via --log-handler CLI option (#3293) 2024-05-30 17:13:27 +02:00
Justin Mayer
c46063cfc3 Ignore latest Ruff fixes in git blame 2024-05-30 16:42:09 +02:00
Justin Mayer
8d8feb6341
Merge pull request #3311 from boxydog/fix_3216_two_commits 2024-05-30 16:33:57 +02:00
boxydog
6d8597addb The ruff and ruff-format fixes 2024-05-30 09:08:16 -05:00
boxydog
4f46fedd73 More Ruff checks, and make it fix 2024-05-30 09:04:58 -05:00
Justin Mayer
f0b6e8732f
Merge pull request #3310 from boxydog/fix_3309
Fix collection error with `test_deprecated_attribute` test
2024-05-30 07:34:08 +02:00
boxydog
1001dcb609 Fix test_deprecated_attribute failures in github tests 2024-05-29 16:36:20 -05:00
Justin Mayer
e4d7f0a9d9 Docs: GitHub Pages workflow not officially supported 2024-05-29 07:29:33 +02:00
GiovanH
0b5934a1fa
Feature: Add setting to append ref parameter to links in feeds (#3249) 2024-04-19 20:54:27 +02:00
Justin Mayer
0f5179b816
Merge pull request #3301 from avaris/gha-windows 2024-04-19 20:38:59 +02:00
Deniz Turgut
666b962eb6
workaround Turkish locale issue 2024-04-19 21:08:26 +03:00
Justin Mayer
94bcd41f27 Ignore Sphinx 7.2.x package install warnings
Sphinx 7.2+ requires Python 3.9+, which results in annoying warnings
since we still support Python 3.8.x.
2024-03-27 08:26:55 +01:00
Justin Mayer
b87308cfaa Update Ruff dependency version 2024-03-27 08:26:24 +01:00
Justin Mayer
fabc409277 Update more GitHub Actions to resolve warnings 2024-03-12 12:18:11 +01:00
Justin Mayer
7454138184 Update setup-python & setup-pdm GitHub Actions 2024-03-12 12:07:53 +01:00
Justin Mayer
7c7c9355b6 Pin Ruff to major semantic version 0.1.x
Upgrading to 0.3.0+ requires code style changes to the code base.
2024-03-12 11:57:46 +01:00
Justin Mayer
960aee5907
Merge pull request #3280 from MinchinWeb/summary-links 2024-01-29 15:06:18 +01:00
Justin Mayer
8a01cb11e1
Merge pull request #3276 from MinchinWeb/plugin-error-loading 2024-01-29 15:03:51 +01:00
MinchinWeb
1f14606f83 On failing to load a plugin, show the stacktrace is pelican is run in debug mode 2024-01-27 10:51:35 -07:00
MinchinWeb
f1f2ceccc7 Warning/error logging: be explicit in how the stacklevel variable is handled 2024-01-27 10:47:54 -07:00
MinchinWeb
c36ab07526 write back to ._summary 2024-01-26 16:31:22 -07:00
Justin Mayer
ff35d26cbc
Merge pull request #3264 from boxydog/medium_importer 2024-01-26 10:02:54 +01:00
Justin Mayer
dbf90a4821
Merge pull request #3278 from bjoernricks/contents-types 2024-01-24 22:54:01 +01:00
Björn Ricks
e4807316ae
Add type hints for utils module
Types make it easier to understand the code and improve autocompletion
in IDEs.
2024-01-24 16:15:50 +01:00
Björn Ricks
3a662ace03
Add type hints for contents module
Types make it easier to understand the code and improve autocompletion
in IDEs.
2024-01-23 11:33:24 +01:00
namori
2fa5c515b0
Feeds - Update generators.py to fix a bug with slugs (#3279) 2024-01-23 09:43:07 +01:00
MinchinWeb
d39dd9b85f Resolve inter-site links in summaries.
c.f. https://github.com/getpelican/pelican/issues/3265
c.f. https://github.com/MinchinWeb/minchin.pelican.plugins.summary/issues/5
2024-01-21 23:13:21 -07:00
Justin Mayer
f2ab4a1dc1
Merge pull request #3251 from snosratiershad/support/new-line-at-end-of-scripts 2024-01-17 12:10:45 +01:00
Justin Mayer
fbe81a971a
Delete RELEASE.md 2024-01-17 09:48:05 +01:00
Justin Mayer
def0899f10
Merge pull request #3267 from bjoernricks/setting-types 2024-01-17 09:44:42 +01:00
boxydog
d6a33f1d21 Medium post importer (from medium export) 2024-01-16 16:56:07 -06:00
Salar Nosrati-Ershad
b1cb6c7326
Use --no-jekyll flag when invoking ghp-import (#3259) 2024-01-15 11:10:12 +01:00
Salar Nosrati-Ershad
5e6dba73ac
Add Github Pages commit message variable (#3250) 2024-01-15 11:03:54 +01:00
boxydog
bf4fd679a5
Document how to import posts from Medium (#3262) 2024-01-15 10:43:19 +01:00
Björn Ricks
f69e2cca6b
Add type hints for settings module
Types make it easier to understand the code and improve autocompletion
in IDEs.
2024-01-15 09:05:14 +01:00
MinchinWeb
f0beb81a97 Better error logging if a plugin refuses to load 2024-01-14 13:45:51 -07:00
Justin Mayer
5d3e87b50b
Merge pull request #3269 from das-g/patch-1 2024-01-12 20:00:53 +01:00
Justin Mayer
af37f0656f
Merge pull request #3257 from MinchinWeb/real-logging 2024-01-09 21:51:58 +01:00
Raphael Das Gupta
8626d5bd85
docs: update URL to AsciiDoc website
https://www.methods.co.nz/asciidoc/
gives a SSL certificate warning
and a 404 (page not found) error.
https://asciidoc.org is the new official website
for the AsciiDoc file format.
(It's also what https://en.wikipedia.org/wiki/AsciiDoc links to.)
2023-12-22 15:56:57 +01:00
Justin Mayer
2d75ca8391
Merge pull request #3260 from pauloxnet/update_pipeline_settings 2023-11-29 08:22:44 +01:00
Paolo Melchiorre
61eacffa90
Update tox and GitHub pipeline 2023-11-28 21:38:26 +01:00
MinchinWeb
4ed5c0d5b8 Log the original calling location, rather than the wrapper function 2023-11-25 20:57:40 -07:00
Salar Nosrati-Ershad
7466b13e0a fix: keep newline at the end of the file in tools
As referenced in Jinja documentation about whitespace control:
<https://jinja.palletsprojects.com/en/3.1.x/templates/#whitespace-control>
>  To keep single trailing newlines, configure Jinja to
>  `keep_trailing_newline`
I added this to our Jinja environment to keep EOL new line in tools
scripts
2023-11-22 22:54:42 +03:30
Vivek Bharadwaj
d9b2bc3a4e
Add GH pages action to fix file permissions (#3248) 2023-11-19 10:48:13 +01:00
botpub
7194cf5795 Release Pelican 4.9.1 2023-11-15 17:16:23 +00:00
Justin Mayer
a1d475fb22
Merge pull request #3246 from MinchinWeb/tz-windows 2023-11-15 18:13:19 +01:00
Justin Mayer
6fd2c0d8e6
Merge branch 'master' into tz-windows 2023-11-15 18:08:49 +01:00
Justin Mayer
76f7343b61 Prepare release 2023-11-15 18:08:10 +01:00
Justin Mayer
f510b4b21f Remove reference to non-existent requirements file 2023-11-15 17:52:41 +01:00
MinchinWeb
a2525f7db4 Remove tzdata from testing requirements.
Should be installed by pelican directly, if needed, based on OS.
2023-11-13 14:42:29 -07:00
MinchinWeb
1d0fd456e8 Add tzdata requirement on Windows 2023-11-13 12:18:41 -07:00
botpub
6cd707a668 Release Pelican 4.9.0 2023-11-12 17:44:45 +00:00
Justin Mayer
7ca66ee9d0 Prepare release 2023-11-12 18:03:36 +01:00
Justin Mayer
9525583ccd
Merge pull request #3243 from avaris/remove-write-selected 2023-11-12 17:56:34 +01:00
Deniz Turgut
86d6898517
remove WRITE_SELECTED
Implementation is buggy and unreliable. Therefore, it is better to
remove the functionality until a robust implementation is added.
2023-11-12 19:43:26 +03:00
Justin Mayer
0c5d63c69e Update documentation related to contributing 2023-11-12 17:11:23 +01:00
Justin Mayer
eca501ac1e
Merge pull request #3242 from pauloxnet/issues/2888 2023-11-12 16:04:28 +01:00
Justin Mayer
e92ccb8a46
Merge pull request #3241 from getpelican/pyupgrade-py38-plus 2023-11-12 16:02:38 +01:00
Justin Mayer
2238dcab07 Ignore code format commits from git blame 2023-11-12 15:53:13 +01:00
Paolo Melchiorre
db241feaa4
Fix #2888 -- Apply ruff and pyupgrade to templates 2023-11-12 15:06:02 +01:00
Justin Mayer
ecd598f293 Update code base for Python 3.8 and above
Result of: pipx run pyupgrade --py38-plus pelican/**/*.py
2023-11-12 13:53:02 +01:00
Justin Mayer
903ce3ce33 Pin Furo doc theme version
We override its page.html template with our own, so it is better to
manually and explicity upgrade rather than have a future version
of the Furo theme potentially break the documentation build.
2023-11-12 13:41:38 +01:00
Justin Mayer
39ff56a082 Update development dependencies 2023-11-12 13:38:30 +01:00
Justin Mayer
be5afa3175
Merge pull request #3234 from pauloxnet/feature/3233-simple-classless-semantic-html 2023-11-12 07:58:12 +01:00
Paolo Melchiorre
6059675d55
Fix #3233 -- Simple theme classless semantic HTML 2023-11-11 14:10:08 +01:00
Justin Mayer
d7015db9e4
Merge pull request #3240 from avaris/remove-icons 2023-11-09 09:06:53 +01:00
Deniz Turgut
e014e5b55b
add notmyidea font license 2023-11-04 01:00:51 +03:00
Deniz Turgut
451b094a94
remove social icons from notmyidea theme
redistribution of these icons may not be compatible with AGPL
2023-11-04 00:54:21 +03:00
Justin Mayer
dc1b6ab14d
Merge pull request #3238 from avaris/ordered-blinker 2023-11-02 23:27:15 +01:00
Deniz Turgut
8a8b952ecb
preserve connection order in blinker 2023-11-03 01:13:12 +03:00
Justin Mayer
14f19474df
Merge pull request #3235 from avaris/plugin-enabled 2023-11-02 16:58:42 +01:00
Justin Mayer
32b72123f0
Modify wording slightly 2023-11-02 14:09:51 +01:00
Justin Mayer
ee10d6995a
Merge pull request #3236 from avaris/missing-dependency 2023-11-01 23:10:34 +01:00
Deniz Turgut
49aef30dab
add sphinxext-opengraph to pyproject dev requirements 2023-11-01 23:19:26 +03:00
Deniz Turgut
feae8ef41c
Provide a plugin_enabled Jinja test for themes 2023-11-01 22:49:15 +03:00
Justin Mayer
76650898a6 Update to Markdown 3.5.1 in test requirements 2023-11-01 09:43:21 +01:00
Justin Mayer
e6a5e2a665 Update pre-commit hook versions 2023-11-01 09:07:48 +01:00
Justin Mayer
abae21494d Adjust line length to 88 in EditorConfig 2023-10-31 16:50:48 +01:00
Justin Mayer
a20cd8dda5
Merge pull request #3231 from getpelican/enforce-code-style 2023-10-30 19:49:58 +01:00
Justin Mayer
3c57996945 Ignore Ruff format commit in the blame view 2023-10-30 19:45:42 +01:00
Justin Mayer
08785f714f Remove obsolete linters: Flake8, Black, isort 2023-10-30 19:35:59 +01:00
Lioman
4e438ffe60
Enable tests to validate dist build contents (#3229) 2023-10-30 16:04:44 +01:00
Justin Mayer
6f467fefdc
Merge pull request #3232 from avaris/git-test-fix 2023-10-29 23:25:26 +01:00
Deniz Turgut
f0aab11a2d
Force git subprocess in tests to use utf-8 2023-10-30 00:53:15 +03:00
boxydog
805ca9b4a9 Run pre-commit on all files during CI test job 2023-10-29 22:21:04 +01:00
Chris Rose
271f4dd68f Strip trailing whitespace 2023-10-29 22:19:44 +01:00
Chris Rose
cabdb26cee Apply code style to project via: ruff format . 2023-10-29 22:18:29 +01:00
Chris Rose
8ea27b82f6 Bump all of the dev dependencies
- remove upper version caps
- updated the minimum version of most of Pelican's runtime deps
- replaced black with ruff as a formatter for pelican
- added a cache step to the docs CI task so that the docs can be
  downloaded and inspected.
2023-10-29 22:11:28 +01:00
Justin Mayer
bfb2587697
Merge pull request #3228 from boxydog/fix_1463 2023-10-29 20:03:37 +01:00
boxydog
dbe0b1125f Don't copy file ownership, permissions and metadata 2023-10-29 12:55:37 -05:00
Justin Mayer
a23a4e14cf
Merge pull request #3189 from seanh/publish-to-ghp-using-gha 2023-10-29 18:29:52 +01:00
Deniz Turgut
6f1605edf9
Extend GHA documentation to specify requirements file 2023-10-29 18:30:25 +03:00
Justin Mayer
842c6537f1
Merge pull request #3226 from getpelican/manifest 2023-10-29 16:16:40 +01:00
Justin Mayer
9437de6341 Include more files in PDM sdist builds
This was previously the job of directives in MANIFEST.in, which should
be covered by this PDM-specific configuration.
2023-10-29 16:12:09 +01:00
Justin Mayer
cce1570135 Fix some comments in wheel-related test 2023-10-29 15:53:11 +01:00
Justin Mayer
73599f44f2
Merge pull request #3220 from lioman/centralize-python-information 2023-10-29 15:43:41 +01:00
Lioman
8a0f335e2b only install dev dependencies during lint step 2023-10-29 15:23:14 +01:00
Justin Mayer
165d57eff5
Merge pull request #3127 from mart-e/no-inifinite-feed 2023-10-29 14:23:28 +01:00
Lioman
eb052cae09 Capitalize PDM in docs 2023-10-29 12:41:55 +01:00
Lioman
00d26fc068 remove old setup files 2023-10-29 12:01:42 +01:00
Lioman
8b6d215934 migrate configuration to PEP621 compatible config
- adapt documentation
- add wheel tests to check wheel contents.
- adapt pipeline to use pdm
- adapt autopub config
- add scripts as shortcuts to invoke tasks
2023-10-29 11:59:58 +01:00
Justin Mayer
c18f1a7308 Re-order pyproject items, with other small fixes 2023-10-29 08:48:37 +01:00
Lioman
a76a419585 migrate configuration to PEP621 compatible one 2023-10-29 08:48:37 +01:00
boxydog
fad2ff7ae3
Add unit test utilities temporary_locale and TestCaseWithCLocale (#3224) 2023-10-29 00:40:40 +02:00
Justin Mayer
fec78ebf33
Merge pull request #3225 from boxydog/test_coverage 2023-10-29 00:36:29 +02:00
boxydog
3a6ae72333 Add a "coverage" task to generate a coverage report
Add a one-liner about "invoke" in docs.
2023-10-28 17:35:00 -05:00
Justin Mayer
84795c701c
Merge pull request #3222 from offbyone/test-on-macos 2023-10-28 23:26:24 +02:00
Justin Mayer
3dce25ab23
Merge pull request #3151 from RealOrangeOne/feature/watchfiles 2023-10-28 23:23:44 +02:00
Justin Mayer
269751b033
Merge pull request #3223 from offbyone/switch-to-ruff 2023-10-28 22:38:26 +02:00
Justin Mayer
85bf98232d
Merge pull request #3148 from djramones/period-archives-context 2023-10-28 22:22:11 +02:00
Will Thong
8a7e01646b
Add rel='nofollow' to all external hardcoded links in templates (#3162) 2023-10-28 22:11:44 +02:00
Yasser Tahiri
b812f2ad1c
chore: Simplify boolean if expression (#2944) 2023-10-28 22:06:24 +02:00
Justin Mayer
e14f20bb99
Merge pull request #2758 from MinchinWeb/settings-pathlib-2 2023-10-28 21:56:34 +02:00
Deniz Turgut
b8d5919cd2
expand period tests to be more specific 2023-10-28 22:11:11 +03:00
Chris Rose
33d6712e8b
Don't install pelican's dependencies to lint 2023-10-28 11:18:24 -07:00
Chris Rose
29b10ef6e6
Use poetry directly in lints 2023-10-28 11:05:15 -07:00
Chris Rose
6cf6a1ffe9
Ruff lint fixes 2023-10-28 11:05:15 -07:00
Chris Rose
58fd855385
inv task now uses ruff 2023-10-28 11:05:15 -07:00
Chris Rose
19c797af5e
Add support to verify windows, too 2023-10-28 10:55:01 -07:00
Chris Rose
7dfc799f25
Use ruff in pre-commit 2023-10-28 10:44:47 -07:00
Chris Rose
f342dc3097
Add macOS testing for 3.11/3.12 2023-10-28 08:00:27 -07:00
Deniz Turgut
43e513f218
run pelican first before waiting for changes 2023-10-28 17:37:56 +03:00
Deniz Turgut
b289dcea82
don't watch not existing paths 2023-10-28 17:30:45 +03:00
Jake Howard
631ac1bdb3
Cleanup imports 2023-10-28 17:17:14 +03:00
Jake Howard
b388057d66
Remove unused extensions list 2023-10-28 17:15:56 +03:00
Jake Howard
5519efef2e
Log watching files which don't exist 2023-10-28 17:15:55 +03:00
Jake Howard
7643e0e92b
Make sure the package depends on watchfiles 2023-10-28 17:15:54 +03:00
Jake Howard
61ca47c519
Use watchfiles as a file watching backend
This doesn't use polling unless absolutely necessarily, making it more efficient. It also reduces the amount of first-party code required, and simplifies working out which files are being watched.
2023-10-28 17:15:54 +03:00
Justin Mayer
6ed7395812
Merge pull request #3221 from avaris/importer-fixes 2023-10-28 16:10:47 +02:00
Deniz Turgut
11c13ceae1
use a tempfile for intermediate html file for pandoc in importer 2023-10-28 16:50:34 +03:00
Deniz Turgut
83a8059d02
force timestamp conversion in tumblr importer to be UTC with offset and adjust tests 2023-10-28 16:50:34 +03:00
Justin Mayer
a20bbb55d6
Merge pull request #3044 from copperchin/fix-3042 2023-10-28 14:28:42 +02:00
Gullumluvl
dc427ad9d6
Strip HTML tags from SITENAME inside title tags. Fixes #3147 (#3149) 2023-10-28 14:24:16 +02:00
Deniz Turgut
b6a9a8333b
skip tests that require git if git is not installed
and minor tweaks to subprocess handling
2023-10-28 14:57:33 +03:00
boxydog
9c87d8f3a3
Deal with broken embedded video links when importing from Tumblr (#3218)
Co-authored-by: boxydog <boxydog@users.noreply.github.com>
Co-authored-by: Will Thong <will@willthong.com>
2023-10-28 12:56:00 +02:00
Justin Mayer
6a623ba10a
Merge pull request #3119 from getpelican/remove-pkg_resources 2023-10-28 11:34:47 +02:00
Justin Mayer
865f7b10dd Replace deprecated pkg_resources
importlib.metadata.version() appears to be the anointed replacement.
2023-10-28 11:29:50 +02:00
Justin Mayer
91d9ef7a70 Add tzdata as dependency in test requirements
Otherwise yields the following error with Python 3.10 on Windows:

zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key UTC'
2023-10-28 11:17:48 +02:00
Lioman
58e70082e0 Remove python 3.7 build configuration 2023-10-28 11:05:29 +02:00
Justin Mayer
8fd5d6f51b Fix IRC server in new GitHub issue template 2023-10-28 09:55:16 +02:00
boxydog
1404a2dbc3
Remove newline when importing Tumblr post photos (#3215)
Co-authored-by: Dan Frankowski <dfrankow@gmail.com>
2023-10-27 21:56:34 +02:00
Justin Mayer
fab6e1a2c5 Fix warning re: future dates setting. Fixes #3184 2023-10-24 11:07:25 +02:00
Justin Mayer
777a708ef7
Merge pull request #3198 from mart-e/remove-posterous 2023-10-24 10:22:19 +02:00
Justin Mayer
620139cdaf
Merge pull request #3141 from mart-e/wp-caption-to-figure 2023-10-24 10:20:22 +02:00
Justin Mayer
0282c1d6eb
Merge pull request #3200 from lioman/don't-run-deploy-on-fork 2023-10-24 10:15:03 +02:00
Justin Mayer
4caf9a88a2
Merge pull request #3204 from FriedrichFroebel/dataclass-in-settings 2023-10-24 10:12:38 +02:00
Justin Mayer
36b4c6dc08
Merge pull request #3205 from getpelican/sphinx-opengraph 2023-10-18 08:36:48 +02:00
Justin Mayer
a8fefad331 Add OpenGraph metadata to docs via Sphinx extension 2023-10-13 08:01:29 +02:00
FriedrichFroebel
ab9e55b398
Allow dataclasses in settings 2023-10-11 19:29:17 +02:00
Martin Trigaux
5d8c03108b Remove Posterous integration
Posterous closed down in 2013.
The API is no longer accessible and the code did not work in python 3
(base64.encodestring was expecting bytes, not string)
2023-10-06 09:34:26 +02:00
Lioman
5c36cfbb9b Only run 'Deploy' action on main repository
Deploy action will always fail on forks as the token is not there.
2023-10-04 10:58:18 +02:00
Justin Mayer
82e2571754
Merge pull request #3199 from lioman/add-pythen-3.12-to-tests 2023-10-03 18:04:38 +02:00
Lioman
de0fae8182 Add python 3.12 to test matrix 2023-10-03 16:59:57 +02:00
Martin (mart-e)
48166bd687 Convert Wordpress caption to figure
In Wordpress, inserting image with a caption can look like:

[caption id="attachment_42" caption="Image Description"]<a ...><img ... /></a>[/caption]
[caption id="attachment_42"]<a ...><img ... /></a> Image Description[/caption]
[caption id="attachment_42"]<img ... > Image Description[/caption]

Replace by an HTML figure tag
2023-10-03 11:45:31 +02:00
Sean Hammond
29185e4ad7
Add GitHub Actions workflow for GitHub Pages
Add a GitHub Actions workflow that users can use to publish their
Pelican sites to GitHub Pages by running `pelican` on GitHub Actions,
without having to run `pelican` locally and push the output directory to
a branch.

See: https://github.com/getpelican/pelican/discussions/3174
2023-09-03 15:15:39 +01:00
Justin Mayer
3be0703b14 Tell GitHub-Linguist to ignore HTML files
Refs #3188
2023-08-27 16:47:45 +02:00
Justin Mayer
e724de9ffe Improve GitHub-Linguist language breakdown
Refs #3188
2023-08-27 16:39:27 +02:00
DJ Ramones
30adfba1ca
Revert *_ARCHIVE_URL default settings to blank 2023-08-17 02:35:39 +08:00
DJ Ramones
8a5f02ac60
Move _build_period_archives out of generate_context
So that we don't contribute to further clutter in generate_context.
2023-08-17 02:04:06 +08:00
Will Thong
2eeff62fd7
Replace pytz dependency in tests (#3165) 2023-08-15 20:07:39 +02:00
Moritz Meier
0d1bcd4b11
Pelican QuickStart: Address tzlocal API change (#3155) 2023-08-08 09:21:10 +02:00
Justin Mayer
63b60da919 Build docs in zipped HTML and PDF formats 2023-08-03 14:44:13 +02:00
Justin Mayer
48a0484d15 Improve ReadTheDocs configuration 2023-08-03 14:37:39 +02:00
Justin Mayer
9384e7cb0b Add ReadTheDocs configuration file 2023-08-03 14:29:18 +02:00
Justin Mayer
639173da6b Generalize analytics support in default theme
As the number of privacy-preserving analytics options proliferates,
it no longer makes sense to support specific solutions provided by
ad-tracking corporations.
2023-08-03 14:10:37 +02:00
Justin Mayer
5435dd0d81 Document _update_context(dict) --> list of tuples
Fix #3024
2023-08-03 11:34:05 +02:00
Justin Mayer
dcd3045f32 Docs: Escape extra setting environment variables. Fix #3016 2023-08-03 10:21:54 +02:00
Justin Mayer
0989ed29be
Merge pull request #2980 from pauloxnet/patch-1 2023-08-03 09:44:48 +02:00
Paolo Melchiorre
5d1dcd8ed3
Remove useless url 2023-08-03 08:49:16 +02:00
Paolo Melchiorre
bf0860ee86
Try to fix documentation build 2023-08-03 08:49:13 +02:00
Paolo Melchiorre
7acc9ac554
Fix documentations errors 2023-08-03 08:48:51 +02:00
Paolo Melchiorre
413c6a1c71
Order codes in themes.rst 2023-08-03 08:48:32 +02:00
Justin Mayer
44d9754466 Add monthly downloads badge to README 2023-08-02 11:01:40 +02:00
Justin Mayer
e8076bfe03
Merge pull request #3164 from marcusdesai/fix/issue-3163 2023-07-27 22:11:28 +02:00
Will Thong
1d2bf8e96e
Replace pytz dependency with zoneinfo. Fix #2958 (#3161) 2023-07-26 17:29:43 +02:00
Justin Mayer
715c056cd4 Update Pygments dev dependency version 2023-07-26 11:24:20 +02:00
Marcus Desai
7f1ecdec8b Fixes #3163; cleanup child processes on kill 2023-07-25 20:27:40 +01:00
(GalaxyMaster)
b8bf5950b6
Adding missing tests for truncate_html_words() (#2918) 2023-07-12 11:28:26 +02:00
Justin Mayer
ef7e26329c Change botpub email address for Git commits 2023-06-29 11:15:41 +02:00
Jorge Maldonado Ventura
0533e2da9f
Small documentation fixes to docs/content.rst (#3156) 2023-06-27 20:35:04 +02:00
Justin Mayer
69d2b5b9af
Merge pull request #3154 from jorgesumle/master 2023-06-24 16:58:54 +02:00
Jorge Maldonado Ventura
b260b3838e Fix grammar errors/typos from docs/faq.rst 2023-06-24 13:29:02 +02:00
Justin Mayer
410f60d6b3 Publish package via PyPI trusted publisher system 2023-06-23 15:54:39 +02:00
Justin Mayer
d3daa4d794 Update Furo theme & pytest-cov dependency versions 2023-06-23 15:53:21 +02:00
Justin Mayer
33220695d1
Merge pull request #3153 from jorgesumle/master 2023-06-23 15:22:19 +02:00
Jorge Maldonado Ventura
7d6accac4d Code should be between backquotes () 2023-06-23 09:27:51 +02:00
Jorge Maldonado Ventura
7877376153 More corrections to pelican-themes.rst 2023-06-23 09:20:32 +02:00
Jorge Maldonado Ventura
168093a750 Fix typo in pelican-themes.rst 2023-06-23 09:05:34 +02:00
DJ Ramones
6ba7a0926d
Clarify docs on ordering in period_archives var 2023-06-19 12:25:32 +08:00
DJ Ramones
5214248344
Implement period_archives common context variable
Also, set default patterns for time-period *_ARCHIVE_URL settings.
2023-06-18 11:07:39 +08:00
Deniz Turgut
1f6b344f7d Add sftp_upload Makefile target to .phony
Signed-off-by: Deniz Turgut <dturgut@gmail.com>
2023-06-04 10:44:00 +02:00
Matthew Pounsett
418a9191b0 Add devserver-global Makefile target to .phony, fixes #3065 2023-06-04 10:44:00 +02:00
Justin Mayer
23c50ea885
Merge pull request #3115 from mart-e/import-config-file 2023-06-04 10:36:55 +02:00
Justin Mayer
1b360acafa
Merge pull request #3114 from mart-e/import-markdown-wp 2023-06-04 10:35:44 +02:00
Matthew Pounsett
bbbc96cf83
Add quoting to devserver-global target in Makefile, fixes #3072 (#3073) 2023-06-04 10:34:09 +02:00
Justin Mayer
043ab617b8
Merge pull request #3124 from FriedrichFroebel/issue3110 2023-06-04 10:32:49 +02:00
Justin Mayer
8b6b7dac2d
Merge pull request #3139 from nikolausschueler/patch-1 2023-05-31 19:58:31 +02:00
Nikolaus Schüler
0a42b5f250
Fix typo in pelican-themes.rst
The least change would be to just say "suffixed", but I don't think that's a correct english word, so I choose "followed by"
2023-05-30 15:58:09 +02:00
Justin Mayer
6f93202e60 Add new Pelican Plugins org link to content docs 2023-05-22 15:12:09 +02:00
Martin (mart-e)
ef844dbe0a Use the default configuration
When importing a blog, a error is logged: 'No timezone information
specified in the settings'.
This is because the code calls read_settings() but no configuration
file is provided.
Instead of providing one (users may not already have one if they are
at the import step), use the default settings.
2023-05-14 08:50:06 +02:00
Martin (mart-e)
bb682973fb Don't specify unlimited feed size by default
Having a feed with hundreds of articles, making a very large file, is
rarely expected.

Set a high fallback value of 100 so it does not change for small sites.

Still allow to have infinite feed by setting FEED_MAX_ITEM = None
2023-05-13 06:53:51 +02:00
FriedrichFroebel
7adcfc7938 Allow resetting memoized cache. Fixes #3110. 2023-04-24 18:44:50 +02:00
Justin Mayer
86f62d0a92
Merge pull request #2963 from geoffff/master 2023-04-20 11:41:00 +02:00
geoffff
8bb9e0da48 Update paginator.py
Use str.startswith('/') to check whether 'ret' starts with a slash. The original code fails when 'ret' is an empty string, such as when INDEX_URL is set to "".
2023-04-20 11:34:38 +02:00
Justin Mayer
208332c0e6
Merge pull request #3112 from getpelican/update-functional-test-output 2023-04-20 08:38:04 +02:00
Justin Mayer
4db5c7ca4b Update to Invoke 2.0 for Python 3.11 compatibility 2023-04-16 09:08:31 +02:00
Justin Mayer
6ac497922f Update pre-commit hooks 2023-04-16 09:07:44 +02:00
Martin (mart-e)
219c01afb0 [IMP] pelican_import with gmf instead of markdown
The markdown import of pandoc is their own flavour of markdown. It for
instance uses fenced divs[1] which are not supported by
python-markdown.  When importing content from Wordpress, there is
several issues as explained in discussion 3113[2]
This change follows a discussion with pandoc developer[3]

[1] https://pandoc.org/MANUAL.html#divs-and-spans
[2] https://github.com/getpelican/pelican/discussions/3113
[3] https://fosstodon.org/@pandoc/110105559949588768

Take the following Wordpress blog post sample:
```html
<p><!-- wp:paragraph --></p>
<p>Paragraph content</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":3747,"sizeSlug":"full"} --></p>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img src="https://test.com/test.jpg" alt="" class="wp-image-3747" title="Some title"/><br />
<figcaption><em>Some caption</em></figcaption>
</figure>
</div>
<p><!-- /wp:image --></p>
```
Before this commit:
was imported as

```md
`<!-- wp:paragraph -->`{=html}

Paragraph content

`<!-- /wp:paragraph -->`{=html}

`<!-- wp:image {"align":"center","id":3747,"sizeSlug":"full"} -->`{=html}

::: wp-block-image
<figure class="aligncenter size-full">
<img src="https://test.com/test.jpg" title="Some title"
class="wp-image-3747" /><br />

<figcaption><em>Some caption</em></figcaption>
</figure>
:::

`<!-- /wp:image -->`{=html}
```

After this change:
```md
<!-- wp:paragraph -->

Paragraph content

<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":3747,"sizeSlug":"full"} -->

<div class="wp-block-image">

<figure class="aligncenter size-full">
<img src="https://test.com/test.jpg" title="Some title"
class="wp-image-3747" /><br />

<figcaption><em>Some caption</em></figcaption>
</figure>

</div>

<!-- /wp:image -->
```

Fixes #3113
2023-03-29 14:07:23 +02:00
Justin Mayer
a2852942ea Update Pygments and Markdown dependency versions 2023-03-27 10:44:01 +02:00
Justin Mayer
06c9e0fb80 Pin Flake8 to 3.9.* in requirements/style.pip 2023-03-27 10:36:00 +02:00
Justin Mayer
385d5bf75e Update functional test output 2023-03-27 10:02:07 +02:00
Boluwatife Victor
b473280eac
Add better description of what Pelican does to README (#3102)
Co-authored-by: Justin Mayer <entroP@gmail.com>
2023-02-23 18:22:56 -08:00
Justin Mayer
95ff3b8e62
Merge pull request #3094 from kurtmckee/fix-readme-link-on-pypi-issue-3093
Fixes https://github.com/getpelican/pelican/issues/3093
2023-01-30 18:00:38 +01:00
Kurt McKee
f50bf26466
Use absolute URL's in the package long_description for PyPI
Fixes #3093
2023-01-30 08:20:12 -06:00
Justin Mayer
7850153c54
Merge pull request #3085 from jorgesumle/deprecate-36 2023-01-30 00:23:56 +01:00
Justin Mayer
504bfcf703
Merge pull request #3091 from EFord36/patch-1 2023-01-20 15:48:15 +01:00
Elliot Ford
b777bedce3
Update Github actions badge
See the linked GitHub issue from the previous version of the badge: badges/shields#8671

In summary, these badges were changed in a breaking fashion such that the badges were just linking to the github issue rather than showing the data. Updating the url resolves this.

Also updated the link added to the badge image, so that it shows exactly the history of actions that the badge shows the most recent one of.
2023-01-20 14:28:44 +00:00
Justin Mayer
4d82a42229 Upgrade Furo theme to 2022.12.07. Refs #3077
Should fix "Previous" and "Next" arrow styling issue.
2023-01-06 10:31:01 +01:00
Justin Mayer
ff665de3ca Tweak README slightly 2023-01-06 10:23:14 +01:00
Jorge Maldonado Ventura
5e986580e8 Change reference to Python version 3.6 from documentation (now 3.7) 2023-01-03 21:29:02 +01:00
Ryan de Kleer
b10c7c699b Fix false-positive in content gen. test failures
Assert equal dirs by return value of diff subprocess, rather than its output.

This prevents tests from failing when file contents are the same but the
file modes are different.

Fix #3042
2022-11-27 22:53:49 -08:00
Justin Mayer
f015ab89d9
Merge pull request #3055 from avaris/python-3.11 2022-10-26 11:12:53 -10:00
Deniz Turgut
3937028c00
update unit test to avoid using deprecated locale.getdefaultlocale() 2022-10-26 23:52:38 +03:00
Deniz Turgut
6ddbc83f43
add python 3.11 to CI and use setup-python pip cache 2022-10-26 23:50:36 +03:00
Justin Mayer
a51d75c8ed
Merge pull request #3043 from copperchin/use-tmp-in-testutils 2022-10-25 14:11:33 -10:00
Justin Mayer
1f6f4a3626
Merge pull request #3054 from renyuneyun/refactor/python-regex 2022-10-24 15:48:40 -10:00
renyuneyun (Rui Zhao)
cbddac44e4 Use (?P=) to replace \2 for intrasite link 2022-10-24 18:05:40 -07:00
Justin Mayer
66408d611f
Merge pull request #3051 from avaris/gh-actions-update 2022-10-24 18:00:17 -07:00
Deniz Turgut
cdc90d5d07
unpin flake8 and do not install pelican while checking
installing pelican brings in markdown. flake8 and markdown have
incompatible requirements for importlib-metadata. installing pelican
is not required to run flake8.
2022-10-23 18:25:25 +03:00
Deniz Turgut
6d11c6f2e5
use python 3.9 for lint, docs and deploy actions
3.7 is old and will soon be EOLed
this also fixes flake8 + importlib-metadata issues
2022-10-20 04:17:11 +03:00
Deniz Turgut
9d509253c3
update github actions
see:
https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-10-20 04:09:48 +03:00
Ryan de Kleer
27f2c678cb Use tmp dir for test output
`shutil.rmtree` would fail in `TestUtils.test_clean_output_dir` on some
filesystems if an application with a filewatcher had the pelican project
open while the test ran.

Using `tempfile.mkdtmp` for test directories circumvents this.
2022-09-16 22:59:54 -07:00
Justin Mayer
2a7e691000 Document switch from IRC to GitHub Discussions 2022-09-15 16:33:19 +02:00
Саша Черных
5d4cb5619b
Docs: Hidden posts also excluded from author index (#3025) 2022-09-13 14:30:43 +02:00
Justin Mayer
6af939e096
Merge pull request #3030 from lioman/master 2022-08-31 23:28:54 +02:00
Lioman
5103aa9a38 Remove python 3.6 from supported language versions 2022-08-23 13:07:19 +02:00
Justin Mayer
09d434d87b Docs: Contact plugin/theme maintainers for those issues 2022-08-21 08:57:07 +02:00
Justin Mayer
062144a875
Merge pull request #3020 from timgates42/bugfix_typos 2022-08-04 15:09:53 +02:00
Justin Mayer
e265deb094
Merge pull request #2976 from pieqq/simple-theme-fixes 2022-08-04 15:08:09 +02:00
Justin Mayer
73c0320f62
Merge pull request #3014 from Lx/static-content-docs 2022-08-04 15:04:35 +02:00
Justin Mayer
083fb357bd
Merge pull request #3013 from Lx/mtime-docs 2022-08-04 15:03:20 +02:00
Anton Mosich
23f3804c96
Fix and update pre-commit hooks (#3011)
Co-authored-by: Justin Mayer <entroP@gmail.com>
2022-08-04 15:01:17 +02:00
Justin Mayer
1bcd6c5f56
Merge pull request #3023 from getpelican/furo-sphinx-theme
Use Furo as Sphinx documentation theme
2022-08-01 15:42:37 +02:00
Justin Mayer
21e855a29f Adjust code style for Flake8 5.0+
We are pinned to Flake8 <4.0, but at least we'll be compliant if we ever
upgrade to Flake8 5.0+.
2022-08-01 13:24:21 +02:00
Justin Mayer
9c0c5b4929 Pin Flake8 due to upper bound on importlib-metadata
See: https://github.com/PyCQA/flake8/pull/1438
2022-08-01 13:23:01 +02:00
Justin Mayer
6487735efb Update Pytest and plugin versions
Also remove pytest-pythonpath as Pytest 7+ includes comparable
functionality. Don't believe we were using it anyway.
2022-08-01 12:56:58 +02:00
Justin Mayer
09c420f40c Update Jinja & Markdown dev dependency versions 2022-08-01 12:55:02 +02:00
Justin Mayer
fcfb39b8f2 Improve copyright year logic in Sphinx configuration 2022-08-01 12:53:09 +02:00
Justin Mayer
81b5fbe174 Add custom Furo page.html template for Sphinx docs 2022-08-01 12:53:09 +02:00
Justin Mayer
33aca76d78 Adjust extlinks configuration for Sphinx 5.0+ 2022-08-01 12:53:09 +02:00
Justin Mayer
961909a149 Update Sphinx and Furo theme dependency versions 2022-08-01 12:53:09 +02:00
Paolo Melchiorre
ac416d7df2 Add Furo as requirement for docs 2022-08-01 10:25:36 +02:00
Paolo Melchiorre
494b418dda Use Furo as Sphinx documentation theme 2022-08-01 10:25:36 +02:00
Tim Gates
6cac8237cc
docs: Fix a few typos
There are small typos in:
- docs/tips.rst
- pelican/tests/__init__.py

Fixes:
- Should read `module` rather than `modulole`.
- Should read `console` rather than `cosole`.

Signed-off-by: Tim Gates <tim.gates@iress.com>
2022-07-24 07:55:18 +10:00
Justin Mayer
84dfbcf3dc
Update PR links in changelog 2022-07-11 19:54:13 +02:00
botpub
9685e4b594 Release Pelican 4.8.0 2022-07-11 17:51:01 +00:00
manhhomienbienthuy
d5d792060c
Fix #2982: Improve _HTMLWordTruncator (#3002) 2022-07-11 19:47:37 +02:00
Justin Mayer
5c222ef41b
Merge pull request #3001 from canyon289/content_expansion 2022-07-11 19:36:54 +02:00
Justin Mayer
c46554ae70
Merge pull request #3000 from canyon289/typo_fix 2022-07-11 19:35:52 +02:00
Alex Peters
7006016121 Add note about unintended static page processing
Fixes #2990.
2022-06-16 14:18:52 +10:00
Alex Peters
39e5edde9c Describe all CHECK_MODIFIED_METHOD options
Fixes #2991.
2022-06-16 13:36:59 +10:00
Ravin Kumar
392bf98118 Add content tag static expansion 2022-04-28 19:53:03 -07:00
Ravin Kumar
595f3be988 Add content expansion 2022-04-28 19:31:21 -07:00
Ravin Kumar
d89c6f6ed2 Fix small typo 2022-04-28 19:28:26 -07:00
Justin Mayer
e8d6318e93
Merge pull request #2989 from chadmando/fix-typo-in-docs
Fix missing word in Automation section
2022-04-03 08:11:00 +02:00
Justin Mayer
f94ba0ef3d
Merge pull request #2994 from avaris/2992
Use JSON values for extra settings in Invoke template
2022-04-03 08:06:26 +02:00
Deniz Turgut
eca0ee04b7
use JSON values for extra settings in invoke template
Signed-off-by: Deniz Turgut <dturgut@gmail.com>
2022-03-23 22:33:57 +03:00
chadmando
433453924b
fix missing word in Automation section 2022-03-11 11:09:59 -06:00
Pierre Equoy
16b8a03ad9 Remove unnecessary ids and classes in simple theme
All of the modified HTML tags can be accessed in CSS without the need
for a dedicated id or an additional class.
2022-02-20 10:29:46 +08:00
Pierre
34ca2e1de2
Merge branch 'getpelican:master' into master 2022-02-20 10:29:06 +08:00
Justin Mayer
77e5381be7
Update CHANGELOG 2022-02-09 09:07:42 -07:00
botpub
5823412085 Release Pelican 4.7.2 2022-02-09 13:25:50 +00:00
Ikko Ashimine
f3613af155
Fix typo in cache.py (#2978)
sublcass -> subclass
2022-02-09 06:15:59 -07:00
Justin Mayer
21c331e789
Merge pull request #2940 from r4victor/fix-issue-2938-attempt-2
Fix parsing of settings passed to `--extra-settings`
2022-02-09 06:12:00 -07:00
Victor Skvortsov
5c178a1ccb Fix #2938
Get rid of the coerce_overrides() function.
Add the ParseOverrides argparse.Action to parse overrides.
Treat all extra settings values strictly as json values.
Test overrides.
Edit docs and cli help.
2022-02-09 06:05:50 -07:00
Victor Skvortsov
ab81f183c6 Add failing tests 2022-02-09 06:05:50 -07:00
Justin Mayer
fe19f1abb6 Pin Sphinx to avoid aggressive extlinks warning
See: https://github.com/sphinx-doc/sphinx/issues/10112
2022-02-01 12:10:20 -07:00
Paolo Melchiorre
2f5fc10614
Add categories.html template to default theme 2022-02-01 11:07:23 -07:00
Pierre Equoy
4794752dd9 Add a viewport meta tag in simple theme for better mobile support
See MDN article about this:

https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag
2022-01-17 16:22:02 +08:00
Pierre Equoy
7b9a859e5e Use <main> and <article> tags in simple theme
Add a <main> tag to surround all the content blocks, so that it's easier
to target the main part of a page (be it an article, the list of posts
or the different categories) using CSS.

Because of this, the <section> part of the article.html template is made
redundant, so it is removed.

Finally, the generic <div> is replaced by an <article> tag to surround
the article's content.
2022-01-17 16:21:59 +08:00
Pierre Equoy
fe4f1ec4ea Uniformize headers in simple theme
In the simple theme, some templates are using `h1`, others are using
`h2` for the main title of the page (other than the one in the header).
This commit changes that so all of the pages are using `h1`.
2022-01-17 16:21:44 +08:00
Gunung P. Wibisono
0384c9bc07
Update Poetry install script to install-poetry.py (#2965) 2022-01-06 16:26:41 -08:00
Justin Mayer
11633992a0
Merge pull request #2952 from ingwinlu/bugfix/2951
Clean up quickstart script
2021-11-27 08:00:39 -07:00
Justin Mayer
4c8572e85d
Merge pull request #2950 from ingwinlu/bugfix/2941
Change spaces to tab as required by Makefile
2021-11-27 07:19:31 -07:00
Justin Mayer
1a321102a1
Merge pull request #2948 from ingwinlu/bugfix/#2845
Extend docstring of slugify util
2021-11-27 07:18:54 -07:00
Lukas Winkler
8f6a61439d Add helper method for rendering jinja templates 2021-11-27 14:04:36 +01:00
Lukas Winkler
59f7f4beb8 Remove unneeded explicit close stmts
Closes #2951
2021-11-27 13:56:33 +01:00
Lukas Winkler
2e35bc90a6 Change spaces to tab as required by Makefile
Closes #2941
2021-11-27 10:31:14 +01:00
Lukas Winkler
fa31a7e279 Extend docstring
We want to hint at the location of our default set of substitutions.
This should allow easier reuse for plugin authors who need to access
this utility as well.

Closes #2845
2021-11-27 09:33:42 +01:00
Justin Mayer
57c5296a44
Merge pull request #2949 from avaris/docutils-update
Use docutils.Node.findall instead of traverse
2021-11-26 18:33:20 -07:00
Deniz Turgut
8eb4be521f
use docutils.Node.findall instead of traverse
docutils.Node.traverse is being deprecated as of docutils==0.18.1
2021-11-25 23:57:09 +03:00
Justin Mayer
1b87ef6a7b Add funding link 2021-11-15 15:39:10 -06:00
iUnknwn
9ec1750709 Document how to inject articles with a plugin
Add to the plugin documentation a recipe for injecting articles
programmatically when Pelican is running.
2021-11-12 15:33:45 -06:00
botpub
bb10d286a6 Release Pelican 4.7.1 2021-10-12 14:45:30 +00:00
Justin Mayer
de2e9b7e41 Prepare release 2021-10-12 15:59:59 +02:00
Justin Mayer
17089aefc9 Add more contributors to THANKS 2021-10-12 15:58:53 +02:00
Ben Sturmfels
99c935df8f Omit __pycache__ and *.pyc/pyo files in packages 2021-10-12 14:50:58 +02:00
Ben Sturmfels
aeec09b397 Distribute sample data used to run tests 2021-10-12 14:49:05 +02:00
Justin Mayer
9bd54b7b60 All roads lead to Rome 2021-10-08 14:52:55 +02:00
Justin Mayer
eab67f7634 PTY all the tasks 2021-10-08 14:52:55 +02:00
Justin Mayer
d1a874e580
Merge pull request #2936 from BenSturmfels/no-pager
Use `git --no-pager` rather than override all environment variables
2021-10-08 14:52:38 +02:00
Ben Sturmfels
793b93bd34
Use --no-pager option rather than override all environment variables
Currently the `assertDirsEqual` test utility uses the `env` argument to `subprocess.Popen` to make git run non-interactively, but this overwrites all environment variables causing test failures on Guix. The `--no-pager` option is a more targeted way to achieve the same thing.
2021-10-08 18:47:40 +11:00
Justin Mayer
33ef2c5356
Merge pull request #2929 from MinchinWeb/mimetypes-webfonts
Add MIME types for web fonts
2021-10-08 08:45:09 +02:00
MinchinWeb
98372c9869 server: for extension_map, refer to upstream version rather than only overwriting it 2021-10-07 14:44:36 -06:00
Jonas Borges
8849721913
Ensure _DISCARDED is not being cached. Fix #2825 (#2926)
Filtration is now being applied before caching the metadata, solving the issue where _DISCARD objects from previous runs were being retrieved from cache.
2021-10-06 10:19:17 +02:00
Justin Mayer
0da8659d0e Add Python 3.10 to test matrix & classifier list 2021-10-06 10:12:34 +02:00
Justin Mayer
30597b70f0 Quote version numbers in GitHub Actions workflow
Otherwise, YAML treats `python: 3.10` as a float, yielding Python 3.1.
2021-10-06 10:12:34 +02:00
Justin Mayer
735d93c7b6
Merge pull request #2933 from getpelican/theme-docs
Add Pelican Themes repo link to docs
2021-10-06 09:53:12 +02:00
MinchinWeb
5803052bb7 server: return proper MIME-types for webfonts 2021-10-05 19:23:52 -06:00
disk0x
31b282f3e2 Add SFTP upload to Makefile
Some managed web hosts do not allow uploads via scp or rsync, so the
sftp command is a necessary alternative.
2021-10-05 07:51:34 +02:00
Justin Mayer
76cf879414 Add Pelican theme repo link to docs 2021-10-05 07:38:24 +02:00
Justin Mayer
b5426fb0bb
Merge pull request #2927 from MinchinWeb/rich-server
Use rich logging for Pelican server
2021-10-05 06:45:03 +02:00
MinchinWeb
2b631ab4d3 Listen: set minimum logging level to INFO
This way we can see the server requests.
2021-10-04 22:40:31 -06:00
MinchinWeb
0b9a488c26 Use rich logging for Pelican server 2021-10-04 22:40:31 -06:00
Justin Mayer
e2c73a0a16
Merge pull request #2932 from BenSturmfels/master
Remove shebang lines from generated pelicanconf.py and publishconf.py
2021-10-05 06:17:48 +02:00
Justin Mayer
324fcefae7
Merge pull request #2931 from avaris/server-list-files
Adjust suffix in server to allow redirection when needed
2021-10-05 06:12:04 +02:00
Ben Sturmfels
c5c7483268
Remove shebang lines from generated pelicanconf.py and publishconf.py.
These configuration files do not need a #! line as they are not intended to be
executed directly and are not marked as executable. (In practise this doesn't
cause any problems - it just came up in a Guix bug report because Guix
transforms the #! lines.)

The "coding: utf-8" lines are also no longer required now that Pelican is Python
3 only.
2021-10-05 10:00:48 +11:00
Deniz Turgut
2d97a45902
Adjust suffix in server to allow redirection when needed
Folders without index.html has to be redirected (/foo -> /foo/) for
directory listing to work properly. Skip '/' suffix if original path
does not have it so that base class can return a redirect.
2021-10-05 01:44:12 +03:00
botpub
f862d64b7a Release Pelican 4.7.0 2021-10-01 14:10:26 +00:00
Justin Mayer
7dec2660fb Prepare release 2021-10-01 16:04:47 +02:00
Justin Mayer
f9238269d7 Tweak changelog 2021-10-01 15:35:41 +02:00
Justin Mayer
492ed61c9f Update changelog 2021-10-01 15:30:03 +02:00
Justin Mayer
eacd6435ef Minor README tweaks 2021-10-01 15:04:58 +02:00
Justin Mayer
24aefd3b1b
Merge pull request #2904 from GiovanH/pickle-typeerror
Pickle.dump can raise TypeError (e.g. generators)
2021-09-29 12:58:46 +02:00
Justin Mayer
7ccaa9a6b6
Merge pull request #2897 from MinchinWeb/rich-logging
Rich logging
2021-09-29 12:56:48 +02:00
ImBearChild
22192c148a Improve word count behavior when generating summary
Improve _HTMLWordTruncator by using more than one unicode block in
_word_regex, making word count function behave properly with CJK,
Cyrillic, and more Latin characters when generating summary.
2021-09-29 12:41:00 +02:00
Ben Sturmfels
a088f8bb9e Update tests for other locales 2021-09-28 14:05:32 +02:00
Ben Sturmfels
62a878ded3 Update tests to match theme changes 2021-09-28 14:05:08 +02:00
Ben Sturmfels
991cebf95d Update notmyidea theme to scale down to smaller screens
The aim here is to make the theme work respectably on mobile devices
with only modest changes. Providing different layouts at multiple
breakpoints is beyond the scope of this change.

The changes here are:

1. `base.html`: Add a `<meta name="viewport"` element

2. `main.css`:
  * Use "max-width" instead of "width"
  * Set "line-height" on the banner and adjust vertical spacing to match
  * Remove fixed height on the nav bar and force it to contain its
    child elements
2021-09-28 14:03:05 +02:00
Gio
438938819e Pickle.dump can raise TypeError (e.g. generators) 2021-08-01 17:06:34 -05:00
MinchinWeb
332be6e5c8
Support date format codes G, V, and u (used by ISO dates) (#2902) 2021-07-13 09:35:22 +02:00
Justin Mayer
0919507ae7
Merge pull request #2901 from MinchinWeb/writer-docs
Document how to add a new writer
2021-07-13 09:33:34 +02:00
MinchinWeb
a168470f29 Use rich.console with printing settings 2021-07-09 09:56:11 -06:00
MinchinWeb
1cd7dd6a28 Print to the (rich) console, rather than directly 2021-07-09 09:55:48 -06:00
MinchinWeb
bc21922cf2 Don't preformat log messages
as per review notes
2021-07-09 09:51:06 -06:00
MinchinWeb
58e3770b80 Document how to add a new writer
c.f. #2899
2021-07-09 08:28:15 -06:00
MinchinWeb
7eb730af78 Nicer logging of found writer
matches generator format
2021-07-08 23:26:33 -06:00
MinchinWeb
a52922bfb5 Move rich's console to log.py 2021-07-08 21:33:22 -06:00
Tristan Miller
82098a634f
Fix formatting of Jinja example code. Fixes #2884 (#2886) 2021-07-07 08:48:10 +02:00
MinchinWeb
7d492bad67 Remove log format test
as *rich* is now doing this
2021-06-30 23:29:20 -06:00
MinchinWeb
4bfcedb8a5 Share rich handler between spinner and logging 2021-06-30 23:03:22 -06:00
MinchinWeb
80f44c494a Switch to rich logging 2021-06-30 22:47:32 -06:00
Justin Mayer
ee8fb6998c
Merge pull request #2892 from MinchinWeb/typo-fix
Fix typo in docstring
2021-06-30 08:56:28 +02:00
Justin Mayer
7dfac1c0c0
Merge pull request #2882 from MinchinWeb/patch-1
Allow easy subclassing of Writer
2021-06-30 08:54:04 +02:00
MinchinWeb
2cafe926fa typo fix
"current" only has two "r"s
2021-06-15 22:41:38 -06:00
Tristan Miller
e800b23b4d
Update links to Jinja docs. Fixes #2883 (#2885) 2021-06-12 08:48:32 -05:00
Justin Mayer
c10792c679
Merge pull request #2878 from jzc/filename-metadata-typo
Fix FILENAME_METADATA doc to render correctly
2021-06-12 08:45:58 -05:00
MinchinWeb
845acfe1ac Allow easy subclassing of Writer
When you write a custom Writer, it gets called with `settings=None`. If you writer is simply a subclass of the built-in Writer, Pelican will through the error `CRITICAL: 'RELATIVE_URLS'`.

The source of the error is from `Pelican._get_writer()` in `__init__.py`.
2021-06-08 14:01:32 -06:00
Justin Mayer
c041bf2192 Fix failing tests on Jinja 3+ 2021-06-08 11:40:27 -05:00
jzc
c41b8abb13 Fix FILENAME_METADATA doc to render correctly 2021-05-20 00:11:58 -06:00
Gio
add3628a64 Add support for hidden articles 2021-05-04 13:54:32 -05:00
Petr Viktorin
487da3550b Add period_num var for period_archives template
This makes it easier to create templates that are language-agnostic
or need extra processing for the date period.
2021-05-04 12:41:17 -05:00
Justin Mayer
7893455b43
Merge pull request #2838 from namn/patch-2
Use a top (instead of bottom) border in hentry
2021-04-27 20:14:10 +02:00
Justin Mayer
fb9df68477
Merge pull request #2869 from getpelican/rich
Add progress spinner animation during generation
2021-04-27 14:42:22 +02:00
Justin Mayer
40f3d2df91 Add progress spinner animation during generation
This is a first step at enriching console output via the `rich` project.
2021-04-21 10:16:59 +02:00
Justin Mayer
14afc6c54a Update Pelican feature documentation 2021-04-21 10:16:28 +02:00
Justin Mayer
fd3ad0c16e Update contributing docs and Poetry repository URL 2021-04-21 10:05:28 +02:00
Justin Mayer
c461def10a Update to v2 of cache GitHub Action 2021-04-21 09:57:08 +02:00
Justin Mayer
dac01831f2
Merge pull request #2868 from MinchinWeb/patch-1
Fix `invoke tests` task problem on Windows
2021-04-19 16:44:29 +02:00
Romain Porte
a00284f744
Automatically open browser when Invoke task starts web server (#2764)
When the `serve` and `livereload` targets are invoked, a web browser will be
automatically opened, pointing to the locally-served website.

If no web browser can be found by the module, the `open()` call returns
`False`, but no exception is raised. This means that it is still possible
to call livereload on a remote machine and access it without any error
being triggered.

Signed-off-by: Romain Porte <microjoe@microjoe.org>
2021-04-19 15:59:41 +02:00
Justin Mayer
88953d45d5 Strip HTML tags from notmyidea page template's title
Fixes #2843
2021-04-19 10:25:59 +02:00
MinchinWeb
cf4e8d527d
Update tasks.py
PTY is not supported on Windows.
2021-04-18 22:20:54 -06:00
Nam Nguyen
507d68e5c6 Update functional tests. 2021-01-07 14:10:50 -08:00
Nam Nguyen
b12443f48a
Use a top (instead of bottom) border in hentry.
`hentry` uses `clear: both` with the intention of placing a separator line (1px border) between each entry. However, it is wrongly using `border-bottom` instead of `border-top` to make that separator. CSS `clear` makes space to clear the **preceding** floats. Hence a `border-bottom` won't enjoy that `clear` effect.
2021-01-05 10:40:31 -08:00
MinchinWeb
a133716709 flake8 fixes 2020-05-21 21:43:06 -06:00
MinchinWeb
cfba3d72be fix testing failures
when settings could be pathlib.Path
2020-05-21 21:13:02 -06:00
MinchinWeb
d817231836 Allow generators to deal with settings that are pathlib.Paths 2020-05-21 21:10:37 -06:00
414 changed files with 35069 additions and 19283 deletions

View file

@ -1,3 +1,4 @@
[report]
omit = pelican/tests/*
omit =
pelican/tests/*
pelican/signals.py

View file

@ -9,7 +9,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
[*.py]
max_line_length = 79
max_line_length = 88
[*.{yml,yaml}]
indent_size = 2

21
.git-blame-ignore-revs Normal file
View file

@ -0,0 +1,21 @@
# .git-blame-ignore-revs
# Apply code style to project via: ruff format .
cabdb26cee66e1173cf16cb31d3fe5f9fa4392e7
# Upgrade code base for Python 3.8 and above
ecd598f293161a52564aa6e8dfdcc8284dc93970
# Apply Ruff and pyupgrade to Jinja templates
db241feaa445375dc05e189e69287000ffe5fa8e
# Change pre-commit to run ruff and ruff-format with fixes
6d8597addb17d5fa3027ead91427939e8e4e89ec
# Upgrade Ruff from 0.1.x to 0.4.x
0bd02c00c078fe041b65fbf4eab13601bb42676d
# Apply more Ruff checks to code
9d30c5608a58d202b1c02d55651e6ac746bfb173
# Apply yet more Ruff checks to code
7577dd7603f7cb3a09922d1edb65b6eafb6e2ac7
# Indent Jinja templates, HTML, CSS, and JS via DjHTML
4af40e80772a58eac8969360e5caeb99e3e26e78
# Ruff UP031: Use F-string format specifiers instead of percent format
30bde3823f50b9ba8ac5996c1c46bb72031aa6b8
# Upgrade Ruff to 0.12.x & comply with new rules
4dedf1795831db99d18941c707923ba48cc28ce7

4
.gitattributes vendored
View file

@ -4,4 +4,8 @@
# Improve accuracy of GitHub's Linguist-powered language statistics
pelican/tests/content/* linguist-vendored
pelican/tests/output/* linguist-vendored
pelican/tests/theme_overrides/* linguist-vendored
pelican/themes/notmyidea/templates/*.html linguist-language=Jinja
pelican/themes/simple/templates/*.html linguist-language=Jinja
samples/* linguist-vendored
*.html linguist-vendored

1
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1 @@
.github/workflows/github_pages.yml @seanh

3
.github/FUNDING.yml vendored
View file

@ -1,2 +1,5 @@
---
github: justinmayer
custom: https://donate.getpelican.com
liberapay: pelican

View file

@ -17,11 +17,15 @@ assignees: ''
<!-- Checked checkbox should look like this: [x] -->
- [ ] I have read the [Filing Issues](https://docs.getpelican.com/en/latest/contribute.html#filing-issues) and subsequent “How to Get Help” sections of the documentation.
- [ ] I can reproduce this problem with stock/default settings file, theme, and sample content (as described in above “How to Get Help” sections of the documentation).
- [ ] I have searched the [issues](https://github.com/getpelican/pelican/issues?q=is%3Aissue) (including closed ones) and believe that this is not a duplicate.
<!--
Once the above boxes are checked, if you are able to fill in the following list
with your information, it would be very helpful for maintainers.
If you cannot reproduce the problem with stock/default settings file, theme, and sample content,
please close this tab and ask your question in the Discussions area instead:
<https://github.com/getpelican/pelican/discussions>
Otherwise, once the above boxes are checked, please fill out the following list
of information, which would be very helpful for maintainers.
-->
- **OS version and name**: <!-- Replace with version + name -->

View file

@ -8,7 +8,11 @@ assignees: ''
---
<!--
Describe your question/issue here. This space is meant to be used for general questions
Instead of a new issue, please consider submitting your question to:
<https://github.com/getpelican/pelican/discussions>
If for some reason you believe that your question warrants a new issue
instead of a discussion thread, describe your question/issue here.
This space is meant to be used for general questions
that are not bugs, feature requests, or documentation issues.
Before you submit this, lets make sure of a few things.
Please make sure the following boxes are ticked if they are correct.
@ -18,6 +22,7 @@ assignees: ''
<!-- Checked checkbox should look like this: [x] -->
- [ ] I have searched the [issues](https://github.com/getpelican/pelican/issues?q=is%3Aissue) (including closed ones) and believe that this is not a duplicate.
- [ ] I have searched the [documentation](https://docs.getpelican.com/) and believe that my question is not covered.
- [ ] I have carefully read the [How to Get Help](https://docs.getpelican.com/en/latest/contribute.html#how-to-get-help) section of the documentation.
## Issue
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->

View file

@ -1,7 +1,8 @@
---
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: '💬 Pelican IRC Channel on Freenode'
url: https://kiwiirc.com/client/irc.freenode.net/?#pelican
- name: '💬 Pelican IRC Channel'
url: https://web.libera.chat/?#pelican
about: |
Chat with the community, ask questions, and learn about best practices.

9
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,9 @@
# See https://docs.github.com/en/free-pro-team@latest/
# github/administering-a-repository/enabling-and-disabling-version-updates
---
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

105
.github/workflows/github_pages.yml vendored Normal file
View file

@ -0,0 +1,105 @@
# Workflow for building the site and (optionally) publishing it to GitHub Pages.
name: Deploy to GitHub Pages
on:
workflow_call:
inputs:
settings:
required: true
description: "The path to your Pelican settings file (`pelican`'s `--settings` option), for example: 'publishconf.py'"
type: string
requirements:
required: false
default: "pelican"
description: "The Python requirements to install, for example to enable markdown and typogrify use: 'pelican[markdown] typogrify' or if you have a requirements file use: '-r requirements.txt'"
type: string
output-path:
required: false
default: "output/"
description: "Where to output the generated files (`pelican`'s `--output` option)"
type: string
theme:
required: false
default: ""
description: "The GitHub repo URL of a custom theme to use, for example: 'https://github.com/seanh/sidecar.git'"
type: string
python:
required: false
default: "3.12"
description: "The version of Python to use, for example: '3.12' (to use the most recent version of Python 3.12, this is faster) or '3.12.1' (to use an exact version, slower)"
type: string
siteurl:
required: false
default: ""
description: "The base URL of your web site (Pelican's SITEURL setting). If not passed this will default to the URL of your GitHub Pages site, which is correct in most cases."
type: string
feed_domain:
required: false
default: ""
description: "The domain to be prepended to feed URLs (Pelican's FEED_DOMAIN setting). If not passed this will default to the URL of your GitHub Pages site, which is correct in most cases."
type: string
deploy:
required: false
default: true
description: "Whether to deploy the site. If true then build the site and deploy it. If false then just test that the site builds successfully but don't deploy anything."
type: boolean
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python }}
- name: Checkout theme
if: ${{ inputs.theme }}
run: git clone '${{ inputs.theme }}' .theme
- name: Configure GitHub Pages
id: pages
uses: actions/configure-pages@v5
- name: Install requirements
run: pip install ${{ inputs.requirements }}
- name: Build Pelican site
shell: python
run: |
import subprocess
cmd = "pelican"
cmd += " --settings ${{ inputs.settings }}"
cmd += " --extra-settings"
cmd += """ SITEURL='"${{ inputs.siteurl || steps.pages.outputs.base_url }}"'"""
cmd += """ FEED_DOMAIN='"${{ inputs.feed_domain || steps.pages.outputs.base_url }}"'"""
cmd += " --output ${{ inputs.output-path }}"
if "${{ inputs.theme }}":
cmd += " --theme-path .theme"
subprocess.run(cmd, shell=True, check=True)
- name: Fix permissions
run: |
chmod -c -R +rX "${{ inputs.output-path }}" | while read line; do
echo "::warning title=Invalid file permissions automatically fixed::$line"
done
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ${{ inputs.output-path }}
deploy:
concurrency:
group: "pages"
cancel-in-progress: false
if: ${{ inputs.deploy }}
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View file

@ -9,60 +9,30 @@ env:
jobs:
test:
name: Test - ${{ matrix.config.python }} - ${{ matrix.config.os }}
runs-on: ${{ matrix.config.os }}-latest
name: Test - ${{ matrix.python }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
config:
os: [ubuntu, macos, windows]
python: ["3.10", "3.11", "3.12", "3.13"]
include:
- os: ubuntu
python: 3.6
- os: ubuntu
python: 3.7
- os: ubuntu
python: 3.8
- os: ubuntu
python: 3.9
- os: macos
python: 3.7
- os: windows
python: 3.7
python: "3.9"
steps:
- uses: actions/checkout@v2
- name: Setup Python ${{ matrix.config.python }}
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.config.python }}
- name: Set pip cache (Linux)
uses: actions/cache@v1
if: startsWith(runner.os, 'Linux')
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements/*') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Setup pip cache (macOS)
uses: actions/cache@v1
if: startsWith(runner.os, 'macOS')
with:
path: ~/Library/Caches/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements/*') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Setup pip cache (Windows)
uses: actions/cache@v1
if: startsWith(runner.os, 'Windows')
with:
path: ~\AppData\Local\pip\Cache
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements/*') }}
restore-keys: |
${{ runner.os }}-pip-
python-version: ${{ matrix.python }}
cache: "pip"
cache-dependency-path: "**/requirements/*"
- name: Install locale (Linux)
if: startsWith(runner.os, 'Linux')
run: sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8
- name: Install pandoc
uses: r-lib/actions/setup-pandoc@v1
uses: r-lib/actions/setup-pandoc@v2
with:
pandoc-version: "2.9.2"
- name: Install tox
@ -74,86 +44,103 @@ jobs:
echo "===== PANDOC ====="
pandoc --version | head -2
- name: Run tests
run: tox -e py${{ matrix.config.python }}
run: tox -e py${{ matrix.python }}
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- uses: pdm-project/setup-pdm@v4
with:
python-version: 3.7
- name: Set pip cache (Linux)
uses: actions/cache@v1
if: startsWith(runner.os, 'Linux')
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install tox
run: python -m pip install -U pip tox
- name: Check
run: tox -e flake8
python-version: "3.11"
cache: true
cache-dependency-path: ./pyproject.toml
- name: Install dependencies
run: |
pdm install --no-default --dev
- name: Run linters
run: pdm lint --diff
- name: Run pre-commit checks on all files
uses: pre-commit/action@v3.0.1
build:
name: Test build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pdm-project/setup-pdm@v4
with:
python-version: "3.11"
cache: true
cache-dependency-path: ./pyproject.toml
- name: Install dependencies
run: pdm install --dev
- name: Build package
run: pdm build
- name: Test build
run: pdm run pytest --check-build=dist pelican/tests/build_test
docs:
name: Build docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.7
- name: Set pip cache (Linux)
uses: actions/cache@v1
if: startsWith(runner.os, 'Linux')
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*') }}
restore-keys: |
${{ runner.os }}-pip-
python-version: "3.11"
cache: "pip"
cache-dependency-path: "**/requirements/*"
- name: Install tox
run: python -m pip install -U pip tox
- name: Check
run: tox -e docs
- name: cache the docs for inspection
uses: actions/upload-artifact@v4
with:
name: docs
path: docs/_build/html/
deploy:
name: Deploy
needs: [test, lint, docs]
environment: Deployment
needs: [test, lint, docs, build]
runs-on: ubuntu-latest
if: ${{ github.ref=='refs/heads/master' && github.event_name!='pull_request' }}
if: github.ref=='refs/heads/main' && github.event_name!='pull_request' && github.repository == 'getpelican/pelican'
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
with:
python-version: 3.7
token: ${{ secrets.GH_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Check release
id: check_release
run: |
python -m pip install pip --upgrade
pip install poetry
pip install githubrelease
pip install --pre autopub
echo "##[set-output name=release;]$(autopub check)"
python -m pip install --upgrade pip
python -m pip install autopub[github]
autopub check
- name: Publish
if: ${{ steps.check_release.outputs.release=='' }}
if: ${{ steps.check_release.outputs.autopub_release=='true' }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
git remote set-url origin https://$GITHUB_TOKEN@github.com/${{ github.repository }}
autopub prepare
poetry build
autopub commit
autopub build
autopub githubrelease
poetry publish -u __token__ -p $PYPI_PASSWORD
- name: Upload package to PyPI
if: ${{ steps.check_release.outputs.autopub_release=='true' }}
uses: pypa/gh-action-pypi-publish@release/v1

15
.gitignore vendored
View file

@ -4,7 +4,7 @@
*.pyc
.DS_Store
docs/_build
docs/fr/_build
docs/*/_build
build
dist
tags
@ -15,4 +15,15 @@ htmlcov
venv
samples/output
*.pem
poetry.lock
*.lock
.pdm-python
.vale
.venv
**/LC_MESSAGES/*.mo
# direnv
.envrc
# IDE cruft
.idea
.vscode

View file

@ -1,7 +1,8 @@
---
# See https://pre-commit.com/hooks.html for info on hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.5.0
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-ast
@ -10,11 +11,20 @@ repos:
- id: debug-statements
- id: detect-private-key
- id: end-of-file-fixer
- id: forbid-new-submodules
- id: trailing-whitespace
- id: flake8
name: Flake8 on commit diff
description: This hook limits Flake8 checks to changed lines of code.
entry: bash
args: [-c, 'git diff HEAD | flake8 --diff --max-line-length=88']
exclude: ^pelican/tests/output/
- repo: https://github.com/astral-sh/ruff-pre-commit
# ruff version should match the one in pyproject.toml
rev: v0.12.2
hooks:
- id: ruff-check
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/rtts/djhtml
rev: '3.0.8'
hooks:
- id: djhtml
- id: djcss
- id: djjs

28
.readthedocs.yaml Normal file
View file

@ -0,0 +1,28 @@
---
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version, and any other needed tools
build:
os: ubuntu-22.04
tools:
python: "3.10"
# Build HTML & PDF formats
formats:
- htmlzip
- pdf
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Version of Python and requirements required to build the docs
python:
install:
- requirements: requirements/developer.pip
- method: pip
path: .

10
.vale.ini Normal file
View file

@ -0,0 +1,10 @@
StylesPath = .vale/styles
Vocab = Pelican
MinAlertLevel = suggestion
Packages = proselint, alex
[*]
BasedOnStyles = Vale, proselint, alex

View file

@ -1,11 +1,13 @@
Filing issues
=============
* Before you file an issue, try `asking for help`_ first.
* If determined to file an issue, first check for `existing issues`_, including
closed issues.
* Before you submit a new issue, try `asking for help`_ first.
* If determined to create a new issue, first search `Pelican Discussions`_
and `existing issues`_ (open and closed) to see if your question has already
been answered previously.
.. _`asking for help`: `How to get help`_
.. _`Pelican Discussions`: https://github.com/getpelican/pelican/discussions
.. _`existing issues`: https://github.com/getpelican/pelican/issues
How to get help
@ -18,24 +20,29 @@ Before you ask for help, please make sure you do the following:
you read the docs for the Pelican version you are using.
2. Use a search engine (e.g., DuckDuckGo, Google) to search for a solution to
your problem. Someone may have already found a solution, perhaps in the
form of a plugin_ or a specific combination of settings.
form of a ':pelican-doc:`plugins` or a specific combination of settings.
3. Try reproducing the issue in a clean environment, ensuring you are using:
* latest Pelican release (or an up-to-date Git clone of Pelican master)
* latest Pelican release (or an up-to-date Git clone of Pelican ``main`` branch)
* latest releases of libraries used by Pelican
* no plugins or only those related to the issue
**NOTE:** The most common sources of problems are anomalies in (1) themes,
(2) settings files, and (3) ``make``/``invoke`` automation wrappers. If you can't
reproduce your problem when using the following steps to generate your site,
then the problem is almost certainly with your chosen theme and/or settings
file (and not Pelican itself)::
**NOTE:** The most common sources of problems are anomalies in (1) themes, (2)
plugins, (3) settings files, and (4) ``make``/``invoke`` automation wrappers.
If you can't reproduce your problem when using the following steps to generate
your site, then the problem is almost certainly with one of the above-listed
elements (and not Pelican itself)::
cd ~/projects/your-site
git clone https://github.com/getpelican/pelican ~/projects/pelican
pelican content -s ~/projects/pelican/samples/pelican.conf.py -t ~/projects/pelican/pelican/themes/notmyidea
If you can generate your site without problems using the steps above, then your
problem is unlikely to be caused by Pelican itself, and therefore please
consider reaching out to the maintainers of the plugins/theme you are using
instead of raising the topic with the Pelican core community.
If despite the above efforts you still cannot resolve your problem, be sure to
include in your inquiry the following information, preferably in the form of
links to content uploaded to a `paste service`_, GitHub repository, or other
@ -59,26 +66,10 @@ publicly-accessible location:
the ``--debug`` flag: ``pelican --debug content [...]``)
.. _documentation: https://docs.getpelican.com/
.. _`paste service`: https://dpaste.de/
Once the above preparation is ready, you can contact people willing to help via
(preferably) the ``#pelican`` IRC channel or send a message to ``authors at getpelican dot com``.
Remember to include all the information you prepared.
The #pelican IRC channel
------------------------
* Because of differing time zones, you may not get an immediate response to your
question, but please be patient and stay logged into IRC — someone will almost
always respond if you wait long enough (it may take a few hours).
* If you don't have an IRC client handy, use the webchat_.
* You can direct your IRC client to the channel using this `IRC link`_ or you
can manually join the ``#pelican`` IRC channel on the `freenode IRC network`_.
.. _webchat: https://kiwiirc.com/client/irc.freenode.net/?#pelican
.. _`IRC link`: irc://irc.freenode.net/pelican
.. _`freenode IRC network`: https://freenode.net/
.. _`paste service`: https://dpaste.com
Once the above preparation is ready, you can post your query as a new thread in
`Pelican Discussions`_. Remember to include all the information you prepared.
Contributing code
=================
@ -86,17 +77,22 @@ Contributing code
Before you submit a contribution, please ask whether it is desired so that you
don't spend a lot of time working on something that would be rejected for a
known reason. Consider also whether your new feature might be better suited as
a plugin_ — you can `ask for help`_ to make that determination.
a ':pelican-doc:`plugins` — you can `ask for help`_ to make that determination.
Also, if you intend to submit a pull request to address something for which there
is no existing issue, there is no need to create a new issue and then immediately
submit a pull request that closes it. You can submit the pull request by itself.
Using Git and GitHub
--------------------
* `Create a new git branch`_ specific to your change (as opposed to making
your commits in the master branch).
* `Create a new branch`_ specific to your change (as opposed to making
your commits in the ``main`` branch).
* **Don't put multiple unrelated fixes/features in the same branch / pull request.**
For example, if you're working on a new feature and find a bugfix that
doesn't *require* your new feature, **make a new distinct branch and pull
request** for the bugfix.
request** for the bugfix. Similarly, any proposed changes to code style
formatting should be in a completely separate pull request.
* Add a ``RELEASE.md`` file in the root of the project that contains the
release type (major, minor, patch) and a summary of the changes that will be
used as the release changelog entry. For example::
@ -115,15 +111,8 @@ Using Git and GitHub
detailed explanation (when relevant).
* `Squash your commits`_ to eliminate merge commits and ensure a clean and
readable commit history.
* If you have previously filed a GitHub issue and want to contribute code that
addresses that issue, **please use** ``hub pull-request`` instead of using
GitHub's web UI to submit the pull request. This isn't an absolute
requirement, but makes the maintainers' lives much easier! Specifically:
`install hub <https://github.com/github/hub/#installation>`_ and then run
`hub pull-request -i [ISSUE] <https://hub.github.com/hub-pull-request.1.html>`_
to turn your GitHub issue into a pull request containing your code.
* After you have issued a pull request, the continuous integration (CI) system
will run the test suite for all supported Python versions and check for PEP8
will run the test suite on all supported Python versions and check for code style
compliance. If any of these checks fail, you should fix them. (If tests fail
on the CI system but seem to pass locally, ensure that local test runs aren't
skipping any tests.)
@ -131,28 +120,20 @@ Using Git and GitHub
Contribution quality standards
------------------------------
* Adhere to `PEP8 coding standards`_. This can be eased via the `pycodestyle
<https://pypi.org/project/pycodestyle>`_ or `flake8
<https://pypi.org/project/flake8/>`_ tools, the latter of which in
particular will give you some useful hints about ways in which the
code/formatting can be improved. We try to keep line length within the
79-character maximum specified by PEP8. Because that can sometimes compromise
readability, the hard/enforced maximum is 88 characters.
* Adhere to the project's code style standards. See: `Development Environment`_
* Ensure your code is compatible with the `officially-supported Python releases`_.
* Add docs and tests for your changes. Undocumented and untested features will
not be accepted.
* `Run all the tests`_ **on all versions of Python supported by Pelican** to
ensure nothing was accidentally broken.
* :pelican-doc:`Run all the tests <contribute>` **on all versions of Python
supported by Pelican** to ensure nothing was accidentally broken.
Check out our `Git Tips`_ page or `ask for help`_ if you
need assistance or have any questions about these guidelines.
.. _`plugin`: https://docs.getpelican.com/en/latest/plugins.html
.. _`#pelican IRC channel`: https://webchat.freenode.net/?channels=pelican&uio=d4
.. _`Create a new git branch`: https://github.com/getpelican/pelican/wiki/Git-Tips#making-your-changes
.. _`Create a new branch`: https://github.com/getpelican/pelican/wiki/Git-Tips#making-your-changes
.. _`Squash your commits`: https://github.com/getpelican/pelican/wiki/Git-Tips#squashing-commits
.. _`Run all the tests`: https://docs.getpelican.com/en/latest/contribute.html#running-the-test-suite
.. _`Git Tips`: https://github.com/getpelican/pelican/wiki/Git-Tips
.. _`PEP8 coding standards`: https://www.python.org/dev/peps/pep-0008/
.. _`ask for help`: `How to get help`_
.. _`officially-supported Python releases`: https://devguide.python.org/#status-of-python-branches
.. _`Development Environment`: https://docs.getpelican.com/en/latest/contribute.html#setting-up-the-development-environment
.. _`officially-supported Python releases`: https://devguide.python.org/versions/#versions

View file

@ -1,3 +0,0 @@
include *.rst
recursive-include pelican *.html *.css *png *.rst *.markdown *.md *.mkd *.xml *.py *.jinja2
include LICENSE THANKS docs/changelog.rst pyproject.toml

View file

@ -1,10 +1,16 @@
Pelican |build-status| |pypi-version| |repology|
================================================
Pelican |build-status| |pypi-version| |downloads| |repology|
============================================================
Pelican is a static site generator, written in Python_.
Pelican is a static site generator, written in Python_, that allows you to create
web sites by composing text files in formats such as Markdown, reStructuredText, and HTML.
* Write content in reStructuredText_ or Markdown_ using your editor of choice
* Includes a simple command line tool to (re)generate site files
With Pelican, you can create web sites without worrying about databases or server-side programming.
Pelican generates static sites that can be served via any web server or hosting service.
You can perform the following functions with Pelican:
* Compose content in Markdown_ or reStructuredText_ using your editor of choice
* Simple command-line tool (re)generates HTML, CSS, and JS from your source content
* Easy to interface with version control systems and web hooks
* Completely static output is simple to host anywhere
@ -12,18 +18,19 @@ Pelican is a static site generator, written in Python_.
Features
--------
Pelican currently supports:
Pelicans feature highlights include:
* Chronological content (e.g., articles, blog posts) as well as static pages
* Integration with external services (e.g., Google Analytics and Disqus)
* Integration with external services
* Site themes (created using Jinja2_ templates)
* Publication of articles in multiple languages
* Generation of Atom and RSS feeds
* Syntax highlighting via Pygments_
* Importing existing content from WordPress, Dotclear, and other services
* Code syntax highlighting via Pygments_
* Import existing content from WordPress, Dotclear, or RSS feeds
* Fast rebuild times due to content caching and selective output writing
* Extensible via a rich plugin ecosystem: `Pelican Plugins`_
Check out `Pelican's documentation`_ for further information.
Check out the `Pelican documentation`_ for further information.
How to get help, contribute, or provide feedback
@ -35,14 +42,14 @@ See our `contribution submission and feedback guidelines <CONTRIBUTING.rst>`_.
Source code
-----------
Pelican's source code is `hosted on GitHub`_. If you feel like hacking,
take a look at `Pelican's internals`_.
Pelicans source code is `hosted on GitHub`_. For information on how it works,
have a look at `Pelican's internals`_.
Why the name "Pelican"?
Why the name “Pelican”?
-----------------------
"Pelican" is an anagram of *calepin*, which means "notebook" in French.
“Pelican” is an anagram of *calepin*, which means “notebook” in French.
.. Links
@ -52,16 +59,20 @@ Why the name "Pelican"?
.. _Markdown: https://daringfireball.net/projects/markdown/
.. _Jinja2: https://palletsprojects.com/p/jinja/
.. _Pygments: https://pygments.org/
.. _`Pelican's documentation`: https://docs.getpelican.com/
.. _`Pelican Plugins`: https://github.com/pelican-plugins
.. _`Pelican documentation`: https://docs.getpelican.com/
.. _`Pelican's internals`: https://docs.getpelican.com/en/latest/internals.html
.. _`hosted on GitHub`: https://github.com/getpelican/pelican
.. |build-status| image:: https://img.shields.io/github/workflow/status/getpelican/pelican/build
:target: https://github.com/getpelican/pelican/actions
.. |build-status| image:: https://img.shields.io/github/actions/workflow/status/getpelican/pelican/main.yml?branch=main
:target: https://github.com/getpelican/pelican/actions/workflows/main.yml?query=branch%3Amain
:alt: GitHub Actions CI: continuous integration status
.. |pypi-version| image:: https://img.shields.io/pypi/v/pelican.svg
:target: https://pypi.org/project/pelican/
:alt: PyPI: the Python Package Index
.. |downloads| image:: https://img.shields.io/pypi/dm/pelican.svg
:target: https://pypi.org/project/pelican/
:alt: Monthly Downloads from PyPI
.. |repology| image:: https://repology.org/badge/tiny-repos/pelican.svg
:target: https://repology.org/project/pelican/versions
:alt: Repology: the packaging hub

25
THANKS
View file

@ -1,9 +1,9 @@
Pelican is a project originally created by Alexis Métaireau
<https://blog.notmyidea.org/> and subsequently maintained by Justin Mayer
<https://justinmayer.com/>, but there are a large number of people that have
contributed or implemented key features over time. We do our best to keep this
list up-to-date, but you can also have a look at the nice contributor graphs
produced by GitHub: https://github.com/getpelican/pelican/graphs/contributors
Pelican is a project led by Justin Mayer <https://justinmayer.com/>
and originally created by Alexis Métaireau <https://blog.notmyidea.org/>, but
there are a large number of people that have contributed or implemented key
features over time. We do our best to keep this list up-to-date, but you can
also have a look at the nice contributor graphs produced by GitHub:
https://github.com/getpelican/pelican/graphs/contributors
If you want to contribute, check the documentation section about how to do so:
<https://docs.getpelican.com/en/latest/contribute.html>
@ -26,6 +26,7 @@ Arnaud BOS
asselinpaul
Axel Haustant
Ben Rosser (TC01)
Ben Sturmfels
Benoît HERVIER
Bernhard Scheirle
Borgar
@ -64,6 +65,7 @@ Feth Arezki
Florian Jacob
Florian Preinstorfer
Félix Delval
Frederik Ring
Freeculture
George V. Reilly
Guillaume
@ -77,6 +79,7 @@ Iuri de Silvio
Ivan Dyedov
James King
James Rowe
Jason K. Moore
jawher
Jered Boxman
Jerome
@ -87,6 +90,7 @@ John Kristensen
John Mastro
Jökull Sólberg Auðunsson
Jomel Imperio
Jonas Borges
Joseph Reagle
Joshua Adelman
Julian Berman
@ -96,6 +100,7 @@ Kevin Yap
Kyle Fuller
Laureline Guerin
Leonard Huang
Leonardo Giordani
Leroy Jiang
Lucas Cimon
Marcel Hellkamp
@ -113,8 +118,11 @@ Michael Reneer
Michael Yanovich
Mike Yumatov
Mikhail Korobov
Mirek Długosz
m-r-r
mviera
Nam Nguyen
NianQing Yao
Nico Di Rocco
Nicolas Duhamel
Nicolas Perriault
@ -124,6 +132,8 @@ Paul Asselin
Pavel Puchkin
Perry Roper
Peter Desmet
Peter Sabaini
Petr Viktorin
Philippe Pepiot
Rachid Belaid
Randall Degges
@ -133,6 +143,7 @@ Rémy HUBSCHER
renhbo
Richard Duivenvoorde
Rogdham
Romain Porte
Roman Skvazh
Ronny Pfannschmidt
Rory McCann
@ -153,8 +164,10 @@ Tarek Ziade
Thanos Lefteris
Thomas Thurman
Tobias
Tom Adler
Tomi Pieviläinen
Trae Blain
Tristan Miller
Tshepang Lekhonkhobe
Valentin-Costel Hăloiu
Vlad Niculae

1
docs/_static/pelican-logo.svg vendored Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="svg33" width="64" height="64" style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.4142" version="1.1" viewBox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g id="g864" transform="matrix(.10228 0 0 .10228 2.441 6.0098e-5)"><g id="g4" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path2" d="m210.35 607.22c-.34-2.106-.842-4.303-1.491-6.591-1.537-5.441-4.918-10.074-9.506-13.854-1.205-1.001-2.503-1.946-3.88-2.823-5.293-3.381-11.692-5.851-18.522-7.32-4.588-.99-9.367-1.525-14.139-1.593-34.662-.774-56.234.387-90.373-.911.012.023.012.046.022.068 1.56 1.264 3.154 2.471 4.782 3.643 3.573 2.584 7.297 4.952 11.155 7.127 7.184 4.04 14.845 7.342 22.859 9.801.956.295 1.912.58 2.87.842 5.6.603 10.631 1.206 14.648 3.074 1.015.455 1.959 1.001 2.835 1.639 2.87 2.106 6.057 6.124 8.152 8.936 4.497 5.999 3.551 10.928 8.88 13.887.557.308 1.182.604 1.889.866 1.696.638 4.119 1.491 5.225-.91.16-.342.283-.764.387-1.264-.446-1.434-1.981-2.675-2.905-3.29-1.638-1.07-2.287-1.719-3.47-2.937-2.186-2.243-2.333-6.056-3.871-8.708 1.935-.82 12.146-2.186 14.287-1.89 4.576.204 8.185.557 10.939 3.392 1.08.854 1.672 1.594 2.652 2.334.069.057.125.114.194.159 4.338 3.153 8.343 4.28 11.894 5.362.936.284 1.822.558 2.69.876 1.332.478 2.582 1.048 3.754 1.81 1.39.922 3.748 3.336 3.849 5.419-3.496-1.116-1.185.296-6.342-.102-2.515-.285-5.087-.456-7.671-.638-4.018-.284-8.038-.581-11.805-1.297-.627-.115-1.254-.251-1.867-.399-.479-.102-.946-.227-1.401-.353-.011.193-.021.376-.021.546-.104 3.939 2.674 5.908-3.678 13.399-.057.08-.137.159-.205.25-1.686 1.97-10.449 5.715-13.182 6.432-11.634 2.334-20.502-5.237-34.515-1.423-4.929 1.833-8.549 9.824-10.815 15.8-3.016 7.936-5.406 17.576-8.139 27.06 5.329-.797 10.53-1.936 15.585-3.427 11.167-3.279 21.651-8.185 31.168-14.445.911-1.231 1.912-2.29 2.994-3.108.284-.217.58-.422.877-.603.215-.137.956-.286 2.127-.502 10.861-1.924 58.5-8.377 61.597-42.962.319-3.494.172-7.285-.513-11.372zm-106.94 18.59c-6.375-1.924-8.003-2.243-12.055-5.385.067.33.17.695.307 1.081 10.779 6.068 22.608 10.462 35.141 12.842-3.893-9.051-8.502-7.445-23.393-8.538zm29.518-4.099c-2.779-6.738-10.313-10.575-16.813-12.464-8.721-3.12-15.061-.125-33.458-8.811.147.239.284.467.432.694 3.575 2.584 7.297 4.963 11.157 7.126 7.184 4.041 14.844 7.343 22.857 9.802 4.167.489 8.175 1.184 11.863 2.96 1.639.773 3.21 1.764 4.702 3.039-.183-.82-.434-1.605-.74-2.346z" style="fill-rule:nonzero;fill:url(#_Linear1)"/></g><g id="g8" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path6" d="m114.13 595.61c-.958-.262-1.914-.547-2.87-.842-8.014-2.459-15.675-5.761-22.859-9.801-3.858-2.175-7.582-4.543-11.155-7.127-1.628-1.172-3.222-2.379-4.782-3.643 2.14 6.603 11.634 13.57 18.078 16.313 8.218 3.495 16.381 4.303 23.588 5.1z" style="fill:#90d4d1"/></g><g id="g12" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path10" d="m94.253 608.25c-3.86-2.163-7.582-4.542-11.157-7.126 10.006 15.823 22.575 15.584 34.014 16.928-8.013-2.459-15.673-5.761-22.857-9.802z" style="fill:#90d4d1"/></g><g id="g16" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path14" d="m126.81 634.34c-12.533-2.38-24.362-6.774-35.141-12.842 1.376 3.973 6.351 10.257 12.943 11.658 2.858 1.024 2.094.762 6.967.614 7.137-.364 10.552-.592 15.608 1.469-.126-.308-.251-.604-.377-.899z" style="fill:#90d4d1"/></g><g id="g20" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path18" d="m143.27 665.76c-.081.101-.159.204-.239.318-13.844 14.093-31.179 24.69-50.59 30.393 1.492-4.132 2.824-8.468 4.076-12.839 5.329-.797 10.53-1.936 15.585-3.427 11.167-3.279 21.651-8.185 31.168-14.445z" style="fill:#90d4d1"/></g><g id="g24" transform="matrix(4.1667 0 0 4.1667 -301.27 -2392.2)"><path id="path22" d="m143.03 666.08c-6.046 8.287-9.118 24.122-12.659 33.274-5.144 13.342-12.294 22.95-27.958 24.317-3.928.351-27.582 1.24-30.11-.035.159-1.344 4.098-2.961 5.123-3.747 6.852-4.847 11.416-13.5 15.014-23.416 19.411-5.703 36.746-16.3 50.59-30.393z" style="fill:#14a0c4"/></g></g><defs id="defs31"><linearGradient id="_Linear1" x2="1" gradientTransform="matrix(138.58 0 0 138.58 72.442 628.88)" gradientUnits="userSpaceOnUse"><stop id="stop26" style="stop-color:rgb(84,196,198)" offset="0"/><stop id="stop28" style="stop-color:rgb(18,186,213)" offset="1"/></linearGradient></defs></svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -9,4 +9,3 @@
.wy-table-responsive {
overflow: visible !important;
}

201
docs/_templates/page.html vendored Normal file
View file

@ -0,0 +1,201 @@
{% extends "base.html" %}
{% block body -%}
{{ super() }}
{% include "partials/icons.html" %}
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
<label class="overlay sidebar-overlay" for="__navigation">
<div class="visually-hidden">Hide navigation sidebar</div>
</label>
<label class="overlay toc-overlay" for="__toc">
<div class="visually-hidden">Hide table of contents sidebar</div>
</label>
{% if theme_announcement -%}
<div class="announcement">
<aside class="announcement-content">
{% block announcement %} {{ theme_announcement }} {% endblock announcement %}
</aside>
</div>
{%- endif %}
<div class="page">
<header class="mobile-header">
<div class="header-left">
<label class="nav-overlay-icon" for="__navigation">
<div class="visually-hidden">Toggle site navigation sidebar</div>
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
</label>
</div>
<div class="header-center">
<a href="{{ pathto(master_doc) }}"><div class="brand">{{ docstitle if docstitle else project }}</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-header-icon{% if furo_hide_toc %} no-toc{% endif %}" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
</header>
<aside class="sidebar-drawer">
<div class="sidebar-container">
{% block left_sidebar %}
<div class="sidebar-sticky">
{%- for sidebar_section in sidebars %}
{%- include sidebar_section %}
{%- endfor %}
</div>
{% endblock left_sidebar %}
</div>
</aside>
<div class="main">
<div class="content">
<div class="article-container">
<a href="#" class="back-to-top muted-link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
</svg>
<span>{% trans %}Back to top{% endtrans %}</span>
</a>
<div class="content-icon-container">
{% if theme_top_of_page_button == "edit" -%}
{%- include "components/edit-this-page.html" with context -%}
{%- elif theme_top_of_page_button != None -%}
{{ warning("Got an unsupported value for 'top_of_page_button'") }}
{%- endif -%}
{#- Theme toggle -#}
<div class="theme-toggle-container theme-toggle-content">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-content-icon{% if furo_hide_toc %} no-toc{% endif %}" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
<article role="main">
{% block content %}{{ body }}{% endblock %}
</article>
</div>
<footer>
{% block footer %}
<div class="related-pages">
{% if next -%}
<a class="next-page" href="{{ next.link }}">
<div class="page-info">
<div class="context">
<span>{{ _("Next") }}</span>
</div>
<div class="title">{{ next.title }}</div>
</div>
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
</a>
{%- endif %}
{% if prev -%}
<a class="prev-page" href="{{ prev.link }}">
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>{{ _("Previous") }}</span>
</div>
{% if prev.link == pathto(master_doc) %}
<div class="title">{{ _("Home") }}</div>
{% else %}
<div class="title">{{ prev.title }}</div>
{% endif %}
</div>
</a>
{%- endif %}
</div>
<div class="bottom-of-page">
<div class="left-details">
{%- if show_copyright %}
<div class="copyright">
{%- if hasdoc('copyright') %}
{% trans path=pathto('copyright'), copyright=copyright|e -%}
<a href="{{ path }}">Copyright</a> &#169; {{ copyright }}
{%- endtrans %}
{%- else %}
{% trans copyright=copyright|e -%}
Copyright &#169; {{ copyright }}, <a href="https://justinmayer.com">Justin Mayer</a>, Alexis Metaireau, and contributors
{%- endtrans %}
{%- endif %}
</div>
{%- endif %}
{%- if last_updated -%}
<div class="last-updated">
{% trans last_updated=last_updated|e -%}
Last updated on {{ last_updated }}
{%- endtrans -%}
</div>
{%- endif %}
</div>
<div class="right-details">
{% if theme_footer_icons or READTHEDOCS -%}
<div class="icons">
{% if theme_footer_icons -%}
{% for icon_dict in theme_footer_icons -%}
<a class="muted-link {{ icon_dict.class }}" href="{{ icon_dict.url }}" aria-label="{{ icon_dict.name }}">
{{- icon_dict.html -}}
</a>
{% endfor %}
{%- else -%}
{#- Show Read the Docs project -#}
{%- if READTHEDOCS and slug -%}
<a class="muted-link" href="https://readthedocs.org/projects/{{ slug }}" aria-label="On Read the Docs">
<svg x="0px" y="0px" viewBox="-125 217 360 360" xml:space="preserve">
<path fill="currentColor" d="M39.2,391.3c-4.2,0.6-7.1,4.4-6.5,8.5c0.4,3,2.6,5.5,5.5,6.3 c0,0,18.5,6.1,50,8.7c25.3,2.1,54-1.8,54-1.8c4.2-0.1,7.5-3.6,7.4-7.8c-0.1-4.2-3.6-7.5-7.8-7.4c-0.5,0-1,0.1-1.5,0.2 c0,0-28.1,3.5-50.9,1.6c-30.1-2.4-46.5-7.9-46.5-7.9C41.7,391.3,40.4,391.1,39.2,391.3z M39.2,353.6c-4.2,0.6-7.1,4.4-6.5,8.5 c0.4,3,2.6,5.5,5.5,6.3c0,0,18.5,6.1,50,8.7c25.3,2.1,54-1.8,54-1.8c4.2-0.1,7.5-3.6,7.4-7.8c-0.1-4.2-3.6-7.5-7.8-7.4 c-0.5,0-1,0.1-1.5,0.2c0,0-28.1,3.5-50.9,1.6c-30.1-2.4-46.5-7.9-46.5-7.9C41.7,353.6,40.4,353.4,39.2,353.6z M39.2,315.9 c-4.2,0.6-7.1,4.4-6.5,8.5c0.4,3,2.6,5.5,5.5,6.3c0,0,18.5,6.1,50,8.7c25.3,2.1,54-1.8,54-1.8c4.2-0.1,7.5-3.6,7.4-7.8 c-0.1-4.2-3.6-7.5-7.8-7.4c-0.5,0-1,0.1-1.5,0.2c0,0-28.1,3.5-50.9,1.6c-30.1-2.4-46.5-7.9-46.5-7.9 C41.7,315.9,40.4,315.8,39.2,315.9z M39.2,278.3c-4.2,0.6-7.1,4.4-6.5,8.5c0.4,3,2.6,5.5,5.5,6.3c0,0,18.5,6.1,50,8.7 c25.3,2.1,54-1.8,54-1.8c4.2-0.1,7.5-3.6,7.4-7.8c-0.1-4.2-3.6-7.5-7.8-7.4c-0.5,0-1,0.1-1.5,0.2c0,0-28.1,3.5-50.9,1.6 c-30.1-2.4-46.5-7.9-46.5-7.9C41.7,278.2,40.4,278.1,39.2,278.3z M-13.6,238.5c-39.6,0.3-54.3,12.5-54.3,12.5v295.7 c0,0,14.4-12.4,60.8-10.5s55.9,18.2,112.9,19.3s71.3-8.8,71.3-8.8l0.8-301.4c0,0-25.6,7.3-75.6,7.7c-49.9,0.4-61.9-12.7-107.7-14.2 C-8.2,238.6-10.9,238.5-13.6,238.5z M19.5,257.8c0,0,24,7.9,68.3,10.1c37.5,1.9,75-3.7,75-3.7v267.9c0,0-19,10-66.5,6.6 C59.5,536.1,19,522.1,19,522.1L19.5,257.8z M-3.6,264.8c4.2,0,7.7,3.4,7.7,7.7c0,4.2-3.4,7.7-7.7,7.7c0,0-12.4,0.1-20,0.8 c-12.7,1.3-21.4,5.9-21.4,5.9c-3.7,2-8.4,0.5-10.3-3.2c-2-3.7-0.5-8.4,3.2-10.3c0,0,0,0,0,0c0,0,11.3-6,27-7.5 C-16,264.9-3.6,264.8-3.6,264.8z M-11,302.6c4.2-0.1,7.4,0,7.4,0c4.2,0.5,7.2,4.3,6.7,8.5c-0.4,3.5-3.2,6.3-6.7,6.7 c0,0-12.4,0.1-20,0.8c-12.7,1.3-21.4,5.9-21.4,5.9c-3.7,2-8.4,0.5-10.3-3.2c-2-3.7-0.5-8.4,3.2-10.3c0,0,11.3-6,27-7.5 C-20.5,302.9-15.2,302.7-11,302.6z M-3.6,340.2c4.2,0,7.7,3.4,7.7,7.7s-3.4,7.7-7.7,7.7c0,0-12.4-0.1-20,0.7 c-12.7,1.3-21.4,5.9-21.4,5.9c-3.7,2-8.4,0.5-10.3-3.2c-2-3.7-0.5-8.4,3.2-10.3c0,0,11.3-6,27-7.5C-16,340.1-3.6,340.2-3.6,340.2z" />
</svg>
</a>
{%- endif -%}
{#- Show GitHub repository home -#}
{%- if READTHEDOCS and display_github and github_user != "None" and github_repo != "None" -%}
<a class="muted-link" href="https://github.com/{{ github_user }}/{{ github_repo }}" aria-label="On GitHub">
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
</svg>
</a>
{%- endif -%}
{%- endif %}
</div>
{%- endif %}
</div>
</div>
{% endblock footer %}
</footer>
</div>
<aside class="toc-drawer{% if furo_hide_toc %} no-toc{% endif %}">
{% block right_sidebar %}
{% if not furo_hide_toc %}
<div class="toc-sticky toc-scroll">
<div class="toc-title-container">
<span class="toc-title">
{{ _("On this page") }}
</span>
</div>
<div class="toc-tree-container">
<div class="toc-tree">
{{ toc }}
</div>
</div>
</div>
{% endif %}
{% endblock right_sidebar %}
</aside>
</div>
</div>
{%- endblock %}

View file

@ -1,6 +1,106 @@
Release history
###############
4.11.0 - 2025-01-15
===================
- Add setting to selectively omit Typogrify filters `(#3439) <https://github.com/getpelican/pelican/pull/3439>`_
- Add more blocks to the Simple themes base template, making it easier to create new themes by inheriting from the Simple theme `(#3405) <https://github.com/getpelican/pelican/pull/3405>`_
- Fix auto-reload behavior upon changes to the theme, content or settings. Make default ``IGNORE_FILES`` recursively ignore all hidden files as well as the `default filters <https://watchfiles.helpmanual.io/api/filters/#watchfiles.DefaultFilter.ignore_dirs>`_ from ``watchfiles.DefaultFilter``. `(#3441) <https://github.com/getpelican/pelican/pull/3441>`_
- Get current year from the ``SOURCE_DATE_EPOCH`` environment variable, if available `(#3430) <https://github.com/getpelican/pelican/pull/3430>`_
- Add Python 3.13 to test matrix and remove Python 3.8 `(#3435) <https://github.com/getpelican/pelican/pull/3435>`_
- Require Typogrify 2.1+ and Pygments <2.19
4.10.2 - 2024-11-27
===================
- Change ``IGNORE_FILES`` setting default to ignore all hidden files
- Fix ``SUMMARY_MAX_PARAGRAPHS`` not being respected in some combinations with ``SUMMARY_MAX_LENGTH``
4.10.1 - 2024-09-28
===================
- Fix error when running ``pelican -r -l``
- Fix symlink handling in ``pelican-themes``
4.10.0 - 2024-09-16
===================
- Add setting to specify summary via paragraph count
- Add new status to skip generation of a post
- Add setting to append ``ref`` parameter to links in feeds
- Configure logging handler via ``--log-handler`` CLI option
- Resolve intra-site links in summaries
- Warn when files are not processed due to disabled readers
- Add Medium post importer
- Improve GitHub Pages workflow
- Improve code test coverage
- Translate documentation into Simplified Chinese
4.9.1 - 2023-11-15
==================
* Ensure ``tzdata`` dependency is installed on Windows
4.9.0 - 2023-11-12
==================
* Upgrade code to new minimum supported Python version: 3.8
* Settings support for ``pathlib.Path`` `(#2758) <https://github.com/getpelican/pelican/pull/2758>`_
* Various improvements to Simple theme (`#2976 <https://github.com/getpelican/pelican/pull/2976>`_ & `#3234 <https://github.com/getpelican/pelican/pull/3234>`_)
* Use Furo as Sphinx documentation theme `(#3023) <https://github.com/getpelican/pelican/pull/3023>`_
* Default to 100 articles maximum in feeds `(#3127) <https://github.com/getpelican/pelican/pull/3127>`_
* Add ``period_archives common context`` variable `(#3148) <https://github.com/getpelican/pelican/pull/3148>`_
* Use ``watchfiles`` as the file-watching backend `(#3151) <https://github.com/getpelican/pelican/pull/3151>`_
* Add GitHub Actions workflow for GitHub Pages `(#3189) <https://github.com/getpelican/pelican/pull/3189>`_
* Allow dataclasses in settings `(#3204) <https://github.com/getpelican/pelican/pull/3204>`_
* Switch build tool to PDM instead of Setuptools/Poetry `(#3220) <https://github.com/getpelican/pelican/pull/3220>`_
* Provide a ``plugin_enabled`` Jinja test for themes `(#3235) <https://github.com/getpelican/pelican/pull/3235>`_
* Preserve connection order in Blinker `(#3238) <https://github.com/getpelican/pelican/pull/3238>`_
* Remove social icons from default ``notmyidea`` theme `(#3240) <https://github.com/getpelican/pelican/pull/3240>`_
* Remove unreliable ``WRITE_SELECTED`` feature `(#3243) <https://github.com/getpelican/pelican/pull/3243>`_
* Importer: Report broken embedded video links when importing from Tumblr `(#3177) <https://github.com/getpelican/pelican/issues/3177>`_
* Importer: Remove newline addition when iterating Photo post types `(#3178) <https://github.com/getpelican/pelican/issues/3178>`_
* Importer: Force timestamp conversion in Tumblr importer to be UTC with offset `(#3221) <https://github.com/getpelican/pelican/pull/3221>`_
* Importer: Use tempfile for intermediate HTML file for Pandoc `(#3221) <https://github.com/getpelican/pelican/pull/3221>`_
* Switch linters to Ruff `(#3223) <https://github.com/getpelican/pelican/pull/3223>`_
4.8.0 - 2022-07-11
==================
* Use JSON values for extra settings in Invoke tasks template `(#2994) <https://github.com/getpelican/pelican/pull/2994>`_
* Add content tag for links, which can help with things like Twitter social cards `(#3001) <https://github.com/getpelican/pelican/pull/3001>`_
* Improve word count behavior when generating summary `(#3002) <https://github.com/getpelican/pelican/pull/3002>`_
4.7.2 - 2022-02-09
==================
* Fix incorrect parsing of parameters specified via `-e` / `--extra-settings` option flags `(#2938) <https://github.com/getpelican/pelican/pull/2938>`_
* Add ``categories.html`` template to default theme `(#2973) <https://github.com/getpelican/pelican/pull/2973>`_
* Document how to use plugins to inject content `(#2922) <https://github.com/getpelican/pelican/pull/2922>`_
4.7.1 - 2021-10-12
==================
* Extend rich logging to server component `(#2927) <https://github.com/getpelican/pelican/pull/2927>`_
* Fix an issue where metadata flagged to be discarded was being cached `(#2926) <https://github.com/getpelican/pelican/pull/2926>`_
* Adjust suffix in server to allow redirection when needed `(#2931) <https://github.com/getpelican/pelican/pull/2931>`_
* Add MIME types for web fonts `(#2929) <https://github.com/getpelican/pelican/pull/2929>`_
* Distribute sample data used to run tests `(#2935) <https://github.com/getpelican/pelican/pull/2935>`_
* Add Python 3.10 to test matrix
4.7.0 - 2021-10-01
==================
* Improve default theme rendering on mobile and other small screen devices `(#2914) <https://github.com/getpelican/pelican/pull/2914>`_
* Add support for hidden articles `(#2866) <https://github.com/getpelican/pelican/pull/2866>`_
* Improve word count behavior when generating summary CJK & other locales `(#2864) <https://github.com/getpelican/pelican/pull/2864>`_
* Add progress spinner during generation `(#2869) <https://github.com/getpelican/pelican/pull/2869>`_
and richer logging `(#2897) <https://github.com/getpelican/pelican/pull/2897>`_, both via `Rich <https://github.com/willmcgugan/rich>`_
* Invoke tasks ``serve`` and ``livereload`` now auto-open a web browser pointing to the locally-served web site `(#2764) <https://github.com/getpelican/pelican/pull/2764>`_
* Support some date format codes used by ISO dates `(#2902) <https://github.com/getpelican/pelican/pull/2902>`_
* Document how to add a new writer `(#2901) <https://github.com/getpelican/pelican/pull/2901>`_
4.6.0 - 2021-03-23
==================

View file

@ -1,51 +1,64 @@
import datetime
import os
import sys
import time
from pelican import __version__
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
sys.path.append(os.path.abspath(os.pardir))
with open("../pyproject.toml", "rb") as f:
project_data = tomllib.load(f).get("project")
if project_data is None:
raise KeyError("project data is not found")
# -- General configuration ----------------------------------------------------
templates_path = ['_templates']
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.ifconfig',
'sphinx.ext.extlinks']
source_suffix = '.rst'
master_doc = 'index'
project = 'Pelican'
copyright = '2010 present, Justin Mayer, Alexis Metaireau, and contributors'
exclude_patterns = ['_build']
release = __version__
version = '.'.join(release.split('.')[:1])
last_stable = __version__
rst_prolog = '''
.. |last_stable| replace:: :pelican-doc:`{}`
'''.format(last_stable)
templates_path = ["_templates"]
locale_dirs = ["locale/"]
gettext_compact = False
gettext_uuid = True
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.extlinks",
"sphinxext.opengraph",
]
source_suffix = ".rst"
master_doc = "index"
project = project_data.get("name").upper()
year = datetime.datetime.fromtimestamp(
int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.timezone.utc
).year
project_copyright = f"2010{year}" # noqa: RUF001
exclude_patterns = ["_build"]
release = project_data.get("version")
version = ".".join(release.split(".")[:1])
last_stable = project_data.get("version")
rst_prolog = f"""
.. |last_stable| replace:: :pelican-doc:`{last_stable}`
.. |min_python| replace:: {project_data.get("requires-python").split(",")[0]}
"""
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
extlinks = {
'pelican-doc': ('https://docs.getpelican.com/%s/', '')
}
extlinks = {"pelican-doc": ("https://docs.getpelican.com/en/latest/%s.html", "%s")}
# -- Options for HTML output --------------------------------------------------
html_theme = 'default'
if not on_rtd:
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
pass
html_static_path = ['_static']
html_theme = "furo"
html_title = f"<strong>{project}</strong> <i>{release}</i>"
html_static_path = ["_static"]
html_theme_options = {
"light_logo": "pelican-logo.svg",
"dark_logo": "pelican-logo.svg",
"navigation_with_keys": True,
}
# Output file base name for HTML help builder.
htmlhelp_basename = 'Pelicandoc'
htmlhelp_basename = "Pelicandoc"
html_use_smartypants = True
@ -61,21 +74,29 @@ html_show_sourcelink = False
def setup(app):
# overrides for wide tables in RTD theme
app.add_css_file('theme_overrides.css') # path relative to _static
app.add_css_file("theme_overrides.css") # path relative to _static
# -- Options for LaTeX output -------------------------------------------------
latex_documents = [
('index', 'Pelican.tex', 'Pelican Documentation', 'Justin Mayer',
'manual'),
("index", "Pelican.tex", "Pelican Documentation", "Justin Mayer", "manual"),
]
# -- Options for manual page output -------------------------------------------
man_pages = [
('index', 'pelican', 'pelican documentation',
['Justin Mayer'], 1),
('pelican-themes', 'pelican-themes', 'A theme manager for Pelican',
['Mickaël Raybaud'], 1),
('themes', 'pelican-theming', 'How to create themes for Pelican',
['The Pelican contributors'], 1)
("index", "pelican", "pelican documentation", ["Justin Mayer"], 1),
(
"pelican-themes",
"pelican-themes",
"A theme manager for Pelican",
["Mickaël Raybaud"],
1,
),
(
"themes",
"pelican-theming",
"How to create themes for Pelican",
["The Pelican contributors"],
1,
),
]

View file

@ -89,14 +89,15 @@ contains a list of reserved metadata keywords:
``summary`` Brief description of content for index pages
``lang`` Content language ID (``en``, ``fr``, etc.)
``translation`` If content is a translation of another (``true`` or ``false``)
``status`` Content status: ``draft``, ``hidden``, or ``published``
``status`` Content status: ``draft``, ``hidden``, ``skip``, or ``published``
``template`` Name of template to use to generate content (without extension)
``save_as`` Save content to this relative file path
``url`` URL to use for this article/page
=============== ===============================================================
Readers for additional formats (such as AsciiDoc_) are available via plugins.
Refer to `pelican-plugins`_ repository for those.
Readers for additional formats (such as AsciiDoc_) are available via plugins,
which you can find via the `Pelican Plugins`_ collection as well as the legacy
`pelican-plugins`_ repository.
Pelican can also process HTML files ending in ``.html`` and ``.htm``. Pelican
interprets the HTML in a very straightforward manner, reading metadata from
@ -161,7 +162,10 @@ author you can use ``author`` field.
If you do not explicitly specify summary metadata for a given post, the
``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the
beginning of an article are used as the summary.
beginning of an article are used as the summary. You can also use an article's
first N paragraphs as its summary using the ``SUMMARY_MAX_PARAGRAPHS`` setting.
If both settings are in use, the specified number of paragraphs will
be used but may be truncated to respect the specified maximum length.
You can also extract any metadata from the filename through a regular
expression to be set in the ``FILENAME_METADATA`` setting. All named groups
@ -183,7 +187,7 @@ files in it will be used to generate static pages, such as **About** or
You can use the ``DISPLAY_PAGES_ON_MENU`` setting to control whether all those
pages are displayed in the primary navigation menu. (Default is ``True``.)
If you want to exclude any pages from being linked to or listed in the menu
If you want to exclude any pages from being linked to or listed in the menu,
then add a ``status: hidden`` attribute to its metadata. This is useful for
things like making error pages that fit the generated theme of your site.
@ -197,6 +201,13 @@ are copied over with the ``STATIC_PATHS`` setting of the project's
``images`` directory for this, but others must be added manually. In addition,
static files that are explicitly linked to are included (see below).
.. note::
In the default configuration, all files with a valid content file suffix
(``.html``, ``.rst``, ``.md``, ...) get processed by the article and page
generators *before* the static generator. This is avoided by altering the
``*_EXCLUDE`` settings appropriately.
Mixed content in the same directory
-----------------------------------
@ -227,7 +238,7 @@ that may be sitting alongside that post (instead of having to determine where
the other content will be placed after site generation).
To link to internal content (files in the ``content`` directory), use the
following syntax for the link target: ``{filename}path/to/file``
following syntax for the link target: ``{filename}path/to/file``.
Note: forward slashes, ``/``,
are the required path separator in the ``{filename}`` directive
on all operating systems, including Windows.
@ -299,7 +310,7 @@ Attaching static files
----------------------
Starting with Pelican 3.5, static files can be "attached" to a page or article
using this syntax for the link target: ``{attach}path/to/file`` This works
using this syntax for the link target: ``{attach}path/to/file``. This works
like the ``{static}`` syntax, but also relocates the static file into the
linking document's output directory. If the static file originates from a
subdirectory beneath the linking document's source, that relationship will be
@ -431,8 +442,8 @@ For **Markdown**, one must rely on an extension. For example, using the `mdx_inc
Importing an existing site
==========================
It is possible to import your site from WordPress, Tumblr, Dotclear, and RSS
feeds using a simple script. See :ref:`import`.
It is possible to import your site from several other blogging sites
(like WordPress, Tumblr, ..) using a simple script. See :ref:`import`.
Translations
============
@ -531,12 +542,12 @@ The specified identifier (e.g. ``python``, ``ruby``) should be one that
appears on the `list of available lexers <https://pygments.org/docs/lexers/>`_.
When using reStructuredText the following options are available in the
code-block directive:
`code-block` directive:
============= ============ =========================================
Option Valid values Description
============= ============ =========================================
anchorlinenos N/A If present wrap line numbers in <a> tags.
anchorlinenos N/A If present, wrap line numbers in ``<a>`` tags.
classprefix string String to prepend to token class names
hl_lines numbers List of lines to be highlighted, where
line numbers to highlight are separated
@ -547,22 +558,22 @@ hl_lines numbers List of lines to be highlighted, where
line numbers.
lineanchors string Wrap each line in an anchor using this
string and -linenumber.
linenos string If present or set to "table" output line
numbers in a table, if set to
"inline" output them inline. "none" means
linenos string If present or set to "table", output line
numbers in a table; if set to
"inline", output them inline. "none" means
do not output the line numbers for this
table.
linenospecial number If set every nth line will be given the
'special' css class.
linenospecial number If set, every nth line will be given the
'special' CSS class.
linenostart number Line number for the first line.
linenostep number Print every nth line number.
lineseparator string String to print between lines of code,
'\n' by default.
linespans string Wrap each line in a span using this and
-linenumber.
nobackground N/A If set do not output background color for
nobackground N/A If set, do not output background color for
the wrapping element
nowrap N/A If set do not wrap the tokens at all.
nowrap N/A If set, do not wrap the tokens at all.
tagsfile string ctags file to use for name definitions.
tagurlformat string format for the ctag links.
============= ============ =========================================
@ -588,7 +599,7 @@ Pelican settings file to include options that will be automatically applied to
every code block.
For example, if you want to have line numbers displayed for every code block
and a CSS prefix you would set this variable to::
and a CSS prefix, you would set this variable to::
PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'}
@ -604,7 +615,7 @@ its metadata. That article will then be output to the ``drafts`` folder and not
listed on the index page nor on any category or tag page.
If your articles should be automatically published as a draft (to not
accidentally publish an article before it is finished) include the status in
accidentally publish an article before it is finished), include the status in
the ``DEFAULT_METADATA``::
DEFAULT_METADATA = {
@ -614,8 +625,24 @@ the ``DEFAULT_METADATA``::
To publish a post when the default status is ``draft``, update the post's
metadata to include ``Status: published``.
Hidden Posts
============
Like pages, posts can also be marked as ``hidden`` with the ``Status: hidden``
attribute. Hidden posts will be output to ``ARTICLE_SAVE_AS`` as expected, but
are not included by default in tag, category, and author indexes, nor in the
main article feed. This has the effect of creating an "unlisted" post.
Skip Posts
==========
Posts marked with ``skip`` status are ignored entirely. They are not processed
nor output to the ``ARTICLE_SAVE_AS`` path. Such posts will similarly not be
included in indexes or feeds.
.. _W3C ISO 8601: https://www.w3.org/TR/NOTE-datetime
.. _AsciiDoc: https://www.methods.co.nz/asciidoc/
.. _AsciiDoc: https://asciidoc.org
.. _Pelican Plugins: https://github.com/pelican-plugins
.. _pelican-plugins: https://github.com/getpelican/pelican-plugins
.. _Python-Markdown: https://github.com/Python-Markdown/markdown
.. _Markdown Extensions: https://python-markdown.github.io/extensions/

View file

@ -15,16 +15,16 @@ Setting up the development environment
======================================
While there are many ways to set up one's development environment, the following
instructions will utilize Pip_ and Poetry_. These tools facilitate managing
instructions will utilize Pip_ and PDM_. These tools facilitate managing
virtual environments for separate Python projects that are isolated from one
another, so you can use different packages (and package versions) for each.
Please note that Python 3.6+ is required for Pelican development.
Please note that Python |min_python| is required for Pelican development.
*(Optional)* If you prefer to install Poetry once for use with multiple projects,
*(Optional)* If you prefer to `install PDM <https://pdm.fming.dev/latest/#installation>`_ once for use with multiple projects,
you can install it via::
curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
curl -sSL https://pdm.fming.dev/install-pdm.py | python3 -
Point your web browser to the `Pelican repository`_ and tap the **Fork** button
at top-right. Then clone the source for your fork and add the upstream project
@ -35,23 +35,22 @@ as a Git remote::
cd ~/projects/pelican
git remote add upstream https://github.com/getpelican/pelican.git
While Poetry can dynamically create and manage virtual environments, we're going
While PDM can dynamically create and manage virtual environments, we're going
to manually create and activate a virtual environment::
mkdir ~/virtualenvs
python3 -m venv ~/virtualenvs/pelican
source ~/virtualenvs/pelican/bin/activate
mkdir ~/virtualenvs && cd ~/virtualenvs
python3 -m venv pelican
source ~/virtualenvs/pelican/*/activate
Install the needed dependencies and set up the project::
python -m pip install invoke
invoke setup
python -m pip install -e ~/projects/pelican
Your local environment should now be ready to go!
.. _Pip: https://pip.pypa.io/
.. _Poetry: https://poetry.eustace.io/docs/#installation
.. _PDM: https://pdm.fming.dev/latest/
.. _Pelican repository: https://github.com/getpelican/pelican
Development
@ -65,6 +64,27 @@ your bug fix or feature::
Now you can make changes to Pelican, its documentation, and/or other aspects of
the project.
Setting up ``git blame`` (optional)
-----------------------------------
``git blame`` annotates lines in a file with information about the pull request
that last modified it. Sweeping shallow changes (like formatting) can make that
information less useful, so we keep a list of such changes to be ignored. Run the
following command to set this up in your repository, adding ``--global`` if you
want this setting to apply to all repositories::
git config blame.ignoreRevsFile .git-blame-ignore-revs
As noted in a `useful article`_ about ``git blame``, there are other related
settings you may find to be beneficial::
# Add `?` to any lines that have had a commit skipped using --ignore-rev
git config --global blame.markIgnoredLines true
# Add `*` to any lines that were added in a skipped commit and can not be attributed
git config --global blame.markUnblamableLines true
.. _useful article: https://www.michaelheap.com/git-ignore-rev/
Running the test suite
----------------------
@ -75,14 +95,22 @@ via::
invoke tests
(For more on Invoke, see ``invoke -l`` to list tasks, or
https://pyinvoke.org for documentation.)
In addition to running the test suite, it is important to also ensure that any
lines you changed conform to code style guidelines. You can check that via::
invoke lint
If style violations are found, many of them can be addressed automatically via::
invoke lint --fix
invoke format
If code style violations are found in lines you changed, correct those lines
and re-run the above lint command until they have all been fixed. You do not
need to address style violations, if any, for code lines you did not touch.
and re-run the ``invoke lint`` command until they have all been fixed. You do
not need to address style violations, if any, for code lines you did not touch.
After making your changes and running the tests, you may see a test failure
mentioning that "some generated files differ from the expected functional tests
@ -106,6 +134,21 @@ environments.
.. _Tox: https://tox.readthedocs.io/en/latest/
Running a code coverage report
------------------------------
Code is more likely to stay robust if it is tested. Coverage_ is a library that
measures how much of the code is tested. To run it::
invoke coverage
This will show overall coverage, coverage per file, and even line-by-line coverage.
There is also an HTML report available::
open htmlcov/index.html
.. _Coverage: https://github.com/nedbat/coveragepy
Building the docs
-----------------
@ -156,8 +199,8 @@ check for code style compliance via::
If style violations are found, many of them can be addressed automatically via::
invoke black
invoke isort
invoke lint --fix
invoke format
If style violations are found even after running the above auto-formatters,
you will need to make additional manual changes until ``invoke lint`` no longer

View file

@ -11,13 +11,13 @@ Please read our :doc:`feedback guidelines <contribute>`.
How can I help?
===============
There are several ways to help out. First, you can report any Pelican
suggestions or problems you might have via IRC (preferred) or the `issue
tracker <https://github.com/getpelican/pelican/issues>`_. If submitting an
issue report, please first check the existing issue list (both open and closed)
in order to avoid submitting a duplicate issue.
There are several ways to help out. First, you can communicate any Pelican
suggestions or problems you might have via `Pelican Discussions
<https://github.com/getpelican/pelican/discussions>`_. Please first check the
existing list of discussions and issues (both open and closed) in order to
avoid submitting topics that have already been covered before.
If you want to contribute, please fork `the git repository
If you want to contribute, please fork `the Git repository
<https://github.com/getpelican/pelican/>`_, create a new feature branch, make
your changes, and issue a pull request. Someone will review your changes as
soon as possible. Please refer to the :doc:`How to Contribute <contribute>`
@ -64,11 +64,24 @@ How do I create my own theme?
Please refer to :ref:`theming-pelican`.
Can I override individual templates without forking the whole theme?
====================================================================
Yes, you can override existing templates of the theme that you are using, or
add new templates, via the ``THEME_TEMPLATES_OVERRIDES`` variable. For example,
to override the page template, you can define the location for your templates
like this::
THEME_TEMPLATES_OVERRIDES = ["templates"]
You can then define a custom template in ``templates/page.html``.
See :ref:`settings/themes` for details.
I want to use Markdown, but I got an error.
===========================================
If you try to generate Markdown content without first installing the Markdown
library, may see a message that says ``No valid files found in content``.
library, you may see a message that says ``No valid files found in content``.
Markdown is not a hard dependency for Pelican, so if you have content in
Markdown format, you will need to explicitly install the Markdown library. You
can do so by typing the following command, prepending ``sudo`` if permissions
@ -99,6 +112,15 @@ If you want to include metadata in templates outside the article context (e.g.,
{% if article and article.modified %}
How do I make my output folder structure identical to my content hierarchy?
===========================================================================
Try these settings::
USE_FOLDER_AS_CATEGORY = False
PATH_METADATA = r"(?P<path_no_ext>.*)\..*"
ARTICLE_URL = ARTICLE_SAVE_AS = PAGE_URL = PAGE_SAVE_AS = "{path_no_ext}.html"
How do I assign custom templates on a per-page basis?
=====================================================
@ -113,7 +135,8 @@ For content in Markdown format::
Template: template_name
Then just make sure your theme contains the relevant template file (e.g.
``template_name.html``).
``template_name.html``). If you just want to add a new custom template to an
existing theme, you can also provide it in a directory specified by ``THEME_TEMPLATES_OVERRIDES`` (see :ref:`settings/themes`).
How can I override the generated URL of a specific page or article?
===================================================================
@ -128,7 +151,7 @@ to override the generated URL. Here is an example page in reST format::
:save_as: override/url/index.html
With this metadata, the page will be written to ``override/url/index.html``
and Pelican will use url ``override/url/`` to link to this page.
and Pelican will use the URL ``override/url/`` to link to this page.
How can I use a static page as my home page?
============================================
@ -217,10 +240,6 @@ changed. A simple solution is to make ``rsync`` use the ``--checksum`` option,
which will make it compare the file checksums in a much faster way than Pelican
would.
When only several specific output files are of interest (e.g. when working on
some specific page or the theme templates), the ``WRITE_SELECTED`` option may
help, see :ref:`writing_only_selected_content`.
How to process only a subset of all articles?
=============================================
@ -229,7 +248,7 @@ This can be achieved by explicitly specifying only the filenames of those
articles in ``ARTICLE_PATHS``. A list of such filenames could be found using a
command similar to ``cd content; find -name '*.md' | head -n 10``.
My tag-cloud is missing/broken since I upgraded Pelican
My tag cloud is missing/broken since I upgraded Pelican
=======================================================
In an ongoing effort to streamline Pelican, tag cloud generation has been

View file

@ -11,7 +11,7 @@ software to reStructuredText or Markdown. The supported import formats are:
- Blogger XML export
- Dotclear export
- Posterous API
- Medium export
- Tumblr API
- WordPress XML export
- RSS/Atom feed
@ -27,6 +27,12 @@ not be converted (as Pelican also supports Markdown).
manually, or use a plugin such as `More Categories`_ that enables multiple
categories per article.
.. note::
Imported pages may contain links to images that still point to the original site.
So you might want to download those images into your local content and manually
re-link them from the relevant pages of your site.
Dependencies
============
@ -48,16 +54,15 @@ Usage
::
pelican-import [-h] [--blogger] [--dotclear] [--posterous] [--tumblr] [--wpfile] [--feed]
pelican-import [-h] [--blogger] [--dotclear] [--tumblr] [--wpfile] [--feed]
[-o OUTPUT] [-m MARKUP] [--dir-cat] [--dir-page] [--strip-raw] [--wp-custpost]
[--wp-attach] [--disable-slugs] [-e EMAIL] [-p PASSWORD] [-b BLOGNAME]
input|api_token|api_key
[--wp-attach] [--disable-slugs] [-b BLOGNAME]
input|api_key
Positional arguments
--------------------
============= ============================================================================
``input`` The input file to read
``api_token`` (Posterous only) api_token can be obtained from http://posterous.com/api/
``api_key`` (Tumblr only) api_key can be obtained from https://www.tumblr.com/oauth/apps
============= ============================================================================
@ -67,7 +72,7 @@ Optional arguments
-h, --help Show this help message and exit
--blogger Blogger XML export (default: False)
--dotclear Dotclear export (default: False)
--posterous Posterous API (default: False)
--medium Medium export (default: False)
--tumblr Tumblr API (default: False)
--wpfile WordPress XML export (default: False)
--feed Feed to parse (default: False)
@ -83,8 +88,7 @@ Optional arguments
(default: False)
--filter-author Import only post from the specified author
--strip-raw Strip raw HTML code that can't be converted to markup
such as flash embeds or iframes (wordpress import
only) (default: False)
such as flash embeds or iframes (default: False)
--wp-custpost Put wordpress custom post types in directories. If
used with --dir-cat option directories will be created
as "/post_type/category/" (wordpress import only)
@ -101,10 +105,6 @@ Optional arguments
output. With this disabled, your Pelican URLs may not
be consistent with your original posts. (default:
False)
-e EMAIL, --email=EMAIL
Email used to authenticate Posterous API
-p PASSWORD, --password=PASSWORD
Password used to authenticate Posterous API
-b BLOGNAME, --blogname=BLOGNAME
Blog name used in Tumblr API
@ -120,18 +120,31 @@ For Dotclear::
$ pelican-import --dotclear -o ~/output ~/backup.txt
for Posterous::
For Medium::
$ pelican-import --posterous -o ~/output --email=<email_address> --password=<password> <api_token>
$ pelican-import --medium -o ~/output ~/medium-export/posts/
The Medium export is a zip file. Unzip it, and point this tool to the
"posts" subdirectory. For more information on how to export, see
https://help.medium.com/hc/en-us/articles/115004745787-Export-your-account-data.
For Tumblr::
$ pelican-import --tumblr -o ~/output --blogname=<blogname> <api_token>
$ pelican-import --tumblr -o ~/output --blogname=<blogname> <api_key>
For WordPress::
$ pelican-import --wpfile -o ~/output ~/posts.xml
For Medium (an example of using an RSS feed):
$ python -m pip install feedparser
$ pelican-import --feed https://medium.com/feed/@username
.. note::
The RSS feed may only return the most recent posts — not all of them.
Tests
=====

View file

@ -1,15 +1,6 @@
Pelican |release|
=================
.. ifconfig:: release.endswith('.dev')
.. warning::
This documentation is for the version of Pelican currently under
development. Were you looking for version |last_stable| documentation?
Pelican is a static site generator, written in Python_. Highlights include:
* Write your content directly with your editor of choice in reStructuredText_
@ -23,19 +14,17 @@ Ready to get started? Check out the :doc:`Quickstart<quickstart>` guide.
Features
--------
Pelican |version| currently supports:
Pelicans feature highlights include:
* Articles (e.g., blog posts) and pages (e.g., "About", "Projects", "Contact")
* Comments, via an external service (Disqus). If you prefer to have more
control over your comment data, self-hosted comments are another option.
Check out the `Pelican Plugins`_ repository for more details.
* Theming support (themes are created using Jinja2_ templates)
* Integration with external services
* Site themes (created using Jinja2_ templates)
* Publication of articles in multiple languages
* Atom/RSS feeds
* Generation of Atom and RSS feeds
* Code syntax highlighting
* Import from WordPress, Dotclear, or RSS feeds
* Integration with external tools: Twitter, Google Analytics, etc. (optional)
* Import existing content from WordPress, Dotclear, or RSS feeds
* Fast rebuild times thanks to content caching and selective output writing
* Extensible via a rich plugin ecosystem: `Pelican Plugins`_
Why the name "Pelican"?
-----------------------
@ -63,8 +52,8 @@ Documentation
content
publish
settings
themes
plugins
themes
pelican-themes
importer
faq
@ -82,4 +71,4 @@ Documentation
.. _Jinja2: https://palletsprojects.com/p/jinja/
.. _`Pelican documentation`: https://docs.getpelican.com/latest/
.. _`Pelican's internals`: https://docs.getpelican.com/en/latest/internals.html
.. _`Pelican plugins`: https://github.com/getpelican/pelican-plugins
.. _`Pelican Plugins`: https://github.com/pelican-plugins

View file

@ -1,7 +1,7 @@
Installing Pelican
##################
Pelican currently runs best on 3.6+; earlier versions of Python are not supported.
Pelican currently runs best on |min_python|; earlier versions of Python are not supported.
You can install Pelican via several different methods. The simplest is via Pip_::
@ -25,10 +25,10 @@ session and create a new virtual environment for Pelican::
Once the virtual environment has been created and activated, Pelican can be
installed via ``python -m pip install pelican`` as noted above. Alternatively, if you
have the project source, you can install Pelican using the distutils method::
have the project source, you can install Pelican using the setuptools method::
cd path-to-Pelican-source
python setup.py install
python -m pip install .
If you have Git installed and prefer to install the latest bleeding-edge
version of Pelican rather than a stable release, use the following command::
@ -64,7 +64,6 @@ automatically installed without any action on your part:
* `pygments <https://pypi.org/project/Pygments/>`_, for syntax highlighting
* `docutils <https://pypi.org/project/docutils/>`_, for supporting
reStructuredText as an input format
* `pytz <https://pypi.org/project/pytz/>`_, for timezone definitions
* `blinker <https://pypi.org/project/blinker/>`_, an object-to-object and
broadcast signaling system
* `unidecode <https://pypi.org/project/Unidecode/>`_, for ASCII

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,669 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-13 11:46+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.17.0\n"
#: ../../contribute.rst:2 848b6c0ec944440791d56b25e314a8ab
msgid "Contributing and feedback guidelines"
msgstr "项目贡献与意见反馈"
#: ../../contribute.rst:4 e8b8762778fd461db0934f07e4fc1fc5
msgid ""
"There are many ways to contribute to Pelican. You can improve the "
"documentation, add missing features, and fix bugs (or just report them). "
"You can also help out by reviewing and commenting on `existing issues "
"<https://github.com/getpelican/pelican/issues>`_."
msgstr ""
"有很多渠道可以参与到贡献项目中来例如帮助改进文档、添加缺失的特性、修复与报告bug。可以从查看 `已有 issues "
"<https://github.com/getpelican/pelican/issues>`_ 开始。"
#: ../../contribute.rst:9 103b2f2862c4469695e4c6aff2321a8d
msgid ""
"Don't hesitate to fork Pelican and submit an issue or pull request on "
"GitHub. When doing so, please consider the following guidelines."
msgstr "随时随地都可以fork Pelican或是在GitHub上提交issue或PR。"
#: ../../../CONTRIBUTING.rst:2 5ad44a6fdf0b45eaaa800023139694f8
msgid "Filing issues"
msgstr "提出issue"
#: ../../../CONTRIBUTING.rst:4 c7e2bb966f49419aba7ed7027a977043
msgid "Before you submit a new issue, try `asking for help`_ first."
msgstr "在你提交一个新的issue之前可以先尝试 `请求他人帮助`_ 。"
#: ../../../CONTRIBUTING.rst:5 a287bb06699b4db79d6dd7491bbe031b
msgid ""
"If determined to create a new issue, first search `Pelican Discussions`_ "
"and `existing issues`_ (open and closed) to see if your question has "
"already been answered previously."
msgstr ""
"当你决定要提出新的issue时先在 `Pelican的讨论版`_ 和 `已有issues`_ "
"中搜索一下开放关闭的issue都搜一下来看看你的问题是不是有人之前已经提出过。"
#: ../../../CONTRIBUTING.rst:14 d4a600f2338b458e822aba90e54d4cfd
msgid "How to get help"
msgstr "如何获取帮助"
#: ../../../CONTRIBUTING.rst:16 db3264afde384c2891d9be7205578556
msgid "Before you ask for help, please make sure you do the following:"
msgstr "在寻求帮助之前,请先尝试如下步骤:"
#: ../../../CONTRIBUTING.rst:18 3581147764244a548cd2898faaa7799a
msgid ""
"Read the documentation_ thoroughly. If in a hurry, at least use the "
"search field that is provided at top-left on the documentation_ pages. "
"Make sure you read the docs for the Pelican version you are using."
msgstr ""
"完整阅读 documentation_ 。如果你很急,至少先在 documentation_ "
"左上角的搜索栏中尝试搜索。确保你阅读的文档和使用的Pelican版本相匹配。"
#: ../../../CONTRIBUTING.rst:21 d8e467909ec64ba7900da93b3765bfa6
msgid ""
"Use a search engine (e.g., DuckDuckGo, Google) to search for a solution "
"to your problem. Someone may have already found a solution, perhaps in "
"the form of a ':pelican-doc:`plugins` or a specific combination of "
"settings."
msgstr ""
"使用搜索引擎(例如 DuckDuckGo、Google搜索遇到问题的解决方案。互联网上可能已经有人遇到过相同的问题解决方法可能包括使用某些 "
":pelican-doc:`plugins` 或配置一系列的设置选项。"
#: ../../../CONTRIBUTING.rst:25 2011839b36504c41b307cc9f817c4a46
msgid "Try reproducing the issue in a clean environment, ensuring you are using:"
msgstr "尝试在一个尽可能简单的环境中重现问题,并确保以下几点:"
#: ../../../CONTRIBUTING.rst:27 2d64217ea3e54dc58a371fc11a6ece8e
msgid ""
"latest Pelican release (or an up-to-date Git clone of Pelican ``main`` "
"branch)"
msgstr "使用最新版本的Pelican或是用Git克隆Pelican的main分支"
#: ../../../CONTRIBUTING.rst:28 721ca09c5a9a495b9fbb6aa86df8be28
msgid "latest releases of libraries used by Pelican"
msgstr "将Pelican使用的库升级到最新版本"
#: ../../../CONTRIBUTING.rst:29 bbe722bd2be748219d38c134f29569dd
msgid "no plugins or only those related to the issue"
msgstr "此环境中没有使用插件或是只使用和问题相关的插件"
#: ../../../CONTRIBUTING.rst:31 e9f337f01ca546be93bd1d18884a1685
msgid ""
"**NOTE:** The most common sources of problems are anomalies in (1) "
"themes, (2) plugins, (3) settings files, and (4) ``make``/``invoke`` "
"automation wrappers. If you can't reproduce your problem when using the "
"following steps to generate your site, then the problem is almost "
"certainly with one of the above-listed elements (and not Pelican "
"itself)::"
msgstr ""
"**注意:** 最常见的问题基本上都产生于主题、插件、设置文件和自动化工具 ``make``/``invoke`` "
"中。如果按照下述步骤生成站点后无法复现之前的问题那么几乎可以肯定问题出在这四个地方而不在Pelican本身"
#: ../../../CONTRIBUTING.rst:41 1420bb3dd096480289b3da1534d7bf64
msgid ""
"If you can generate your site without problems using the steps above, "
"then your problem is unlikely to be caused by Pelican itself, and "
"therefore please consider reaching out to the maintainers of the "
"plugins/theme you are using instead of raising the topic with the Pelican"
" core community."
msgstr "如果按照上述步骤能够正常生成站点那么你的问题不太可能是由Pelican本身导致的请考虑联系对应插件/主题的维护者而不是在Pelican内核的社区中提出问题。"
#: ../../../CONTRIBUTING.rst:46 bdb7575fa4c74c0891fd686794cc84fd
msgid ""
"If despite the above efforts you still cannot resolve your problem, be "
"sure to include in your inquiry the following information, preferably in "
"the form of links to content uploaded to a `paste service`_, GitHub "
"repository, or other publicly-accessible location:"
msgstr ""
"经过上面这些努力,若您仍无法解决问题,确保你的提问中包括如下信息,可以以 `paste service`_ "
"链接、GitHub仓库或者其他可公开获取的形式提供"
#: ../../../CONTRIBUTING.rst:51 b559dc6ca72649baa754cb14d1ac77ca
msgid ""
"Describe what version of Pelican you are running (output of ``pelican "
"--version`` or the HEAD commit hash if you cloned the repo) and how "
"exactly you installed it (the full command you used, e.g. ``python -m pip"
" install pelican``)."
msgstr ""
"描述正在运行的Pelican版本信息可以通过 ``pelican --version`` 命令得到如果clone的源仓库则可以查看HEAD "
"commit的哈希值以及你是如何安装Pelican的要包括使用到的命令例如 ``python -m pip install "
"pelican``"
#: ../../../CONTRIBUTING.rst:54 d09a0393a4c1462b878c1adf31a7537d
msgid ""
"If you are looking for a way to get some end result, prepare a detailed "
"description of what the end result should look like (preferably in the "
"form of an image or a mock-up page) and explain in detail what you have "
"done so far to achieve it."
msgstr "如果你希望产生某种特定的最终结果,请详细描述此最终结果是什么样的(最好以图片或者伪页面的形式),,并且细致讲述你做了哪些尝试。"
#: ../../../CONTRIBUTING.rst:58 720ee9dbccc74dccbabb994a2d36638d
msgid ""
"If you are trying to solve some issue, prepare a detailed description of "
"how to reproduce the problem. If the issue cannot be easily reproduced, "
"it cannot be debugged by developers or volunteers. Describe only the "
"**minimum steps** necessary to reproduce it (no extra plugins, etc.)."
msgstr ""
"如果你在尝试解决某些问题,请详细描述如何复现此问题。如果问题很难被复现,其他开发者和志愿者就很难进行调试。尽量只写出复现该问题的 **最少步骤**"
" (无额外插件)。"
#: ../../../CONTRIBUTING.rst:62 34bdc49c617643d8ae7adb6a433a88fe
msgid ""
"Upload your settings file or any other custom code that would enable "
"people to reproduce the problem or to see what you have already tried to "
"achieve the desired end result."
msgstr "上传你的配置文件以及所有自定义过的代码,这可以使得大家能够重现问题或者看到你已经做出的尝试。"
#: ../../../CONTRIBUTING.rst:65 03c88e23c7b54117aa69e003c8bbef6e
msgid ""
"Upload detailed and **complete** output logs and backtraces (remember to "
"add the ``--debug`` flag: ``pelican --debug content [...]``)"
msgstr ""
"上传详细 **完整** 的输出日志以及backtraces信息记得在执行pelican命令时加上 ``--debug`` 标记: "
"``pelican --debug content [...]`` "
#: ../../../CONTRIBUTING.rst:71 953240a12cd64be7b9375a4571193314
msgid ""
"Once the above preparation is ready, you can post your query as a new "
"thread in `Pelican Discussions`_. Remember to include all the information"
" you prepared."
msgstr "一旦做好了上述准备,就可以在 `Pelican Discussions`_ 中发起你的问题了。记得在请求中附上收集好的信息。"
#: ../../../CONTRIBUTING.rst:75 e9f48bdfc6c744f282c70da3ac581052
msgid "Contributing code"
msgstr "贡献代码"
#: ../../../CONTRIBUTING.rst:77 888be6bde2de42a49705f29443a519c1
msgid ""
"Before you submit a contribution, please ask whether it is desired so "
"that you don't spend a lot of time working on something that would be "
"rejected for a known reason. Consider also whether your new feature might"
" be better suited as a ':pelican-doc:`plugins` — you can `ask for help`_"
" to make that determination."
msgstr ""
"在提交代码修改前,请先询问是否需要此修改,以免你做的工作因为已知原因而被拒绝。想想要添加的新特性是否更适合以 :pelican-doc:`插件` "
"形式完成。可以通过 `如何获取帮助`_ 来帮助你作出决定。"
#: ../../../CONTRIBUTING.rst:82 6e1329bbd8354c30b8ffa07f18894d3f
msgid ""
"Also, if you intend to submit a pull request to address something for "
"which there is no existing issue, there is no need to create a new issue "
"and then immediately submit a pull request that closes it. You can submit"
" the pull request by itself."
msgstr "另外如果你的PR是为了解决一个目前没有在issue中出现过的问题那么就没有必要先创建一个新的issue而是可以直接提起PR。"
#: ../../../CONTRIBUTING.rst:87 bca476812a33487c98d6aa840820671b
msgid "Using Git and GitHub"
msgstr "使用Git与GitHub"
#: ../../../CONTRIBUTING.rst:89 51f8df6063a544baabf35ef3bae28e83
msgid ""
"`Create a new branch`_ specific to your change (as opposed to making your"
" commits in the ``main`` branch)."
msgstr "`创建一个新的分支`_ 来标记你做的修改(而不是直接在主分支中提交)。"
#: ../../../CONTRIBUTING.rst:91 6c419972402444d5976574902311e2d7
msgid ""
"**Don't put multiple unrelated fixes/features in the same branch / pull "
"request.** For example, if you're working on a new feature and find a "
"bugfix that doesn't *require* your new feature, **make a new distinct "
"branch and pull request** for the bugfix. Similarly, any proposed changes"
" to code style formatting should be in a completely separate pull "
"request."
msgstr ""
"**不要把多个无关联的修复/特性修改放在同一个分支/拉去请求中。** 如果当你在做新特性的时候发现了一个bug可以修复但修复这个bug "
"*不需要用到* 这个新特性, **那么请另外创建一个分支并拉取请求。** 类似的,任何对代码风格的格式化都应该在单独的请求中拉取。"
#: ../../../CONTRIBUTING.rst:96 ced35621749d426a8e39fdeb9b0f7c90
msgid ""
"Add a ``RELEASE.md`` file in the root of the project that contains the "
"release type (major, minor, patch) and a summary of the changes that will"
" be used as the release changelog entry. For example::"
msgstr ""
"在项目根目录下添加 ``RELEASE.md`` "
"文件在其中包含release的类型主要、次要、补丁以及对项目改变的概述这些内容会作为该release发布日志的一部分。下面是一个例子"
#: ../../../CONTRIBUTING.rst:104 ca6b2bf54f5248cbb7d90edb678478fc
msgid ""
"Check for unnecessary whitespace via ``git diff --check`` before "
"committing."
msgstr "在提交前使用 ``git diff --check`` 来检查是否有无意义的空白字符。"
#: ../../../CONTRIBUTING.rst:105 48776b48e4924398b7632b8f05141e78
msgid ""
"First line of your commit message should start with present-tense verb, "
"be 50 characters or less, and include the relevant issue number(s) if "
"applicable. *Example:* ``Ensure proper PLUGIN_PATH behavior. Refs #428.``"
" If the commit *completely fixes* an existing bug report, please use "
"``Fixes #585`` or ``Fix #585`` syntax (so the relevant issue is "
"automatically closed upon PR merge)."
msgstr ""
"commit信息的第一行应该以现在时动词开头并且第一行尽量保持在50字以下并且包含相关联issue的编号如果有的话。 例如: "
"``Ensure proper PLUGIN_PATH behavior. Refs #428.`` 如果此项提交 *完全修复* "
"了某项已报告的bug请使用例如 ``Fixes #585`` 或 ``Fix #585`` "
"的语法这样的话相关的issue会在PR合并后自动关闭。"
#: ../../../CONTRIBUTING.rst:110 75acb68d9eaa4230ae230f016bf77b6c
msgid ""
"After the first line of the commit message, add a blank line and then a "
"more detailed explanation (when relevant)."
msgstr "在第一行commit信息后添加一行空白行再进行更多相关的细节描述。"
#: ../../../CONTRIBUTING.rst:112 51e3a16f76364d91a9abf219c731ff80
msgid ""
"`Squash your commits`_ to eliminate merge commits and ensure a clean and "
"readable commit history."
msgstr "`压缩commit`_ 来消除合并commits确保你的commit历史记录是干净可读的。"
#: ../../../CONTRIBUTING.rst:114 01ddd9df01024d38a8de79122a91cc07
msgid ""
"After you have issued a pull request, the continuous integration (CI) "
"system will run the test suite on all supported Python versions and check"
" for code style compliance. If any of these checks fail, you should fix "
"them. (If tests fail on the CI system but seem to pass locally, ensure "
"that local test runs aren't skipping any tests.)"
msgstr "在你发出PR后持续集成CI系统会在所有支持的Python版本上运行测试套件并且检查代码风格的合规性。如果出现了错误你应该将其修复。如果没有通过CI系统上的测试但是本地测试通过了请再检查一下确保在本地进行了所有CI系统中的检查"
#: ../../../CONTRIBUTING.rst:121 bc27587df397410a9bb272f0851756a3
msgid "Contribution quality standards"
msgstr "贡献的质量标准"
#: ../../../CONTRIBUTING.rst:123 2cf100b3e98b43e5b841493887a1d8be
msgid ""
"Adhere to the project's code style standards. See: `Development "
"Environment`_"
msgstr "遵循项目的代码风格标准。详见 `开发环境`_"
#: ../../../CONTRIBUTING.rst:124 fffad000d6ca490291bd09cb18fcc75a
msgid ""
"Ensure your code is compatible with the `officially-supported Python "
"releases`_."
msgstr "确保你的代码可以兼容 `python的官方发布版本`_"
#: ../../../CONTRIBUTING.rst:125 907e4426cbc643fb9075e32be169ba42
msgid ""
"Add docs and tests for your changes. Undocumented and untested features "
"will not be accepted."
msgstr "请为你修改的内容添加文档与测试。未注有文档或没有对应测试的特性会被拒绝。"
#: ../../../CONTRIBUTING.rst:127 d2bcbeeb9c0541c2a5ac5ec589a16ca4
msgid ""
":pelican-doc:`Run all the tests <contribute>` **on all versions of Python"
" supported by Pelican** to ensure nothing was accidentally broken."
msgstr ""
"**在Pelican支持的所有Python版本上** :pelican-doc:`执行所有测试 <contribute>` "
",以确保没有意料之外的问题。"
#: ../../../CONTRIBUTING.rst:130 26daa76aea674039be278882a95422f5
msgid ""
"Check out our `Git Tips`_ page or `ask for help`_ if you need assistance "
"or have any questions about these guidelines."
msgstr "若需要帮助或对以上指南有任何疑惑,还可以查看我们的 `Git提示`_ 页面和 `请求帮助`_ 部分。"
#: ../../contribute.rst:15 b4a94275e9c14d8795fa54473ee2f05b
msgid "Setting up the development environment"
msgstr "配置开发环境"
#: ../../contribute.rst:17 a0eb6948883742d2a00665a576ef6aba
msgid ""
"While there are many ways to set up one's development environment, the "
"following instructions will utilize Pip_ and PDM_. These tools facilitate"
" managing virtual environments for separate Python projects that are "
"isolated from one another, so you can use different packages (and package"
" versions) for each."
msgstr ""
"在配置开发环境时往往有很多种方式,但下面的指南会使用 Pip_ 和 PDM_ "
"完成配置。这两个工具都可以用于管理虚拟环境使得不同的Python项目相互隔离这样就可以很方便的在不同的项目中使用不同的库以及不同的库版本。"
#: ../../contribute.rst:22 4c5c4d91e6964d709d01102e32310642
msgid "Please note that Python |min_python| is required for Pelican development."
msgstr "请注意要进行Pelican的开发至少需要Python |min_python|"
#: ../../contribute.rst:24 5419157e28984a618fc1f0df81deb620
msgid ""
"*(Optional)* If you prefer to `install PDM "
"<https://pdm.fming.dev/latest/#installation>`_ once for use with multiple"
" projects, you can install it via::"
msgstr ""
"*(可选)* 若您想要 `安装PDM <https://pdm.fming.dev/latest/#installation>`_ "
",可以使用下面这条命令:"
#: ../../contribute.rst:29 a9d08dc294cb4857a58d2c63eae98a15
msgid ""
"Point your web browser to the `Pelican repository`_ and tap the **Fork** "
"button at top-right. Then clone the source for your fork and add the "
"upstream project as a Git remote::"
msgstr ""
"在Web浏览器中进入 `Pelican的代码仓库`_ ,点击右上角的 **Fork** "
"按钮。然后克隆你自己的这份fork最后添加项目的原仓库为远程仓库upstream"
#: ../../contribute.rst:38 4c8ebbf9839441ca9364eeb1d25b180f
msgid ""
"While PDM can dynamically create and manage virtual environments, we're "
"going to manually create and activate a virtual environment::"
msgstr "通过下面的命令可以手动创建并激活一个虚拟环境:"
#: ../../contribute.rst:45 ../../contribute.rst:186
#: 2afe046c20814fe5b3de9a65606505f1 6ec60e6a37b642edb68af7ed1bc82c0b
msgid "Install the needed dependencies and set up the project::"
msgstr "安装必需的依赖并配置项目:"
#: ../../contribute.rst:50 59d5dabaab1d409c8873187e5664fe67
msgid "Your local environment should now be ready to go!"
msgstr "现在,你的本地开发环境就配置完成了!"
#: ../../contribute.rst:57 6fdce76f8ec64275b24366ff03cc6340
msgid "Development"
msgstr "开发"
#: ../../contribute.rst:59 1d1a814a5dba40bcb84ce824d6312805
msgid ""
"Once Pelican has been set up for local development, create a topic branch"
" for your bug fix or feature::"
msgstr "在配置好Pelican的本地开发环境后请先为你的bug修复或特性增加创建一个分支"
#: ../../contribute.rst:64 773cdd3a48894e11a62cb24b25ef4829
msgid ""
"Now you can make changes to Pelican, its documentation, and/or other "
"aspects of the project."
msgstr "在切换到新建的分支后就可以开始对Pelican的文档或其他内容做更改了。"
#: ../../contribute.rst:68 bb120553218b4d0699998fbaf00d32c0
msgid "Setting up ``git blame`` (optional)"
msgstr "配置 ``git blame`` (可选)"
#: ../../contribute.rst:70 644fae63e5ea4e66a24e35a7ada3524c
msgid ""
"``git blame`` annotates lines in a file with information about the pull "
"request that last modified it. Sweeping shallow changes (like formatting)"
" can make that information less useful, so we keep a list of such changes"
" to be ignored. Run the following command to set this up in your "
"repository, adding ``--global`` if you want this setting to apply to all "
"repositories::"
msgstr ""
"``git blame`` "
"会在文件中的行上标注有关最后一次修改该行的PR信息。对浅层变化如格式化进行批量更改可能会使这些信息变得不那么有用因此我们维护一个包含此类更改的列表以便忽略它们。运行以下命令在您的存储库中设置此配置如果希望此设置适用于所有存储库请添加"
" ``--global`` "
#: ../../contribute.rst:78 68b7031047e94e03b0e1b0ea39d0355e
msgid ""
"As noted in a `useful article`_ about ``git blame``, there are other "
"related settings you may find to be beneficial::"
msgstr "就像在 `这篇文章`_ 中提到的,还可以进行一些可能有用的额外设置:"
#: ../../contribute.rst:89 c33fd6178fb044dda7073f1fc2cce979
msgid "Running the test suite"
msgstr "运行测试套件"
#: ../../contribute.rst:91 5b51e49bc1ca42c6916c4dceed476057
msgid ""
"Each time you make changes to Pelican, there are two things to do "
"regarding tests: check that the existing tests pass, and add tests for "
"any new features or bug fixes. The tests are located in "
"``pelican/tests``, and you can run them via::"
msgstr ""
"每次对Pelican做出修改后在测试方面需要做两个工作检查是否能通过已有的测试、为新增特性或bug修复创建测试。请将自动化测试文件放在 "
"``pelican/tests`` 中,接着执行以下命令:"
#: ../../contribute.rst:98 0e03b29d89cc408e9374cb51f7147611
msgid ""
"(For more on Invoke, see ``invoke -l`` to list tasks, or "
"https://pyinvoke.org for documentation.)"
msgstr "(执行 ``invoke -l`` 会列出可以调用的测试任务,关于此的更多文档请参阅 https://pyinvoke.org "
#: ../../contribute.rst:101 70aad8c721c64d2b8d32488dd9da851e
msgid ""
"In addition to running the test suite, it is important to also ensure "
"that any lines you changed conform to code style guidelines. You can "
"check that via::"
msgstr "除了运行测试套件外,还要确保修改了的部分遵循代码风格指南。可以通过下面的命令检查代码风格:"
#: ../../contribute.rst:106 ../../contribute.rst:200
#: b0ff008dde5e4e0b892e0fc2fa959b6a
msgid ""
"If style violations are found, many of them can be addressed "
"automatically via::"
msgstr "若存在不合规范风格的代码,大多数情况下可以通过下述命令自动纠正:"
#: ../../contribute.rst:111 ebad1e2cb63a45d999d2d3e510711972
msgid ""
"If code style violations are found in lines you changed, correct those "
"lines and re-run the ``invoke lint`` command until they have all been "
"fixed. You do not need to address style violations, if any, for code "
"lines you did not touch."
msgstr "如果在修改过的代码中有地方违反了代码风格规范,请纠正并再次运行上述命令,直到全部纠正。但是若是发现违反代码风格的地方并不是你修改的,请忽略之,不要进行纠正。"
#: ../../contribute.rst:115 e208ada16ab8425e9fbbcd5f135f6574
msgid ""
"After making your changes and running the tests, you may see a test "
"failure mentioning that \"some generated files differ from the expected "
"functional tests output.\" If you have made changes that affect the HTML "
"output generated by Pelican, and the changes to that output are expected "
"and deemed correct given the nature of your changes, then you should "
"update the output used by the functional tests. To do so, **make sure you"
" have both** ``en_EN.utf8`` **and** ``fr_FR.utf8`` **locales installed**,"
" and then run the following command::"
msgstr ""
"在修改完代码运行测试的过程中你可能会看到测试失败中有提到“some generated files differ from the "
"expected functional tests output” "
"。这可能是由于你对代码的修改影响到了Pelican的HTML输出若输出的结果确实是你想要的请更新功能测试所用的输出用例。请确保你安装了 "
"``en_EN.utf8`` 和 ``fr_FR.utf8`` ,然后执行下述命令:"
#: ../../contribute.rst:125 a4a3e16c3e0345c99cb2d8b674627afa
msgid ""
"You may also find that some tests are skipped because some dependency "
"(e.g., Pandoc) is not installed. This does not automatically mean that "
"these tests have passed; you should at least verify that any skipped "
"tests are not affected by your changes."
msgstr "你还可能会发现有一些测试由于缺少依赖(例如 Pandoc而被跳过。这并不意味着通过了这些测试请至少确保对代码的修改不会影响到这些被跳过的测试。"
#: ../../contribute.rst:130 dd6db784c2534b0ea0842cb736dca7c3
msgid ""
"You should run the test suite under each of the supported versions of "
"Python. This is best done by creating a separate Python environment for "
"each version. Tox_ is a useful tool to automate running tests inside "
"``virtualenv`` environments."
msgstr ""
"你应该在Pelican支持的所有Python版本下运行测试套件。一般会通过为每一个Python版本创建一个虚拟环境来实现这一点。Tox_ "
"是一个用于在 ``virtualenv`` 环境中自动运行测试的工具。"
#: ../../contribute.rst:138 58fd644b4b7248ebb9c8ff899a2f90b1
msgid "Running a code coverage report"
msgstr "运行代码测试覆盖报告"
#: ../../contribute.rst:140 abe50ab68fef48dea42aa269743fc172
msgid ""
"Code is more likely to stay robust if it is tested. Coverage_ is a "
"library that measures how much of the code is tested. To run it::"
msgstr "经过测试的代码往往具有更好的健壮性。 Coverage_ 是一个用于衡量代码测试覆盖率的库执行下面的命令以调取之:"
#: ../../contribute.rst:145 9d5ba28c240f464c92db9869c01e3917
msgid ""
"This will show overall coverage, coverage per file, and even line-by-line"
" coverage. There is also an HTML report available::"
msgstr "该命令会展示总体覆盖率以及在每个文件上的覆盖率甚至还会展示每一行的覆盖情况。同样也会有一份HTML格式的报告供您查看"
#: ../../contribute.rst:153 45e095f0c0fd4a5b9f75027d12dd891f
msgid "Building the docs"
msgstr "构建文档"
#: ../../contribute.rst:155 e1e8bb56a9c8449a8da8e10fcf45da2a
msgid ""
"If you make changes to the documentation, you should build and inspect "
"your changes before committing them::"
msgstr "若你对文档进行过修改请在commit前完成构建和检查"
#: ../../contribute.rst:160 9482dc5bee484f0c9f05af197b49ed70
msgid ""
"Open http://localhost:8000 in your browser to review the documentation. "
"While the above task is running, any changes you make and save to the "
"documentation should automatically appear in the browser, as it live-"
"reloads when it detects changes to the documentation source files."
msgstr ""
"执行上述命令后请在Web浏览器中打开 http://localhost:8000 "
"来查看文档。在上述命令执行时,对文档做的任何修改应该会自动反映在浏览器中。"
#: ../../contribute.rst:166 82343c9684bb440eb260110d98bb0e59
msgid "Plugin development"
msgstr "插件开发"
#: ../../contribute.rst:168 8697f547344e4973ad34f9c619ddf22e
msgid ""
"To create a *new* Pelican plugin, please refer to the `plugin template`_ "
"repository for detailed instructions."
msgstr "要创建一个 *新的* Pelican插件请参阅 `插件模板`_ 仓库以获得更为详细的指导。"
#: ../../contribute.rst:171 3c505e3035c143c89efd3e648fe00e8e
msgid ""
"If you want to contribute to an *existing* Pelican plugin, follow the "
"steps above to set up Pelican for local development, and then create a "
"directory to store cloned plugin repositories::"
msgstr "若你想在 *已有* Pelican插件中做贡献请先按前文所述步骤配置Pelican的本地开发环境然后创建一个文件夹来存放克隆下来的插件仓库"
#: ../../contribute.rst:177 5523421ea2664b1ab0859216a1c8a463
msgid ""
"Assuming you wanted to contribute to the Simple Footnotes plugin, you "
"would first browse to the `Simple Footnotes`_ repository on GitHub and "
"tap the **Fork** button at top-right. Then clone the source for your fork"
" and add the upstream project as a Git remote::"
msgstr ""
"假设想要为Simple Footnotes插件做贡献你应该先查看并fork `Simple Footnotes`_ "
"的Github仓库然后克隆你自己fork的那一份再添加原仓库作为Git远程仓库upstream"
#: ../../contribute.rst:190 e5178eb4654a44919c743d37f00ff4c3
msgid "Create a topic branch for your plugin bug fix or feature::"
msgstr "同样地为你想要进行的bug修复或特性添加创建一个分支"
#: ../../contribute.rst:194 af04dad9f528473caa4c4c0f4c33042a
msgid ""
"After writing new tests for your plugin changes, run the plugin test "
"suite and check for code style compliance via::"
msgstr "完成修改并添加测试后,运行测试套件,并检查代码风格:"
#: ../../contribute.rst:205 06d00f61d5c344d587baa85116b3c1e0
msgid ""
"If style violations are found even after running the above auto-"
"formatters, you will need to make additional manual changes until "
"``invoke lint`` no longer reports any code style violations."
msgstr "如果在自动格式化后仍存在代码风格上的问题,请手动修正这些问题,直到执行 ``invoke lint`` 时不再报告问题。"
#: ../../contribute.rst:213 9a0831b06abd494fad469b7df71c489f
msgid "Submitting your changes"
msgstr "提交更改"
#: ../../contribute.rst:215 23b5d147059b4cea99a213f50d63097a
msgid ""
"Assuming linting validation and tests pass, add a ``RELEASE.md`` file in "
"the root of the project that contains the release type (major, minor, "
"patch) and a summary of the changes that will be used as the release "
"changelog entry. For example::"
msgstr ""
"通过了风格检查和所有测试后,请在项目的根目录下添加一个 ``RELEASE.md`` "
"文件其中应包含发布的类型major、minor、patch以及代码变更的摘要这份摘要会被用作更新日志的条目。下面是一个例子"
#: ../../contribute.rst:224 6794c41ebe2c4937ba4f3f8e16e7a9d9
msgid "Commit your changes and push your topic branch::"
msgstr "commit你的更改并push对应分支"
#: ../../contribute.rst:230 daa69b097fc14739be924714f8070cf6
msgid ""
"Finally, browse to your repository fork on GitHub and submit a pull "
"request."
msgstr "最后前往Github从你fork的仓库向原仓库提出PR。"
#: ../../contribute.rst:234 b71524be74c84517a12fcdecb51bc55e
msgid "Logging tips"
msgstr "日志技巧"
#: ../../contribute.rst:236 a0b70f864ce144eabe0f89d78844c395
msgid "Try to use logging with appropriate levels."
msgstr "请仔细斟酌合适的日志等级。"
#: ../../contribute.rst:238 3b44fa3ec9b3493e97c310207e5dce91
msgid "For logging messages that are not repeated, use the usual Python way::"
msgstr "对于不重复的日志消息,使用一般的方式即可:"
#: ../../contribute.rst:247 49d4e407310348838660e8c74c6e3fb6
#, python-format
msgid ""
"Do not format log messages yourself. Use ``%s`` formatting in messages "
"and pass arguments to logger. This is important, because the Pelican "
"logger will preprocess some arguments, such as exceptions."
msgstr ""
"请不要自己格式化日志消息,而是使用在日志消息中使用 ``%s`` "
"并向logger传入参数。请务必遵循这一规则因为Pelican的logger会自动预处理一些特殊的参数例如exception。"
#: ../../contribute.rst:252 4ac501dff8bc4554998d3f03486cce0e
msgid "Limiting extraneous log messages"
msgstr "限制低关联日志消息"
#: ../../contribute.rst:254 c4dfb487945341cda6c0858954a2ed40
msgid ""
"If the log message can occur several times, you may want to limit the log"
" to prevent flooding. In order to do that, use the ``extra`` keyword "
"argument for the logging message in the following format::"
msgstr "如果同一日志消息会重复多次,你会希望限制这些多余的内容。使用 ``extra`` 命名参数来实现这一点:"
#: ../../contribute.rst:261 4090a3bc71e3441e8a7efd639d36ec1e
msgid ""
"Optionally, you can also set ``'limit_args'`` as a tuple of arguments in "
"``extra`` dict if your generic message needs formatting."
msgstr "可选的,如果通用日志消息需要格式化,可以添加 ``'limit_args'`` 参数并将其对应值设为一个元组。"
#: ../../contribute.rst:264 dd6530ceb29d4a91902046a3d4e63af6
msgid ""
"Limit is set to ``5``, i.e, first four logs with the same ``'limit_msg'``"
" are outputted normally but the fifth one will be logged using "
"``'limit_msg'`` (and ``'limit_args'`` if present). After the fifth, "
"corresponding log messages will be ignored."
msgstr ""
"限制数默认设为了 ``5`` ,即前四个有相同 ``'limit_msg'`` 参数的日志消息会正常输出,但第五条这样的日志消息会呈现为 "
"``'limit_msg'`` 参数值本身( ``'limit_args'`` 同理)。第六条及之后的日志消息会被直接忽略。"
#: ../../contribute.rst:269 50bdb3405a964740aeb91a7d559ba9b5
msgid ""
"For example, if you want to log missing resources, use the following "
"code::"
msgstr "例如,如果你想要用日志记录资源缺失的信息,可以使用下面的代码:"
#: ../../contribute.rst:277 0303387eccd842f9aa57eb3192252dba
msgid "The log messages will be displayed as follows::"
msgstr "最终的日志消息看起来会像这样:"
#: ../../contribute.rst:287 281637c4520d4755993e8bfa46b0326b
msgid "Outputting traceback in the logs"
msgstr "在日志中输出traceback信息"
#: ../../contribute.rst:289 8bd9319a7a6c4f77bd651057d1cc7c75
msgid ""
"If you're logging inside an ``except`` block, you may want to provide the"
" traceback information as well. You can do that by setting ``exc_info`` "
"keyword argument to ``True`` during logging. However, doing so by default"
" can be undesired because tracebacks are long and can be confusing to "
"regular users. Try to limit them to ``--debug`` mode like the following::"
msgstr ""
"当在 ``except`` 块中进行日志记录时你可能会希望同时输出traceback信息。可以简单地将 ``exc_info`` 参数设为 "
"``True`` 来实现这一功能。但是通过此方法输出的traceback信息会非常长不便于理解。可以像下述代码一样将这些信息限制在 "
"``--debug`` 模式中:"
#~ msgid "latest Pelican release (or an up-to-date Git clone of Pelican master)"
#~ msgstr ""
#~ msgid ""
#~ "`Create a new branch`_ specific to "
#~ "your change (as opposed to making "
#~ "your commits in the master branch)."
#~ msgstr ""

View file

@ -0,0 +1,484 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-07 16:25+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.16.0\n"
#: ../../faq.rst:2 84467b3ab4b8411589855b3130e14406
msgid "Frequently Asked Questions (FAQ)"
msgstr "常见问题解答"
#: ../../faq.rst:4 54c28b1640fd4939b5f196fa377292eb
msgid "Here are some frequently asked questions about Pelican."
msgstr "以下是一些Pelican的常见问题解答。"
#: ../../faq.rst:7 a95f8f3dcb6741949ba9d4761199dd0a
msgid "What's the best way to communicate a problem, question, or suggestion?"
msgstr "交流问题、疑问或提建议的最佳方式是什么?"
#: ../../faq.rst:9 d93f8424407d42b2b3ce37b39baecd8a
msgid "Please read our :doc:`feedback guidelines <contribute>`."
msgstr "请参阅文档 :doc:`项目贡献与意见反馈 <contribute>` 。"
#: ../../faq.rst:12 9fea72b4670c4fe6a3d67e1ddb158f47
msgid "How can I help?"
msgstr "我可以帮上什么忙?"
#: ../../faq.rst:14 3f4b88cf5b814e678a552c821ae4b450
msgid ""
"There are several ways to help out. First, you can communicate any "
"Pelican suggestions or problems you might have via `Pelican Discussions "
"<https://github.com/getpelican/pelican/discussions>`_. Please first check"
" the existing list of discussions and issues (both open and closed) in "
"order to avoid submitting topics that have already been covered before."
msgstr ""
"有好多种方法可以提供帮助。首先,可以在 `Pelican讨论板块 "
"<https://github.com/getpelican/pelican/discussions>`_ "
"中提出任何关于Pelican的建议或是问题。在提问或建议之前请先查看已关闭或开放的issues中是否已有相关内容以避免内容上的重复。"
#: ../../faq.rst:20 ca9e66682caf43a481ca91ecace43ed0
msgid ""
"If you want to contribute, please fork `the Git repository "
"<https://github.com/getpelican/pelican/>`_, create a new feature branch, "
"make your changes, and issue a pull request. Someone will review your "
"changes as soon as possible. Please refer to the :doc:`How to Contribute "
"<contribute>` section for more details."
msgstr ""
"如果你想要对项目进行贡献请fork `Git仓库 <https://github.com/getpelican/pelican/>`_ "
"创建一个新的功能分支并在其中进行修改在修改完成后提出一个PR。项目组会尽快审核你的PR。关于此的更多内容请参见 "
":doc:`项目贡献与意见反馈 <contribute>` 一节。"
#: ../../faq.rst:26 f05e9b722b084a439cd6d99b3155910d
msgid ""
"You can also contribute by creating themes and improving the "
"documentation."
msgstr "你可以发起的贡献当然也包括创建主题和改进文档。"
#: ../../faq.rst:29 d40c58aeafe54bdaa389c3c05a0fd721
msgid "Is the Pelican settings file mandatory?"
msgstr "Pelican配置文件是必要的吗"
#: ../../faq.rst:31 96ef0c57471d4a669bd7f2a7f493c23b
msgid ""
"Configuration files are optional and are just an easy way to configure "
"Pelican. For basic operations, it's possible to specify options while "
"invoking Pelican via the command line. See ``pelican --help`` for more "
"information."
msgstr ""
"配置文件是可选的其本质是使您可以更方便地配置Pelican。对于一些基本的配置操作完全可以在命令行中指定调用 ``pelican "
"--help`` 可以查看pelican命令的更多信息。"
#: ../../faq.rst:36 e3752aec18514ce292ee4ebd0d95db37
msgid "Changes to the settings file take no effect"
msgstr "修改后的配置文件没有生效"
#: ../../faq.rst:38 3f5c632fd20446cf8dd70a5eb88dbbcf
msgid ""
"When experimenting with different settings (especially the metadata ones)"
" caching may interfere and the changes may not be visible. In such cases,"
" ensure that caching is disabled via ``LOAD_CONTENT_CACHE = False`` or "
"use the ``--ignore-cache`` command-line switch."
msgstr ""
"在尝试不同的配置时(尤其是尝试不同元数据时),缓存很可能会产生干扰,使得修改不可见。此时,确保配置了 ``LOAD_CONTENT_CACHE ="
" False`` 或在命令行中加上 ``--ignore-cache`` 以禁用缓存。"
#: ../../faq.rst:44 067892211d0d4f4bae85d65a0132eb1d
msgid "I'm creating my own theme. How do I use Pygments for syntax highlighting?"
msgstr "在自己创建主题时如何使用Pygments来调整语法高亮"
#: ../../faq.rst:46 b1e6ed1bea2e4b3cb3798131f30a828c
msgid ""
"Pygments adds some classes to the generated content. These classes are "
"used by themes to style code syntax highlighting via CSS. Specifically, "
"you can customize the appearance of your syntax highlighting via the "
"``.highlight pre`` class in your theme's CSS file. To see how various "
"styles can be used to render Django code, for example, use the style "
"selector drop-down at top-right on the `Pygments project demo site "
"<https://pygments.org/demo/>`_."
msgstr ""
"Pygments会为生成的内容添加一些CSS类。这些类会为主题所用主题会通过CSS来为代码添加语法高亮。具体来说你可以通过主题CSS文件中的 "
"``.highlight pre`` 类来自定义语法高亮的外观。在 `Pygments 项目的demo网站 "
"<https://pygments.org/demo/>`_ 上可以预览能够渲染的代码类型。"
#: ../../faq.rst:53 5dccc8ae367545b08bdce61e008e0a20
msgid ""
"You can use the following example commands to generate a starting CSS "
"file from a Pygments built-in style (in this case, \"monokai\") and then "
"copy the generated CSS file to your new theme::"
msgstr "你可以使用下面的命令来让Pygments使用内置风格此处为“monokai”生成一个初始CSS文件然后将此文件拷贝到新主题中"
#: ../../faq.rst:60 027edae1ebdf4d52b59171a26915c1ac
msgid "Don't forget to import your ``pygment.css`` file from your main CSS file."
msgstr "不要忘了在你的CSS主文件中引入 ``pygment.css`` 文件。"
#: ../../faq.rst:63 164af3be4dce45879963c5d3ee0cd264
msgid "How do I create my own theme?"
msgstr "如何创建我自己的主题?"
#: ../../faq.rst:65 7b1db6528b0a4735894868a229a5969d
msgid "Please refer to :ref:`theming-pelican`."
msgstr "请参阅 :ref:`theming-pelican` 。"
#: ../../faq.rst:68 b8e21f837e0744c49cfe8f0cb3a1d5ee
msgid "Can I override individual templates without forking the whole theme?"
msgstr "我只需要覆盖主题中单独的几个模板文件可不可以不fork整个主题"
#: ../../faq.rst:70 70fd7b5c55c246a6a25b20304bfdb616
msgid ""
"Yes, you can override existing templates of the theme that you are using,"
" or add new templates, via the ``THEME_TEMPLATES_OVERRIDES`` variable. "
"For example, to override the page template, you can define the location "
"for your templates like this::"
msgstr "当然可以,覆盖部分模板文件或是添加一些模板文件都是可以的,使用 ``THEME_TEMPLATES_OVERRIDES`` 变量即可。"
"例如若需要覆盖page的模板可以向这样定义你自己的模板文件位置"
#: ../../faq.rst:77 a96870f0cad74996bec2469ea0c2e9e1
msgid ""
"You can then define a custom template in ``templates/page.html``. See "
":ref:`settings/themes` for details."
msgstr "自定义的模板可以为 ``templates/page.html`` 。详情请参看 :ref:`settings/themes` 。"
#: ../../faq.rst:81 b832cd952cf44a0097f383825f0f295f
msgid "I want to use Markdown, but I got an error."
msgstr "我想要使用Markdown但是出错了。"
#: ../../faq.rst:83 32d9dbde7029412d852ab8e710112573
msgid ""
"If you try to generate Markdown content without first installing the "
"Markdown library, you may see a message that says ``No valid files found "
"in content``. Markdown is not a hard dependency for Pelican, so if you "
"have content in Markdown format, you will need to explicitly install the "
"Markdown library. You can do so by typing the following command, "
"prepending ``sudo`` if permissions require it::"
msgstr ""
"如果没有事先安装Markdown库在生成Markdown内容时会看到一条提示 ``No valid files found in "
"content`` "
"。虽然Markdown并不是必需依赖但如果你写的内容中含有Markdown格式就需要安装Markdown库了。输入下面的命令以安装Markdown库如果需要权限请在前面添加"
" ``sudo`` "
#: ../../faq.rst:93 46728a367ffe47d9afeb7608e9c0db5f
msgid "Can I use arbitrary metadata in my templates?"
msgstr "在模板中可以使用任意元数据吗?"
#: ../../faq.rst:95 9b7fbafc6d29429a88a079bfb74e3af5
msgid ""
"Yes. For example, to include a modified date in a Markdown post, one "
"could include the following at the top of the article::"
msgstr "当然可以。例如可以在Markdown帖子中包含一个“修改日期”加在文章开头即可"
#: ../../faq.rst:100 ce62442a4c9d4347bd6ae8a59476fcee
msgid ""
"For reStructuredText, this metadata should of course be prefixed with a "
"colon::"
msgstr "对于reStructuredText此元数据也应当以冒号为前缀"
#: ../../faq.rst:104 bf869a6da43e448a9cc512843aa4a183
msgid ""
"This metadata can then be accessed in templates such as ``article.html`` "
"via::"
msgstr "此元数据可以在模板中获取到,例如在 ``article.html`` 中,可以像这样获取:"
#: ../../faq.rst:110 b9c9a648b30942b996b124af9fd5a84c
msgid ""
"If you want to include metadata in templates outside the article context "
"(e.g., ``base.html``), the ``if`` statement should instead be::"
msgstr "如果您想在其他模板(例如 ``base.html`` )中获取此元数据,则 ``if`` 语句应改为:"
#: ../../faq.rst:116 b78a678a165d40f4823fac2b19bcafc1
msgid ""
"How do I make my output folder structure identical to my content "
"hierarchy?"
msgstr "如何使得输出目录的结构和content目录的结构保持一致"
#: ../../faq.rst:118 851d1019c070482991667cc024063d29
msgid "Try these settings::"
msgstr "可以尝试如下配置:"
#: ../../faq.rst:125 5195876e3f364a838d72b16c568263bc
msgid "How do I assign custom templates on a per-page basis?"
msgstr "如何为某个页面指定某个模板?"
#: ../../faq.rst:127 2ddd3cf1fbf048b1819bcfc9b3691a12
msgid ""
"It's as simple as adding an extra line of metadata to any page or article"
" that you want to have its own template. For example, this is how it "
"would be handled for content in reST format::"
msgstr "这非常简单在任何页面或者文章中都可以通过多添加一行元数据来指定特定模板。例如在reST中使用"
#: ../../faq.rst:133 6f5eb40b4a5e4f83ab9d1cb48fefad57
msgid "For content in Markdown format::"
msgstr "对于Markdown则使用"
#: ../../faq.rst:137 2e28d1bf074c437eb5017bf6f345bf71
msgid ""
"Then just make sure your theme contains the relevant template file (e.g. "
"``template_name.html``). If you just want to add a new custom template to"
" an existing theme, you can also provide it in a directory specified by "
"``THEME_TEMPLATES_OVERRIDES`` (see :ref:`settings/themes`)."
msgstr ""
#: ../../faq.rst:142 675e77f99f3c42bb8715c84a97c7a064
msgid "How can I override the generated URL of a specific page or article?"
msgstr "如何重写某一个页面或文章生成的URL"
#: ../../faq.rst:144 7e518b99b29d4787addc732d57e94ed1
msgid ""
"Include ``url`` and ``save_as`` metadata in any pages or articles that "
"you want to override the generated URL. Here is an example page in reST "
"format::"
msgstr "在任意页面或文章中都可以添加 ``url`` 和 ``save_as`` 元数据这样就可以重写URL了。下面以reST格式为例"
#: ../../faq.rst:153 903306ecaed3483591b4ed2dcba3d183
msgid ""
"With this metadata, the page will be written to "
"``override/url/index.html`` and Pelican will use the URL "
"``override/url/`` to link to this page."
msgstr ""
"有了这样的元数据,此页面会保存为 ``override/url/index.html`` Pelican会将 ``override/url/``"
" 作为链接到此页面的URL。"
#: ../../faq.rst:157 d80d84fcb6844e25a8452e29c4113181
msgid "How can I use a static page as my home page?"
msgstr "如何使用一个静态页面作为主页?"
#: ../../faq.rst:159 e17a2e2dd9014109888bab9286ee607c
msgid ""
"The override feature mentioned above can be used to specify a static page"
" as your home page. The following Markdown example could be stored in "
"``content/pages/home.md``::"
msgstr "上一个问题中提到的特性可以用于实现此需求。下面例子中的Markdown文件保存为 ``content/pages/home.md`` "
#: ../../faq.rst:169 b99ba0ca8656416cbdc38f3fa263b7eb
msgid ""
"If the original blog index is still wanted, it can then be saved in a "
"different location by setting ``INDEX_SAVE_AS = 'blog_index.html'`` for "
"the ``'index'`` direct template."
msgstr ""
"如果仍需要原来的博客主页(即 ``'index'`` 直接模板),可以通过设置 ``INDEX_SAVE_AS = "
"'blog_index.html'`` 将其存储在其他位置。"
#: ../../faq.rst:174 fca4725a57dd451fb3b0fb9df78f69b5
msgid "What if I want to disable feed generation?"
msgstr "可以禁用订阅源生成吗?"
#: ../../faq.rst:176 e9c08140e2ed44f189a7a156db027a3e
msgid ""
"To disable feed generation, all feed settings should be set to ``None``. "
"All but three feed settings already default to ``None``, so if you want "
"to disable all feed generation, you only need to specify the following "
"settings::"
msgstr ""
"要禁用订阅源,所有订阅源相关的配置都应被设为 ``None`` 。其中有三项设置默认为 ``None`` "
",因此如果要彻底不生成订阅源,你只需要指定下面这些设置:"
#: ../../faq.rst:186 7820a481af4c4f44a40fb3ae80768a1d
msgid ""
"The word ``None`` should not be surrounded by quotes. Please note that "
"``None`` and ``''`` are not the same thing."
msgstr "``None`` 两侧不需要加引号。请注意 ``None`` 和 ``''`` 不是同一个东西。"
#: ../../faq.rst:190 4fa2ffbf1c274ec396a0d756762c260d
msgid ""
"I'm getting a warning about feeds generated without SITEURL being set "
"properly"
msgstr "Pelican警告说由于SITEURL设置不正确无法正常生成订阅源"
#: ../../faq.rst:192 8d52f14f6b03476897dfb15c188a961a
msgid ""
"`RSS and Atom feeds require all URL links to be absolute "
"<https://validator.w3.org/feed/docs/rss2.html#comments>`_. In order to "
"properly generate links in Pelican you will need to set ``SITEURL`` to "
"the full path of your site."
msgstr ""
"`RSS和Atom订阅源要求所有URL都要链接到绝对地址 "
"<https://validator.w3.org/feed/docs/rss2.html#comments>`_ "
"。为了使得Pelican能正确生成链接你需要将站点的 ``SITEURL`` 设置为完整路径。"
#: ../../faq.rst:197 1412ceb735d44a30b58db3241248e7ec
msgid ""
"Feeds are still generated when this warning is displayed, but links "
"within may be malformed and thus the feed may not validate."
msgstr "虽然Pelican提出了警告但是仍会生成订阅源但其中的链接可能是无效的这会导致订阅源不可用。"
#: ../../faq.rst:201 20cadccc527e4ebda08eac9ed34f5055
msgid "Can I force Atom feeds to show only summaries instead of article content?"
msgstr "可以让Atom订阅源只显示摘要不显示文章内容吗"
#: ../../faq.rst:203 9c45ba2ec5c6402e86e89661b943d1ad
msgid ""
"Instead of having to open a separate browser window to read articles, the"
" overwhelming majority of folks who use feed readers prefer to read "
"content within the feed reader itself. Mainly for that reason, Pelican "
"does not support restricting Atom feeds to only contain summaries. Unlike"
" Atom feeds, the RSS feed specification does not include a separate "
"``content`` field, so by default Pelican publishes RSS feeds that only "
"contain summaries (but can optionally be set to instead publish full "
"content RSS feeds). So the default feed generation behavior provides "
"users with a choice: subscribe to Atom feeds for full content or to RSS "
"feeds for just the summaries."
msgstr ""
"绝大多数使用订阅源阅读器的人都更喜欢直接在阅读器中阅读文章内容而不是另外再打开窗口来阅读。因此Pelican不支持使Atom只包含摘要。但是由于RSS不包含单独的"
" ``content`` "
"字段因此Pelican在发布RSS时默认只包含摘要当然也可以设置为包含文章内容。Pelican在订阅源生成上的如此行为就可以让用户自行选择订阅类型包含了完整内容的Atom或是只包含摘要的RSS。"
#: ../../faq.rst:214 bf0d4ca837f74d9ab6618db6306c6a70
msgid "Is Pelican only suitable for blogs?"
msgstr "Pelican只适合用于博客吗"
#: ../../faq.rst:216 49697f375cfc49b08f5d0c2297d15028
msgid ""
"No. Pelican can be easily configured to create and maintain any type of "
"static site. This may require a little customization of your theme and "
"Pelican configuration. For example, if you are building a launch site for"
" your product and do not need tags on your site, you could remove the "
"relevant HTML code from your theme. You can also disable generation of "
"tag-related pages via::"
msgstr "不是的。Pelican可以方便地用于创建维护任何静态站点为此你需要对主题和配置做一些定制。例如如果要为你的产品构建一个宣传网站即不需要使用标签特性从主题中移除与标签相关的HTML代码即可。另外还可以通过下面的设置来禁用标签相关页面的生成"
#: ../../faq.rst:226 0a59dd7209554237912579b362d07788
msgid ""
"Why does Pelican always write all HTML files even with content caching "
"enabled?"
msgstr "启用内容缓存后为什么Pelican仍会每次都写入所有HTML文件"
#: ../../faq.rst:228 6291b82d02fc4450a79d1200b5d04f62
msgid ""
"In order to reliably determine whether the HTML output is different "
"before writing it, a large part of the generation environment including "
"the template contexts, imported plugins, etc. would have to be saved and "
"compared, at least in the form of a hash (which would require special "
"handling of unhashable types), because of all the possible combinations "
"of plugins, pagination, etc. which may change in many different ways. "
"This would require a lot more processing time and memory and storage "
"space. Simply writing the files each time is a lot faster and a lot more "
"reliable."
msgstr "为了确定HTML输出确实和之前的不同模板上下文、插件等很多生成环境都需要保存并比较某种哈希值对于不可哈希的内容类型还需要进行一些额外处理。另外由于插件、分页等内容的存在输出的HTML很可能会与之前不同。因此考虑到处理时间和存储空间每次都重新写入全部HTML会更快更可靠。"
#: ../../faq.rst:237 5cc5e1361f914c92b0670030f0c83f5d
msgid ""
"However, this means that the modification time of the files changes every"
" time, so a ``rsync`` based upload will transfer them even if their "
"content hasn't changed. A simple solution is to make ``rsync`` use the "
"``--checksum`` option, which will make it compare the file checksums in a"
" much faster way than Pelican would."
msgstr ""
"然而,这样的机制会使得在每次生成站点后,文件的修改时间都会变化,因此基于 ``rsync`` "
"上传时会把没有变化的内容也进行上传。一个简便的解决方法就是给 ``rsync`` 加上 ``--checksum`` "
"选项这会比Pelican在生成时进行校验更快。"
#: ../../faq.rst:244 b24c40be89b94f3b980cbbda38d46115
msgid "How to process only a subset of all articles?"
msgstr "如何只处理一部分文章?"
#: ../../faq.rst:246 fa34a90481f44ace83ee16401543ce09
msgid ""
"It is often useful to process only e.g. 10 articles for debugging "
"purposes. This can be achieved by explicitly specifying only the "
"filenames of those articles in ``ARTICLE_PATHS``. A list of such "
"filenames could be found using a command similar to ``cd content; find "
"-name '*.md' | head -n 10``."
msgstr ""
"简便起见,在调试时可能只需要处理几篇文章。可以直接在配置项 ``ARTICLE_PATHS`` 中添加需要处理文章的文件名。可以通过像 ``cd "
"content; find -name '*.md' | head -n 10`` 这样的命令获取文章文件名的列表。"
#: ../../faq.rst:252 0fa566e3aa084cb9b04e0cee32684222
msgid "My tag cloud is missing/broken since I upgraded Pelican"
msgstr "在升级Pelican后标签云消失或不可用了"
#: ../../faq.rst:254 0bd1304a12c24f048b227c68391b148c
msgid ""
"In an ongoing effort to streamline Pelican, tag cloud generation has been"
" moved out of Pelican core and into a separate `plugin "
"<https://github.com/pelican-plugins/tag-cloud>`_. See the :ref:`plugins` "
"documentation for further information about the Pelican plugin system."
msgstr ""
"我们一直致力于精简Pelican标签云生成的功能已经从Pelican核心中移除转而放到了一个单独的 `tag-cloud插件 "
"<https://github.com/pelican-plugins/tag-cloud>`_ 中。查看 :ref:`plugins` "
"文档获取更多关于Pelican插件系统的信息。"
#: ../../faq.rst:260 1833dfba94c74f4bb9e9f0a112ed3e0f
msgid "Since I upgraded Pelican my pages are no longer rendered"
msgstr "升级Pelican后一些页面没有被渲染"
#: ../../faq.rst:262 576e5c2338ba4c43a51bb562301ad0c2
msgid ""
"Pages were available to themes as lowercase ``pages`` and uppercase "
"``PAGES``. To bring this inline with the :ref:`templates-variables` "
"section, ``PAGES`` has been removed. This is quickly resolved by updating"
" your theme to iterate over ``pages`` instead of ``PAGES``. Just "
"replace::"
msgstr ""
"在以前的版本中,主题通过小写的 ``pages`` 和大写的 ``PAGES`` 都能获取到页面。为了使之与 :ref:`templates-"
"variables` 一节中的内容保持一致,大写的 ``PAGES`` 被删除了。只要将主题中的 ``PAGES`` 替换为 ``pages`` "
",问题即可解决。例如将原先的:"
#: ../../faq.rst:269 355512b9f6b34ece9b6baed128b2ca4d
msgid "with something like::"
msgstr "替换为:"
#: ../../faq.rst:274 99ef769943fe41c4a37ca951e905b2ba
msgid "How can I stop Pelican from trying to parse my static files as content?"
msgstr "如何避免让Pelican将我的静态文件解析为内容文件译者注例如要将一个HTML文件作为静态文件"
#: ../../faq.rst:276 4efb20c5b82d41afb07151599fa189dd
msgid ""
"Pelican's article and page generators run before it's static generator. "
"That means if you use a setup similar to the default configuration, where"
" a static source directory is defined inside a ``*_PATHS`` setting, all "
"files that have a valid content file ending (``.html``, ``.rst``, "
"``.md``, ...) will be treated as articles or pages before they get "
"treated as static files."
msgstr ""
"Pelican的文章与页面生成器会先于静态文件生成器运行。这意味着若使用默认配置即静态资源文件夹定义在某个 ``*_PATHS`` "
"配置项中,所有以有效内容文件后缀结尾的文件( ``.html`` 、 ``.rst`` 、 ``.md`` "
"等)都会被视为文章或者页面,而不是静态文件。"
#: ../../faq.rst:282 d959eb6a67fe440caa70105e1692bf93
msgid ""
"To circumvent this issue either use the appropriate ``*_EXCLUDES`` "
"setting or disable the offending reader via ``READERS`` if you don't need"
" it."
msgstr ""
"为了避免这个问题,使用合适的 ``*_EXCLUDES`` 配置,在必要时还可以通过 ``READERS`` "
"配置项来直接禁用产生问题的reader。"
#: ../../faq.rst:286 5e64dc4b6fad4e7ea07278f5a2529e89
msgid "Why is [arbitrary Markdown syntax] not supported?"
msgstr "为什么不是所有的Markdown语法都支持"
#: ../../faq.rst:288 6872a70ec1434c41a78d465271761c69
msgid ""
"Pelican does not directly handle Markdown processing and instead "
"delegates that task to the Python-Markdown_ project, the core of which "
"purposefully follows the original Markdown syntax rules and not the "
"myriad Markdown \"flavors\" that have subsequently propagated. That said,"
" Python-Markdown_ is quite modular, and the syntax you are looking for "
"may be provided by one of the many available `Markdown Extensions`_. "
"Alternatively, some folks have created Pelican plugins that support "
"Markdown variants, so that may be your best choice if there is a "
"particular variant you want to use when writing your content."
msgstr ""
"Pelican并不直接对Markdown进行处理而是将此任务交给 Python-Markdown_ "
"项目此项目的核心有意只遵循原始的Markdown语法规则而不服从之后传播开的大量Markdown风格。另外 Python-Markdown_"
" 是相当模块化的,你想要使用的语法可能已经有现成的 `Markdown扩展`_ "
"进行了实现。或者也有人创建了支持Markdown变体的Pelican插件如果你想要用某种Markdown变体可以在这些地方寻找支持。"
#~ msgid ""
#~ "Then just make sure your theme "
#~ "contains the relevant template file "
#~ "(e.g. ``template_name.html``)."
#~ msgstr "确保对应的模板文件在主题中存在即可(例如 ``template_name.html`` )。"

View file

@ -0,0 +1,321 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../importer.rst:4 2e58a5582f664ba0af49aac4480bc799
msgid "Importing an existing site"
msgstr "导入已有站点"
#: ../../importer.rst:7 5182de0b717543c7a4813491755b720a
msgid "Description"
msgstr "简介"
#: ../../importer.rst:9 29a8bae0ba78486894ed4c286cd2f3b4
msgid ""
"``pelican-import`` is a command-line tool for converting articles from "
"other software to reStructuredText or Markdown. The supported import "
"formats are:"
msgstr ""
"命令行工具 ``pelican-import`` 用于将其他软件生成的文章转换成reStructuredText"
"或Markdown格式。支持导入下面这些格式"
#: ../../importer.rst:12 c670f6055ad24d818132d74951c9928c
msgid "Blogger XML export"
msgstr "Blogger XML export"
#: ../../importer.rst:13 d31ddaa8c7d54a268b379f706164de39
msgid "Dotclear export"
msgstr "Dotclear export"
#: ../../importer.rst:14 5102eb70c58240b2ad4d508a196b176e
msgid "Medium export"
msgstr "Medium export"
#: ../../importer.rst:15 2cfcdf575387417bae3a9938aa55b0e6
msgid "Tumblr API"
msgstr "Tumblr API"
#: ../../importer.rst:16 42233d68a4bc46339b284681bdbdd19c
msgid "WordPress XML export"
msgstr "WordPress XML export"
#: ../../importer.rst:17 0170dad08a80435b99a39ccaf887c5bb
msgid "RSS/Atom feed"
msgstr "RSS/Atom feed"
#: ../../importer.rst:19 077a8220f4a84dd297ec5aa7cff15a24
msgid ""
"The conversion from HTML to reStructuredText or Markdown relies on "
"`Pandoc`_. For Dotclear, if the source posts are written with Markdown "
"syntax, they will not be converted (as Pelican also supports Markdown)."
msgstr ""
"从HTML转换到reStructuredText或Markdown是依赖 `Pandoc`_ "
"完成的。对于Dotclear若原帖子是由Markdown语法写的则无需转换"
"因为Pelican本就支持Markdown。"
#: ../../importer.rst:25 e9b94b6029204b82b009d3ef23c19814
msgid ""
"Unlike Pelican, Wordpress supports multiple categories per article. These"
" are imported as a comma-separated string. You have to resolve these "
"manually, or use a plugin such as `More Categories`_ that enables "
"multiple categories per article."
msgstr ""
"和Pelican不同在Wordpress中可以将一篇文章同时放在多个分类中。在导入时各个分类"
"会以逗号分隔,你必须自己手动进行处理。或者也可以使用例如 `More Categories`_ "
"这样的插件,使得文章可以同时存在于多个分类中。"
#: ../../importer.rst:32 f7add19b68754b6e8a617a1d50dee759
msgid ""
"Imported pages may contain links to images that still point to the "
"original site. So you might want to download those images into your local"
" content and manually re-link them from the relevant pages of your site."
msgstr ""
"要导入的内容中可能会包含指向原站点的图片链接,你可能希望将他们全部下载下来,然后再"
"重新手动调整这些链接。"
#: ../../importer.rst:37 22cc1a514c4f42efbcf9afc3d987c42e
msgid "Dependencies"
msgstr "依赖"
#: ../../importer.rst:39 6139199770a24fc7af7ca7e556d18d5f
msgid ""
"``pelican-import`` has some dependencies not required by the rest of "
"Pelican:"
msgstr ""
"``pelican-import`` 需要用到一些其他依赖,这些依赖只会被 ``pelican-import`` 用到:"
#: ../../importer.rst:41 0e8eb04bb07f4752880b873e73e7f7e5
msgid ""
"*BeautifulSoup4* and *lxml*, for WordPress and Dotclear import. Can be "
"installed like any other Python package (``pip install BeautifulSoup4 "
"lxml``)."
msgstr ""
"为了能够导入WordPress和Dotclear的内容需要 *BeautifulSoup4* 与 *lxml* 。"
"安装方法与其他Python包相同 ``pip install BeautifulSoup4 lxml`` "
#: ../../importer.rst:44 7d31c1ad4ecb4014a3ef240436b9b3e1
msgid "*Feedparser*, for feed import (``pip install feedparser``)."
msgstr "为了能够导入订阅源,需要 *Feedparser* ``pip install feedparser`` "
#: ../../importer.rst:45 db7a18b1a4534a17956c9d030dddff56
msgid ""
"*Pandoc*, see the `Pandoc site`_ for installation instructions on your "
"operating system."
msgstr ""
"还需要 *Pandoc* ,参照 `Pandoc官方网站`_ 进行安装。"
#: ../../importer.rst:53 9952881aed104ef0ac82af5339e6b149
msgid "Usage"
msgstr "用法"
#: ../../importer.rst:63 83dbe43e4d2e4d8eaf3e37724ac119e3
msgid "Positional arguments"
msgstr "位置参数"
#: ../../importer.rst:65 4a12692744024752be75d82ed74d369d
msgid "``input``"
msgstr "``input``"
#: ../../importer.rst:65 52f62f22221f4c3d964df5aced3d2a2b
msgid "The input file to read"
msgstr "需要读取的输入文件"
#: ../../importer.rst:66 acc46432d5c14ea8a5e27e6ec2b84d18
msgid "``api_key``"
msgstr "``api_key``"
#: ../../importer.rst:66 29dd358bf2fe49d8a218c56ca376f6a6
msgid ""
"(Tumblr only) api_key can be obtained from "
"https://www.tumblr.com/oauth/apps"
msgstr ""
"只会在Tumblr中用到从 https://www.tumblr.com/oauth/apps 中获取到的api_key"
#: ../../importer.rst:70 a81b90d51a9f4c28adc09038715cf5c2
msgid "Optional arguments"
msgstr "可选参数"
#: ../../importer.rst:72 d4d5211b75aa4103b06ad7685368af06
msgid "Show this help message and exit"
msgstr "显示此帮助信息并退出 ``pelican-import`` "
#: ../../importer.rst:73 a7bae87fe16644f4b5da7d32fdc05f95
msgid "Blogger XML export (default: False)"
msgstr "输入是否为Blogger XML格式默认False"
#: ../../importer.rst:74 e8c133125ed04120bcc3737fa2a0ba60
msgid "Dotclear export (default: False)"
msgstr "输入是否为Dotclear格式默认False"
#: ../../importer.rst:75 caffd159f92a4f36aadedec398823ac3
msgid "Medium export (default: False)"
msgstr "输入是否为Medium格式默认False"
#: ../../importer.rst:76 f1bcaccf8e2f43f6894f2f0540c9d7ba
msgid "Tumblr API (default: False)"
msgstr "输入是否为Tumblr API格式默认False"
#: ../../importer.rst:77 6131f8fa00294515a028f4bb1a3a3053
msgid "WordPress XML export (default: False)"
msgstr "输入是否为WordPress XML格式默认False"
#: ../../importer.rst:78 dad00ee0aebb4550acae995ecdbb622f
msgid "Feed to parse (default: False)"
msgstr "输入是否为订阅源格式默认False"
#: ../../importer.rst:80 0ca3cbbc57c64b5b88444ccde94f94ce
msgid "Output path (default: content)"
msgstr "输出路径默认content"
#: ../../importer.rst:82 baa2762a4ee745028e29865720ca299d
msgid ""
"Output markup format: ``rst``, ``markdown``, or ``asciidoc`` (default: "
"``rst``)"
msgstr ""
"输出格式,可选值为: ``rst`` 、 ``markdown`` 、 ``asciidoc`` (默认: ``rst`` "
#: ../../importer.rst:84 53232a317a58422d8f070c245d3b7409
msgid "Put files in directories with categories name (default: False)"
msgstr "是否要将输出文件按分类名放到各文件夹中默认False"
#: ../../importer.rst:86 f72e1895d9fc4facb90ddffb53b31a0a
msgid ""
"Put files recognised as pages in \"pages/\" sub- directory (blogger and "
"wordpress import only) (default: False)"
msgstr ""
"将识别为页面的文件放入“pages/” 子文件夹中仅在blogger和wordpress中有用默认False"
#: ../../importer.rst:89 3f9315af4f1e4ced8ece96fca71cb1e7
msgid "Import only post from the specified author"
msgstr "仅导入某个作者的帖子"
#: ../../importer.rst:90 0b34125f0bb744b089fe77b86b3e50f7
msgid ""
"Strip raw HTML code that can't be converted to markup such as flash "
"embeds or iframes (default: False)"
msgstr ""
"删除无法转换的HTML代码例如嵌入的flash或iframe默认False"
#: ../../importer.rst:92 f899a119b708450bbd38913f813255c2
msgid ""
"Put wordpress custom post types in directories. If used with --dir-cat "
"option directories will be created as \"/post_type/category/\" (wordpress"
" import only)"
msgstr ""
"将wordpress中的自定义类型博文放到对应文件夹中。如果同时还使用了 --dir-cat 选项,"
"输出转换后文件时会创建诸如“/post_type/category/” 的文件夹只在wordpress中有效"
#: ../../importer.rst:95 627c041fab81460eafd4f5fe361bcd1a
msgid ""
"Download files uploaded to wordpress as attachments. Files will be added "
"to posts as a list in the post header and links to the files within the "
"post will be updated. All files will be downloaded, even if they aren't "
"associated with a post. Files will be downloaded with their original path"
" inside the output directory, e.g. \"output/wp-"
"uploads/date/postname/file.jpg\". (wordpress import only) (requires an "
"internet connection)"
msgstr ""
"下载作为附件上传到WordPress的文件。文件会以列表形式添加到帖子的开头并且到这些"
"文件的链接都会进行更新。另外,即使某些文件没有在任何帖子中用到,也同样会被下载。"
"文件会被下载到输出文件夹下,并保持原始路径,例如"
"“output/wp-uploads/date/postname/file.jpg” 。仅在wordpress中有效"
"且需要互联网连接)"
#: ../../importer.rst:104 11162d8c497b4108a38c2a60af4a4215
msgid ""
"Disable storing slugs from imported posts within output. With this "
"disabled, your Pelican URLs may not be consistent with your original "
"posts. (default: False)"
msgstr ""
"不保存导入推文的slug会导致Pelican的URL和原推文不一致。默认False"
#: ../../importer.rst:109 f4f4b6e918d3498e927b59c5d0bae05a
msgid "Blog name used in Tumblr API"
msgstr "Tumblr API中使用的博客名"
#: ../../importer.rst:113 16e0f9bd1c6e4b338673f1800e6a4995
msgid "Examples"
msgstr "例子"
#: ../../importer.rst:115 0cf17b9fd72940c391a1bb8bf7de534b
msgid "For Blogger::"
msgstr "导入Blogger"
#: ../../importer.rst:119 3fc79daf9e9e4f5ba1a121faaabd0c9e
msgid "For Dotclear::"
msgstr "导入Dotclear"
#: ../../importer.rst:123 328ff8145b464fa2ab59505a8bc3236a
msgid "For Medium::"
msgstr "导入Medium"
#: ../../importer.rst:127 8ca5f721833142249b6d798efcb77458
msgid ""
"The Medium export is a zip file. Unzip it, and point this tool to the "
"\"posts\" subdirectory. For more information on how to export, see "
"https://help.medium.com/hc/en-us/articles/115004745787-Export-your-"
"account-data."
msgstr ""
"Medium中导出的是一个zip文件。请先解压之然后再将其中的“posts”子目录传给此工具。 "
"https://help.medium.com/hc/en-us/articles/115004745787-Export-your-account-data "
"中有更详细的导出指导。"
#: ../../importer.rst:131 516a83a4d8cf4570a9a6fff416e5cf5a
msgid "For Tumblr::"
msgstr "导入Tumblr"
#: ../../importer.rst:135 8fcab620c0d44bb29a120d8d781f4daa
msgid "For WordPress::"
msgstr "导入WordPress"
#: ../../importer.rst:139 a929213eb21f4118b9adbb6199bd78ea
msgid "For Medium (an example of using an RSS feed):"
msgstr "导入Medium例子中使用了RSS订阅源"
#: ../../importer.rst:141 5e23c5d167ef4db1994f4323ac3d120e
msgid ""
"$ python -m pip install feedparser $ pelican-import --feed "
"https://medium.com/feed/@username"
msgstr ""
"$ python -m pip install feedparser $ pelican-import --feed "
"https://medium.com/feed/@username"
#: ../../importer.rst:146 b44dfe0f807049899c0560c6bf62c386
msgid "The RSS feed may only return the most recent posts — not all of them."
msgstr "RSS订阅源可能只会返回最新的帖子而不是所有帖子。"
#: ../../importer.rst:149 575426ff787d4647b3aa2469b8b52412
msgid "Tests"
msgstr "测试"
#: ../../importer.rst:151 036d2119412b41f3a3cb69cec74ecc81
msgid "To test the module, one can use sample files:"
msgstr "可以使用下面的文件作为样例进行测试:"
#: ../../importer.rst:153 482b30f9aab54717bb14218ae5fa8ea6
msgid ""
"for WordPress: https://www.wpbeginner.com/wp-themes/how-to-add-dummy-"
"content-for-theme-development-in-wordpress/"
msgstr ""
"WordPress https://www.wpbeginner.com/wp-themes/how-to-add-dummy-content-"
"for-theme-development-in-wordpress/"
#: ../../importer.rst:154 6cb1bd10d37e4993aabece8aaed20171
msgid "for Dotclear: http://media.dotaddict.org/tda/downloads/lorem-backup.txt"
msgstr "Dotclear http://media.dotaddict.org/tda/downloads/lorem-backup.txt"

View file

@ -0,0 +1,134 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../index.rst:2 160b5c32c524404ba295da4e89124739
msgid "Pelican |release|"
msgstr "Pelican |release|"
#: ../../index.rst:4 19170a80b4274f71b77062c7a6b90726
msgid ""
"Pelican is a static site generator, written in Python_. Highlights "
"include:"
msgstr ""
"Pelican是一个用 Python_ 写的静态站点生成器,它有诸多亮点:"
#: ../../index.rst:6 6ab42a346f2c46d789cd46655195f2d3
msgid ""
"Write your content directly with your editor of choice in "
"reStructuredText_ or Markdown_ formats"
msgstr ""
"你可以直接在自己的编辑器中用 reStructuredText_ 或 Markdown_ 完成内容创作"
#: ../../index.rst:8 dbd17888530e43ce8bdfc1594947032c
msgid "Includes a simple CLI tool to (re)generate your site"
msgstr "自带了一个简单的命令行工具,你可以用它来生成你的站点"
#: ../../index.rst:9 2bbe72bda8db457a88f3d3a94d16cc0c
msgid "Easy to interface with distributed version control systems and web hooks"
msgstr "易于与分布式版本控制系统和webhook交互"
#: ../../index.rst:10 24af69b083024f2a9c4f162d54fa57c6
msgid "Completely static output is easy to host anywhere"
msgstr "生成的站点是完全静态的,可以在任何主机上轻松地部署"
#: ../../index.rst:12 1e2090f3f19d49a19a6c50524e4cd0b7
msgid "Ready to get started? Check out the :doc:`Quickstart<quickstart>` guide."
msgstr "准备好开始体验了吗?请查看 :doc:`快速入门<quickstart>` 指南。"
#: ../../index.rst:15 481a352565e84c848e018de507fbe9af
msgid "Features"
msgstr "特性"
#: ../../index.rst:17 6c7b5d9b43ca42f1b1df139e7f884d26
msgid "Pelicans feature highlights include:"
msgstr "Pelican在特性上也有很多亮点"
#: ../../index.rst:19 464e5e8ea8324fab9c5496b317a6db97
msgid ""
"Articles (e.g., blog posts) and pages (e.g., \"About\", \"Projects\", "
"\"Contact\")"
msgstr ""
"可以生成文章(例如博客推文)和页面(例如“关于”、“联系我们”、“项目”)"
#: ../../index.rst:20 c7cc4fe6ea8145feb0ace7d0965e2634
msgid "Integration with external services"
msgstr "可以和外部服务集成"
#: ../../index.rst:21 ceb2c8a629024157946eba53638d7eb1
msgid "Site themes (created using Jinja2_ templates)"
msgstr "可以使用主题(主题使用 Jinja2_ 模板引擎创建)"
#: ../../index.rst:22 51c3defcba6c4d31a77c3aade6826f1a
msgid "Publication of articles in multiple languages"
msgstr "可以为同一篇文章发布多种语言版本"
#: ../../index.rst:23 6f7cbfae94c54318a904e9725ce73677
msgid "Generation of Atom and RSS feeds"
msgstr "可以生成Atom和Rss订阅源"
#: ../../index.rst:24 3d667d2ed98a489788f6c38a4e4a6752
msgid "Code syntax highlighting"
msgstr "可以渲染代码高亮"
#: ../../index.rst:25 bf1a1f91b821464182471a3760a59d4f
msgid "Import existing content from WordPress, Dotclear, or RSS feeds"
msgstr "可以从WordPress、Dotclear或Rss订阅源导入已有的内容"
#: ../../index.rst:26 bd82641c549645cb8b4cd3187800397c
msgid "Fast rebuild times thanks to content caching and selective output writing"
msgstr "得益于内容缓存和选择性生成设计,可以快速重新生成站点"
#: ../../index.rst:27 8dec47d1ab13410c9b99db0709c860a3
msgid "Extensible via a rich plugin ecosystem: `Pelican Plugins`_"
msgstr "可扩展性强,有丰富的插件生态: `Pelican Plugins`_"
#: ../../index.rst:30 c7e090d7d2e04ff1ac1844e56209d75b
msgid "Why the name \"Pelican\"?"
msgstr "为什么叫做“Pelican”"
#: ../../index.rst:32 8c31222af5e24ba69acb5dd07a5b5d56
msgid ""
"\"Pelican\" is an anagram for *calepin*, which means \"notebook\" in "
"French. ;)"
msgstr ""
"“Pelican”是法语词笔记本 *calepin* 读音的回文。;)"
#: ../../index.rst:35 188f72b2bb644f978180eba22009ebc6
msgid "Source code"
msgstr "源码"
#: ../../index.rst:37 2c8804f173fb4aa8973fb4d2413c263b
msgid "You can access the source code at: https://github.com/getpelican/pelican"
msgstr "在这里可以获取Pelican的源码 https://github.com/getpelican/pelican"
#: ../../index.rst:40 06ab21b7cde94cee92193199ddc69775
msgid "How to get help, contribute, or provide feedback"
msgstr "如何获取帮助、贡献内容或是提供反馈"
#: ../../index.rst:42 7fdcc2bcaac04317a6f4114f1d9c327f
msgid ""
"See our :doc:`feedback and contribution submission guidelines "
"<contribute>`."
msgstr ""
"请查看文档 :doc:`反馈意见和贡献的提交指南 <contribute>`。"
#: ../../index.rst:45 3d15499d76e1489d8e8782c65f73bb29
msgid "Documentation"
msgstr "文档"

View file

@ -0,0 +1,220 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-13 11:46+0800\n"
"PO-Revision-Date: 2024-06-25 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.17.0\n"
#: ../../install.rst:2 e735e1393d63466092c9fc0a5ee4117d
msgid "Installing Pelican"
msgstr "安装Pelican"
#: ../../install.rst:4 e34bdf7c1bbb4c75a47f8bd16e626c67
msgid ""
"Pelican currently runs best on |min_python|; earlier versions of Python "
"are not supported."
msgstr "Pelican需要 |min_python| 以上版本的Python不支持更低版本。"
#: ../../install.rst:6 ff98ade47da6403e84dd1b2209896d9c
msgid ""
"You can install Pelican via several different methods. The simplest is "
"via Pip_::"
msgstr "有多种方法可以安装Pelican最简单的就是通过 Pip_"
#: ../../install.rst:10 ae2fcb82534e4a3f81980f69ed94c9ad
msgid "Or, if you plan on using Markdown::"
msgstr "如果您需要使用Markdown请使用下面的命令安装"
#: ../../install.rst:14 ed597b1eb47949efba0f1781ef7bbd1f
msgid ""
"(Keep in mind that some operating systems will require you to prefix the "
"above command with ``sudo`` in order to install Pelican system-wide.)"
msgstr "(在某些操作系统中,需要在命令前加 ``sudo`` 才能在整个系统上安装Pelican"
#: ../../install.rst:17 04d6784f06dd40e7bff76bf6476aaba1
msgid ""
"While the above is the simplest method, the recommended approach is to "
"create a virtual environment for Pelican via virtualenv_ before "
"installing Pelican. Assuming you have virtualenv_ installed, you can then"
" open a new terminal session and create a new virtual environment for "
"Pelican::"
msgstr ""
"尽管上面是最简单的安装方法,但我们推荐使用虚拟环境 virtualenv_ 完成Pelican的安装。当您安装好 virtualenv_ "
"后打开一个新的命令行并为Pelican创建一个虚拟环境"
#: ../../install.rst:26 08aae819315e48a194a065a3fc3dddad
msgid ""
"Once the virtual environment has been created and activated, Pelican can "
"be installed via ``python -m pip install pelican`` as noted above. "
"Alternatively, if you have the project source, you can install Pelican "
"using the setuptools method::"
msgstr ""
"当创建并激活虚拟环境后,使用之前提到过的命令 ``python -m pip install pelican`` "
"就可以安装Pelican了。或者如果您想要从源码安装可以使用setuptools"
#: ../../install.rst:33 368febf14ca740e19fa470b0f832dea1
msgid ""
"If you have Git installed and prefer to install the latest bleeding-edge "
"version of Pelican rather than a stable release, use the following "
"command::"
msgstr "如果安装过Git并且您希望安装Pelican的最最新版本而不是稳定版请使用下面的命令"
#: ../../install.rst:38 2498d09099194317a62e67b907bdd5d3
msgid ""
"Once Pelican is installed, you can run ``pelican --help`` to see basic "
"usage options. For more detail, refer to the :doc:`Publish<publish>` "
"section."
msgstr ""
"当您安装好Pelican可以执行 ``pelican --help`` 命令来查看一些基本用法。在 :doc:`发布站点<publish>` "
"章节中可以了解更多信息。"
#: ../../install.rst:42 4ef93669753e4bb89252a8c9852e7a71
msgid "Optional packages"
msgstr "可选包"
#: ../../install.rst:44 190eabcd8f3a437cbf895ecee25aff4d
msgid ""
"If you plan on using `Markdown <https://pypi.org/project/Markdown/>`_ as "
"a markup format, you can install Pelican with Markdown support::"
msgstr ""
"如您希望使用 `Markdown <https://pypi.org/project/Markdown/>`_ "
"来写作执行下面的命令来安装Markdown支持"
#: ../../install.rst:49 fa8fc8ff397a412f839bc2805696aa45
msgid ""
"Typographical enhancements can be enabled in your settings file, but "
"first the requisite `Typogrify <https://pypi.org/project/typogrify/>`_ "
"library must be installed::"
msgstr ""
"Pelican还支持排版增强若您需要使用请先安装 `Typogrify "
"<https://pypi.org/project/typogrify/>`_ 库,稍后您可以在设置文件中启用它。"
#: ../../install.rst:56 74911273a6934154bad4fadbc0d1f28b
msgid "Dependencies"
msgstr "依赖"
#: ../../install.rst:58 77d44b11ae7e4945b119fd473bb53e67
msgid ""
"When Pelican is installed, the following dependent Python packages should"
" be automatically installed without any action on your part:"
msgstr "当Pelican安装完成后下面的所有Python依赖应该都会自动安装无需另外做任何操作"
#: ../../install.rst:61 22bdf13ed0a3482fb66f10486518261c
msgid ""
"`feedgenerator <https://pypi.org/project/feedgenerator/>`_, to generate "
"the Atom feeds"
msgstr "`feedgenerator <https://pypi.org/project/feedgenerator/>`_用于生成Atom feeds"
#: ../../install.rst:63 21ddc5ce3bed4f9cab2a454e8319a8c4
msgid "`jinja2 <https://pypi.org/project/Jinja2/>`_, for templating support"
msgstr "`jinja2 <https://pypi.org/project/Jinja2/>`_用于模板系统"
#: ../../install.rst:64 9302b2919a4f4de0927060911f69f5ed
msgid "`pygments <https://pypi.org/project/Pygments/>`_, for syntax highlighting"
msgstr "`pygments <https://pypi.org/project/Pygments/>`_用于语法高亮"
#: ../../install.rst:65 c6e45ac0f3ea4f91953fb2dfc66d29d9
msgid ""
"`docutils <https://pypi.org/project/docutils/>`_, for supporting "
"reStructuredText as an input format"
msgstr "`docutils <https://pypi.org/project/docutils/>`_用于reStructuredText格式"
#: ../../install.rst:67 aea17a424f3c4e8eab50172b6653fe16
msgid ""
"`blinker <https://pypi.org/project/blinker/>`_, an object-to-object and "
"broadcast signaling system"
msgstr "`blinker <https://pypi.org/project/blinker/>`_对象-对象的信号广播系统"
#: ../../install.rst:69 5da4c8d1fdf349c2afe23ffc9d832816
msgid ""
"`unidecode <https://pypi.org/project/Unidecode/>`_, for ASCII "
"transliterations of Unicode text utilities"
msgstr ""
"`unidecode "
"<https://pypi.org/project/Unidecode/>`_用于将Unicode文本转为ASCII字符的音译"
#: ../../install.rst:72 ff81051def5544e1b5d66532453aed25
msgid ""
"`MarkupSafe <https://pypi.org/project/MarkupSafe/>`_, for a markup-safe "
"string implementation"
msgstr "`MarkupSafe <https://pypi.org/project/MarkupSafe/>`_用于转义字符的安全处理"
#: ../../install.rst:74 0222b4cdfdcb48839f5f6b092071db99
msgid ""
"`python-dateutil <https://pypi.org/project/python-dateutil/>`_, to read "
"the date metadata"
msgstr ""
"`python-dateutil <https://pypi.org/project/python-"
"dateutil/>`_用于读取日期相关的元数据"
#: ../../install.rst:78 49117127302b49b39bd5b86abae18709
msgid "Upgrading"
msgstr "更新升级"
#: ../../install.rst:80 93962c7d303f4c9fa5ad9d43f86ea50a
msgid ""
"If you installed a stable Pelican release via Pip_ and wish to upgrade to"
" the latest stable release, you can do so by adding ``--upgrade``::"
msgstr "若是通过 Pip_ 安装了稳定版本的Pelican可以通过在安装命令中添加 ``--upgrade`` 来升级到最新版:"
#: ../../install.rst:85 1ac1fa009f9e4245ae7f975bda7d5a22
msgid ""
"If you installed Pelican via distutils or the bleeding-edge method, "
"simply perform the same step to install the most recent version."
msgstr "若是通过distutils安装或是通过Git安装了测试版的Pelican重新进行一遍和安装时同样的步骤即可。"
#: ../../install.rst:89 7845fa285f0b4dcd8e881c9edd61f80c
msgid "Kickstart your site"
msgstr "启动网站"
#: ../../install.rst:91 488ad84175cb45f6a6bb26cec24c1f10
msgid ""
"Once Pelican has been installed, you can create a skeleton project via "
"the ``pelican-quickstart`` command, which begins by asking some questions"
" about your site::"
msgstr ""
"Pelican安装完成后通过 ``pelican-quickstart`` "
"命令创建项目的整体框架,在运行这个命令时,您需要输入一些与站点相关的信息:"
#: ../../install.rst:97 63a773d35b91455b944206337e527a3a
msgid ""
"If run inside an activated virtual environment, ``pelican-quickstart`` "
"will look for an associated project path inside "
"``$VIRTUAL_ENV/.project``. If that file exists and contains a valid "
"directory path, the new Pelican project will be saved at that location. "
"Otherwise, the default is the current working directory. To set the new "
"project path on initial invocation, use: ``pelican-quickstart --path "
"/your/desired/directory``"
msgstr ""
"如果是在虚拟环境中执行 ``pelican-quickstart`` ,系统会自动在 ``$VIRTUAL_ENV/.project`` "
"目录中查找这个命令。若这个这个命令存在并且路径是正确的一个新的Pelican项目就会在目标位置创建。否则会默认在当前的工作目录下创建这个项目。若要在初始化时指定项目路径请使用"
" ``pelican-quickstart --path /your/desired/directory``。"
#: ../../install.rst:104 b7cdf15328074880bb4fc69dcb7bd26f
msgid ""
"Once you finish answering all the questions, your project will consist of"
" the following hierarchy (except for *pages* — shown in parentheses below"
" — which you can optionally add yourself if you plan to create non-"
"chronological content)::"
msgstr ""
"当您回答完所有问题后,项目就会成功创建。项目中会包含下述的一些层级结构(除了用括号括起来的 "
"*pages*。如果有一些内容不需要按时间排序您可以将它们放在pages所在的位置"
#: ../../install.rst:118 05e4fe3b0d0a4c998fba451692a68725
msgid ""
"The next step is to begin to adding content to the *content* folder that "
"has been created for you."
msgstr "接下来就可以开始往 *content* 目录中添加自己创作的内容了。"

View file

@ -0,0 +1,172 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../internals.rst:2 5d90a7c7f9dd42b5ba1fdfc05c5e9c3c
msgid "Pelican internals"
msgstr "Pelican内部机制"
#: ../../internals.rst:4 fa53597118244e8585b3b0a9fb4336c0
msgid ""
"This section describe how Pelican works internally. As you'll see, it's "
"quite simple, but a bit of documentation doesn't hurt. :)"
msgstr ""
"这一节描述了Pelican的内部运行机制。你会发现Pelican的内部其实并不复杂。 :)"
#: ../../internals.rst:7 c9a34db098f34796b80ee62896702be2
msgid ""
"You can also find in the :doc:`report` section an excerpt of a report the"
" original author wrote with some software design information."
msgstr "你可以在 :doc:`report` 一节中找到原作者用软件设计相关内容报告的节选。"
#: ../../internals.rst:13 ac2af84842574bef9a791b416e21834e
msgid "Overall structure"
msgstr "总体结构"
#: ../../internals.rst:15 fb7aea45b8f74c9c877bf2640d47aaac
msgid ""
"What Pelican does is take a list of files and process them into some sort"
" of output. Usually, the input files are reStructuredText and Markdown "
"files, and the output is a blog, but both input and output can be "
"anything you want."
msgstr ""
"Pelican做的事情其实很简单获取一个文件列表并将它们处理为某种输出。通常输入文件是"
"reStructuredText和Markdown文件输出是一个博客但事实上输入和输出都可以是你想要的"
"任何内容。"
#: ../../internals.rst:19 599649d1e9da4355ab02b50ea4fbdb19
msgid "The logic is separated into different classes and concepts:"
msgstr "系统的整体逻辑可以分为几个不同的类和概念:"
#: ../../internals.rst:21 8ec0821a726e4ade8046921cc09b3ea3
msgid ""
"**Writers** are responsible for writing files: .html files, RSS feeds, "
"and so on. Since those operations are commonly used, the object is "
"created once and then passed to the generators."
msgstr ""
"**Writers** 负责完成 html、RSS订阅源等等内容的文件写入。因为这些操作都是比较常用的"
"这个类只会被创建一次然后再传给Generators。"
#: ../../internals.rst:25 63c9a61869884147a8752e9be188e0e9
msgid ""
"**Readers** are used to read from various formats (HTML, Markdown and "
"reStructuredText for now, but the system is extensible). Given a file, "
"they return metadata (author, tags, category, etc.) and content (HTML-"
"formatted)."
msgstr ""
"**Readers** 用于读取不同格式的文件目前支持HTML、Markdown、reStructuredText"
"但可以继续扩展)。向**Readers**输入一个文件,它会返回文档的元数据(作者、标签、"
"分类等等与HTML格式的文档正文内容。"
#: ../../internals.rst:29 d9bc146ae213415b804cd93ebf43e340
msgid ""
"**Generators** generate the different outputs. For instance, Pelican "
"comes with ``ArticlesGenerator`` and ``PageGenerator``. Given a "
"configuration, they can do whatever they want. Most of the time, it's "
"generating files from inputs."
msgstr ""
"**Generators** 用以生成不同的输出Pelican自带了 ``ArticlesGenerator`` 和 "
"``PageGenerator`` 。给定一套配置信息, **Generators** 可以做几乎任何事。"
"但大多数情况下,它的工作就是从输入生成文件。"
#: ../../internals.rst:34 49ef39e8677a4529a3ee226faae1526b
msgid ""
"Pelican also uses templates, so it's easy to write your own theme. The "
"syntax is `Jinja2 <https://palletsprojects.com/p/jinja/>`_ and is very "
"easy to learn, so don't hesitate to jump in and build your own theme."
msgstr ""
"Pelican使用了模板引擎因此可以较为简单地编写自定义主题。模板语法使用的是易于学习的 "
"`Jinja2 <https://palletsprojects.com/p/jinja/>`_ ,因此快去构建你自己的主题吧。"
#: ../../internals.rst:39 1aef766f93d549afa332fad4278c4063
msgid "How to implement a new reader?"
msgstr "如何实现一个新的reader"
#: ../../internals.rst:41 abbbfc19ccea4e3ea3716179981e3c1d
msgid ""
"Is there an awesome markup language you want to add to Pelican? Well, the"
" only thing you have to do is to create a class with a ``read`` method "
"that returns HTML content and some metadata."
msgstr ""
"若是希望为Pelican添加一个标记语言只需要创建一个类实现 ``read`` 方法,并在其中"
"返回元数据和以HTML表示的正文内容。"
#: ../../internals.rst:45 1e9fc1bcc9444db4b751f1c621280a32
msgid "Take a look at the Markdown reader::"
msgstr "可以看一看Markdown的reader"
#: ../../internals.rst:71 cbc4f49384964be3a0a68b1083100839
msgid "Simple, isn't it?"
msgstr "是不是很简单呢?"
#: ../../internals.rst:73 02643c7e485d49e39344570ba5639a60
msgid ""
"If your new reader requires additional Python dependencies, then you "
"should wrap their ``import`` statements in a ``try...except`` block. "
"Then inside the reader's class, set the ``enabled`` class attribute to "
"mark import success or failure. This makes it possible for users to "
"continue using their favourite markup method without needing to install "
"modules for formats they don't use."
msgstr ""
"如果新创建的reader需要额外的Python依赖应该把 ``import`` 放在 ``try...except`` "
"块中。在reader类中设置类属性 ``enabled`` 来标记import是否成功。这使得用户能"
"继续使用他们喜欢的标记语言而无需安装用不到的模块。"
#: ../../internals.rst:80 02deeeac368b4dbc8c7b1025275d5bd5
msgid "How to implement a new generator?"
msgstr "如何实现一个新的generator"
#: ../../internals.rst:82 f7e5c28efbdb40c0bac7b985e8264310
msgid ""
"Generators have two important methods. You're not forced to create both; "
"only the existing ones will be called."
msgstr ""
"generator有两个重要方法。不一定两个都要创建若只创建了一个就会自动调用存在的方法。"
#: ../../internals.rst:85 01f2801461e043e7882167907e337d2c
msgid ""
"``generate_context``, that is called first, for all the generators. Do "
"whatever you have to do, and update the global context if needed. This "
"context is shared between all generators, and will be passed to the "
"templates. For instance, the ``PageGenerator`` ``generate_context`` "
"method finds all the pages, transforms them into objects, and populates "
"the context with them. Be careful *not* to output anything using this "
"context at this stage, as it is likely to change by the effect of other "
"generators."
msgstr ""
"``generate_context`` 会优先被调用,其中可以完成任何你想要做的事,如果需要的话,还要"
"更新全局上下文。全局上下文会在所有generator间共享并在之后传给模板。例如 "
"``PageGenerator`` 的 ``generate_context`` 方法会找寻所有页面,并将他们转换为对象,"
"再将上下文传入其中。注意,请 *不要* 在此阶段使用该上下文输出任何内容,因为其他"
"generator还会继续影响上下文。"
#: ../../internals.rst:93 3241d04af8944c48bf162963a774000c
msgid ""
"``generate_output`` is then called. And guess what is it made for? Oh, "
"generating the output. :) It's here that you may want to look at the "
"context and call the methods of the ``writer`` object that is passed as "
"the first argument of this function. In the ``PageGenerator`` example, "
"this method will look at all the pages recorded in the global context and"
" output a file on the disk (using the writer method ``write_file``) for "
"each page encountered."
msgstr ""
"``generate_output`` 会在 ``generate_context`` 之后被调用,用于生成要输出的内容。"
"此时就需要使用上下文并调用 ``writer`` 对象的方法,此 ``writer`` 就是传入 "
"``generate_output`` 方法的第一个参数。``PageGenerator`` 的 ``generate_output`` "
"方法中会使用writer的 ``write_file`` 方法为全局上下文中的每一个页面输出一个文件。"

View file

@ -0,0 +1,206 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../pelican-themes.rst:2 1fce54d5389b41f4a588e9b23b646aee
msgid "pelican-themes"
msgstr "pelican-themes"
#: ../../pelican-themes.rst:7 6158b329ed7b469286405115e2ed7fa0
msgid "Description"
msgstr "简介"
#: ../../pelican-themes.rst:9 3df74d6d079945f7a4e0062ed5ea3eed
msgid ""
"``pelican-themes`` is a command line tool for managing themes for "
"Pelican. See :ref:`settings/themes` for settings related to themes."
msgstr ""
"``pelican-themes`` 是一个命令行工具用于管理Pelican主题。有关主题的配置"
"请参考 :ref:`设置章节中的主题 <settings/themes>` 。"
#: ../../pelican-themes.rst:14 03eb76faf4544c8dbf478752096c7d7c
msgid "Usage"
msgstr "用法"
#: ../../pelican-themes.rst:16 d5dcdc6c26094f5695061f9c53633589
msgid "pelican-themes [-h] [-l] [-i theme path [theme path ...]]"
msgstr "pelican-themes [-h] [-l] [-i theme path [theme path ...]]"
#: ../../pelican-themes.rst:17 99b7a21ca612425da217b72b8c0c9b64
msgid "[-r theme name [theme name ...]]"
msgstr "[-r theme name [theme name ...]]"
#: ../../pelican-themes.rst:18 1f64db909173426dabee822aea3b269b
msgid "[-s theme path [theme path ...]] [-v] [--version]"
msgstr "[-s theme path [theme path ...]] [-v] [--version]"
#: ../../pelican-themes.rst:21 63ef4d44a1db4176b4c3866671a93603
msgid "Optional arguments:"
msgstr "可选参数:"
#: ../../pelican-themes.rst:24 348360945a0943ffa8122aad16bf0ec1
msgid "Show the help and exit"
msgstr "显示帮助信息并退出"
#: ../../pelican-themes.rst:26 aaec8d28264b45b7aac617b7140b5b13
msgid "Show the themes already installed"
msgstr "显示已安装的主题"
#: ../../pelican-themes.rst:28 c8d44b6ac6754f4e8e10a39848f042d0
msgid "One or more themes to install"
msgstr "安装一个或多个主题"
#: ../../pelican-themes.rst:30 18077fbf428e476aa218464fb0f18d8d
msgid "One or more themes to remove"
msgstr "移除一个或多个主题"
#: ../../pelican-themes.rst:32 e328d59886be45a6ae9530a0f2bea3ca
msgid ""
"Same as ``--install``, but create a symbolic link instead of copying the "
"theme. Useful for theme development"
msgstr ""
"和 ``--install`` 相同,区别在于此选项仅会创建一个符号链接到给定的目录,"
"而不会将主题完整拷贝。一般用于主题的开发"
#: ../../pelican-themes.rst:35 481c7a32a5e6400d83c9e2e56e6b94a4
msgid "Verbose output"
msgstr "开启详细输出"
#: ../../pelican-themes.rst:37 d7889dd20ac643ecad73e464ec4cfa55
msgid "Print the version of this script"
msgstr "显示此工具的版本信息"
#: ../../pelican-themes.rst:42 5c3d3aabd5304e8f9a6f0593824f1da6
msgid "Examples"
msgstr "例子"
#: ../../pelican-themes.rst:46 4d6ff63aae06482dbf22f41d4111b001
msgid "Listing the installed themes"
msgstr "列出已安装主题"
#: ../../pelican-themes.rst:48 91a9e942ea36479999586426afead753
msgid ""
"With ``pelican-themes``, you can see the available themes by using the "
"``-l`` or ``--list`` option:"
msgstr ""
"在 ``pelican-themes`` 中使用 ``-l`` 或 ``--list`` 选项,查看可用主题:"
#: ../../pelican-themes.rst:62 7a2f7dc98fcc45cabc4639576d503c28
msgid ""
"In this example, we can see there are three themes available: "
"``notmyidea``, ``simple``, and ``two-column``."
msgstr ""
"在上面的例子中,可以看到有三个主题可供使用: ``notmyidea`` 、 "
"``simple`` 、和 ``two-column`` 。"
#: ../../pelican-themes.rst:65 8c03dfa908114d92b8a9aeb6673555ce
msgid ""
"``two-column`` is followed by an ``@`` because this theme is not copied "
"to the Pelican theme path, but is instead just linked to it (see "
"`Creating symbolic links`_ for details about creating symbolic links)."
msgstr ""
"主题 ``two-column`` 后有一个 ``@`` 这是因为该主题没有被拷贝到Pelican的主题"
"路径下,而只是为其创建了一个符号链接 (详见 `创建符号链接`_ )。"
#: ../../pelican-themes.rst:69 bc91e8c3ff4a44dd9234d0ab186d8515
msgid ""
"Note that you can combine the ``--list`` option with the ``-v`` or "
"``--verbose`` option to get more verbose output, like this:"
msgstr ""
"当然,你可以将 ``--list`` 选项和 ``-v`` 或 ``--verbose`` 结合起来,从而"
"得到更详细的输出:"
#: ../../pelican-themes.rst:81 0b407ed71e6a4b428f5a582b58a47f3c
msgid "Installing themes"
msgstr "安装主题"
#: ../../pelican-themes.rst:83 e95f78a5c3b844b9a6fd2924f455748f
msgid ""
"You can install one or more themes using the ``-i`` or ``--install`` "
"option. This option takes as argument the path(s) of the theme(s) you "
"want to install, and can be combined with the ``--verbose`` option:"
msgstr ""
"使用 ``-i`` 或 ``--install`` 选项可以安装一个或多个主题。此选项将一个"
"或多个到达主题的路径作为参数,同样可以结合 ``--verbose`` 选项:"
#: ../../pelican-themes.rst:103 5b20e90396564e08860b2b3a569e7166
msgid "Removing themes"
msgstr "移除主题"
#: ../../pelican-themes.rst:105 2415bf89e3804c9dbdc34814b0132b8c
msgid ""
"The ``pelican-themes`` command can also remove themes from the Pelican "
"themes path. The ``-r`` or ``--remove`` option takes as argument the "
"name(s) of the theme(s) you want to remove, and can be combined with the "
"``--verbose`` option."
msgstr ""
"``pelican-themes`` 命令同样可用于移除Pelican主题文件夹下的主题。 ``-r`` 或 "
"``--remove`` 选项以一个或多个主题的名称为参数,同样也可以结合 ``--verbose`` "
"选项使用。"
#: ../../pelican-themes.rst:122 9ea5149543a648049444220a4041da69
msgid "Creating symbolic links"
msgstr "创建符号链接"
#: ../../pelican-themes.rst:124 17cdf3146683485ea72db5fbd9c1f60a
msgid ""
"``pelican-themes`` can also install themes by creating symbolic links "
"instead of copying entire themes into the Pelican themes path."
msgstr ""
"``pelican-themes`` 也可以通过创建符号链接来安装主题,如此便无需完整拷贝主题。"
#: ../../pelican-themes.rst:127 1d2c60b41c374936a9986a852d50e898
msgid ""
"To symbolically link a theme, you can use the ``-s`` or ``--symlink``, "
"which works exactly as the ``--install`` option:"
msgstr ""
"使用 ``-s`` 或 ``--symlink`` 选项来为主题创建符号链接,用法和 ``--install`` 选项相同:"
#: ../../pelican-themes.rst:134 66707a8607f549199dca6f93586d2d87
msgid ""
"In this example, the ``two-column`` theme is now symbolically linked to "
"the Pelican themes path, so we can use it, but we can also modify it "
"without having to reinstall it after each modification."
msgstr ""
"在上面的例子中, ``two-column`` 主题就已经在Pelican主题目录下创建了符号链接"
"也可以正常使用。如此,当我们修改主题后就无需重新进行安装。"
#: ../../pelican-themes.rst:138 93ec27a473b04bca9d2930a7cb6b609c
msgid "This is useful for theme development:"
msgstr "这对主题的开发是很有用的:"
#: ../../pelican-themes.rst:155 66d808308aa64fc9afcef8bdf03bca8b
msgid "Doing several things at once"
msgstr "同时执行多个操作"
#: ../../pelican-themes.rst:157 ace10a2c2f4d4adab9ade60631e82c38
msgid ""
"The ``--install``, ``--remove`` and ``--symlink`` options are not "
"mutually exclusive, so you can combine them in the same command line to "
"do more than one operation at time, like this:"
msgstr ""
"``--install`` 、 ``--remove`` 和 ``--symlink`` 可以同时使用,不会冲突,"
"因此可以在同一行命令中同时做多个操作:"
#: ../../pelican-themes.rst:169 e7adbac04b6a40fd986c02e834cc1756
msgid ""
"In this example, the theme ``notmyidea-cms`` is replaced by the theme "
"``notmyidea-cms-fr``"
msgstr ""
"在上面的例子中,用 ``notmyidea-cms-fr`` 替换了 ``notmyidea-cms`` 主题。"

View file

@ -0,0 +1,669 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-13 11:46+0800\n"
"PO-Revision-Date: 2024-06-26 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.17.0\n"
#: ../../plugins.rst:4 3df58bcad1a64350a8e763d87d7470e3
msgid "Plugins"
msgstr "插件"
#: ../../plugins.rst:6 5e0f2aa517254778a71d1e742b051645
msgid ""
"Beginning with version 3.0, Pelican supports plugins. Plugins are a way "
"to add features to Pelican without having to directly modify the Pelican "
"core."
msgstr "Pelican从3.0版本开始支持插件。通过插件不必直接修改Pelican的核心代码就可以给Pelican添加新功能。"
#: ../../plugins.rst:10 40ad4aad1dc54b929f6059031edae0d9
msgid "How to use plugins"
msgstr "如何使用插件"
#: ../../plugins.rst:12 8fc9f8cba76b4bb9930d80b5b985885a
msgid ""
"Starting with version 4.5, Pelican moved to a new plugin structure "
"utilizing namespace packages that can be easily installed via Pip_. "
"Plugins supporting this structure will install under the namespace "
"package ``pelican.plugins`` and can be automatically discovered by "
"Pelican. To see a list of Pip-installed namespace plugins that are active"
" in your environment, run::"
msgstr ""
"Pelican从4.5版本开始使用了一种全新的插件结构,利用了命名空间包,并且可以轻松地通过 Pip_ "
"进行安装。支持此结构地插件都会被安装在命名空间包 ``pelican.plugins`` "
"下因此Pelican可以自动发现他们。下面的命令可以用于查看环境中用Pip安装的所有插件"
#: ../../plugins.rst:20 de052285e7f645a9ab551433f3c07d46
msgid ""
"If you leave the ``PLUGINS`` setting as default (``None``), Pelican will "
"automatically discover namespace plugins and register them. If, on the "
"other hand, you specify a ``PLUGINS`` setting as a list of plugins, this "
"auto-discovery will be disabled. At that point, only the plugins you "
"specify will be registered, and you must explicitly list any namespace "
"plugins as well."
msgstr ""
"若将 ``PLUGINS`` 配置项设为默认的 ``None`` Pelican会自动发现命名空间中的插件并且将他们全部加载若你在 "
"``PLUGINS`` 设置项中指定了一系列的插件Pelican就不会去自动发现插件也就是说你需要显式地指定所有要使用的插件。"
#: ../../plugins.rst:26 a9675be841b84df584e67087cd23ab34
msgid ""
"If you are using the ``PLUGINS`` setting, you can specify plugins in two "
"ways. The first method specifies plugins as a list of strings. Namespace "
"plugins can be specified either by their full names "
"(``pelican.plugins.myplugin``) or by their short names (``myplugin``)::"
msgstr ""
"在配置 ``PLUGINS`` 时,有两种方式。一是用字符串列表指定插件的名称,可以是包含命名空间的完整名称(例如 "
"``pelican.plugins.myplugin`` ),也可以是简短名称( ``myplugin``"
#: ../../plugins.rst:35 188bf617180b4a7b9bc09f3fb1c201ae
msgid ""
"Alternatively, you can import them in your settings file and pass the "
"modules::"
msgstr "二是在设置文件中先import进来再将import进的模块放在 ``PLUGINS`` 设置项中:"
#: ../../plugins.rst:43 2d5db874810245a98b59ab080a0df1a5
msgid ""
"When experimenting with different plugins (especially the ones that deal "
"with metadata and content) caching may interfere and the changes may not "
"be visible. In such cases disable caching with ``LOAD_CONTENT_CACHE = "
"False`` or use the ``--ignore-cache`` command-line switch."
msgstr ""
"在尝试不同的插件时(尤其是那些处理元数据和内容的插件),缓存可能会相互干扰,一些更改不会生效。发生这种情况时,就需要通过设置 "
"``LOAD_CONTENT_CACHE = False`` 或使用 ``--ignore-cache`` 命令行选项禁用缓存。"
#: ../../plugins.rst:48 7421f93c1d714c9c853fc9311681515a
msgid ""
"If your plugins are not in an importable path, you can specify a list of "
"paths via the ``PLUGIN_PATHS`` setting. As shown in the following "
"example, paths in the ``PLUGIN_PATHS`` list can be absolute or relative "
"to the settings file::"
msgstr ""
"如果插件处于无法直接进行import的路径可以在 ``PLUGIN_PATHS`` 配置项中指定这些路径。如下例所示, "
"``PLUGIN_PATHS`` 中的路径可以是绝对的,也可以是相对于设置文件的:"
#: ../../plugins.rst:56 b8406038d0284d3fbef9d3de1fa7fd9f
msgid "Where to find plugins"
msgstr "在哪儿下载插件"
#: ../../plugins.rst:57 b07653ce77194a998630a55ae9511de5
msgid ""
"Namespace plugins can be found in the `pelican-plugins organization`_ as "
"individual repositories. Legacy plugins are located in the `pelican-"
"plugins repository`_ and will be gradually phased out in favor of the "
"namespace versions."
msgstr ""
"新的命名空间插件可以在GitHub的 `pelican-plugins 组织`_ "
"中找到每个插件都是一个独立的仓库。而老的插件则可以在GitHub的 `pelican-plugins 仓库`_ "
"中找到。这些老的插件会逐步淘汰并转移到新的命名空间版本。"
#: ../../plugins.rst:65 5c55fa6f3d664be2a49b8256dc2f6a2e
msgid ""
"Please note that while we do our best to review and maintain these "
"plugins, they are submitted by the Pelican community and thus may have "
"varying levels of support and interoperability."
msgstr "请注意尽管我们尽全力审查和维护这些插件但这些插件是Pelican社区提交的因此支持性和互操作性程度各不相同。"
#: ../../plugins.rst:70 25339a713a97492c88b0e60024ac34b8
msgid "How to create plugins"
msgstr "如何创建插件"
#: ../../plugins.rst:72 62b6b4a1a5f0486e8b3a39d6a7050f0a
msgid ""
"Plugins are based on the concept of signals. Pelican sends signals, and "
"plugins subscribe to those signals. The list of available signals is "
"documented in a subsequent section."
msgstr "插件是基于信号这一概念的。Pelican会发送信号插件则订阅这些信号。可用的信号在下一节会贴出来。"
#: ../../plugins.rst:76 f8f74b0257be46a1878e72e126166bd0
msgid ""
"The only rule to follow for plugins is to define a ``register`` callable,"
" in which you map the signals to your plugin logic. Let's take a simple "
"example::"
msgstr ""
"对于插件来说,唯一需要遵循的规则就是一定要定义一个可调用的 ``register`` ,在 ``register`` "
"中需要将信号映射到插件逻辑上。下面是一个简单的例子:"
#: ../../plugins.rst:93 163eebc74421416da2ad497830c42771
msgid ""
"Signal receivers are weakly-referenced and thus must not be defined "
"within your ``register`` callable or they will be garbage-collected "
"before the signal is emitted."
msgstr "信号接收器在Pelican中是弱引用的因此不能将它定义在可调用的 ``register`` 中,否则接收器在信号发送之前就会被回收。"
#: ../../plugins.rst:97 bb63bd2d24e341a1a4f7dfa118648d9a
msgid ""
"If multiple plugins connect to the same signal, plugins will be invoked "
"in the order they are registered. When the ``PLUGINS`` setting is "
"defined, plugin invocation order will be the order in which the plugins "
"are listed in the ``PLUGINS`` setting. If you rely on auto-discovered "
"namespace plugins and have no ``PLUGINS`` setting defined, plugins will "
"be invoked in the same order that they are discovered (the same order as "
"listed in the output of the ``pelican-plugins`` command). If you want to "
"specify the order explicitly, disable auto-discovery by defining "
"``PLUGINS`` in the desired order."
msgstr ""
"对于关联到同一个信号的多个插件,将按照它们注册的前后顺序执行。但若设置了 ``PLUGINS`` "
"配置项则会以此配置项中的顺序为准。如果您使用了无需PLUGINS设置的新版命名空间插件它们将按照被探测到的顺序进行连接与 pelican-"
"plugins 输出的顺序相同)。若您此时仍想要显式指定顺序,设置 ``PLUGINS`` 配置项即可。"
#: ../../plugins.rst:107 062aa3a3402141cfbd376d4fee1b5b34
msgid "Namespace plugin structure"
msgstr "命名空间插件的结构"
#: ../../plugins.rst:109 e6968290620d4de3b71ff62d5abba91f
msgid ""
"Namespace plugins must adhere to a certain structure in order to function"
" properly. They need to be installable (i.e. contain ``setup.py`` or "
"equivalent) and have a folder structure as follows::"
msgstr "命名空间插件必须遵循特定的结构才能正常工作。这些插件需要是可安装的(即包含 ``setup.py`` 或其他等效文件),并且遵循下述文件夹结构:"
#: ../../plugins.rst:122 b9782f71fae14bce9854b8b5056407d8
msgid ""
"It is crucial that ``pelican`` or ``pelican/plugins`` folder **not** "
"contain an ``__init__.py`` file. In fact, it is best to have those "
"folders empty besides the listed folders in the above structure and keep "
"your plugin related files contained solely in the "
"``pelican/plugins/myplugin`` folder to avoid any issues."
msgstr ""
"非常关键的一点就是, ``pelican`` 和 ``pelican/plugins`` 文件夹下都 **不能** 包含 "
"``__init__.py`` 文件。事实上,这两个文件夹下最好是只有上面列出的文件夹,并且保证与插件相关的文件都仅包含在 "
"``pelican/plugins/myplugin`` 文件夹中,以避免奇奇怪怪的问题。"
#: ../../plugins.rst:128 8440bc91329c498c90fadab556391a84
msgid ""
"To easily set up the proper structure, a `cookiecutter template for "
"plugins`_ is provided. Refer to that project's README for instructions on"
" how to use it."
msgstr "为了让大家更容易就能建立正确的结构,我们为插件提供了一个 `cookiecutter模板`_ 使用方法参考此项目README文件中的指示即可。"
#: ../../plugins.rst:134 bb029c6c9ea14a2dac684d516fb9a1eb
msgid "List of signals"
msgstr "信号列表"
#: ../../plugins.rst:136 968d92d9b3bb4491ad9c0e4a015e73f9
msgid "Here is the list of currently implemented signals:"
msgstr "下面是目前已经实现了的信号:"
#: ../../plugins.rst:139 f2db011f146d40bf9f07ec6b09c7c6d0
msgid "Signal"
msgstr "信号"
#: ../../plugins.rst:139 32f683cb25c74315ac803c62868bd7b2
msgid "Arguments"
msgstr "参数"
#: ../../plugins.rst:139 d02ae4c30dec40ae8bd894fda051562d
msgid "Description"
msgstr "描述"
#: ../../plugins.rst:141 d526b9cb6c3c409f9b2d243082dfbdc3
msgid "initialized"
msgstr "initialized"
#: ../../plugins.rst:141 ../../plugins.rst:142 ../../plugins.rst:160
#: ../../plugins.rst:163 0ab3e30cf009477980c4c619e0a7dc5e
#: 8cf4a2d70a234250a4d9f63e4e8cb49f a600f769faef42d99333442745c7b498
#: a69e7ba2df7a47658b2f0e4ade60d455
msgid "pelican object"
msgstr "pelican object"
#: ../../plugins.rst:142 3aff44965eec41269a45fd0b84b8b5d7
msgid "finalized"
msgstr "finalized"
#: ../../plugins.rst:142 6a3bd6c773b245af9151ff5669ef7f84
msgid ""
"invoked after all the generators are executed and just before pelican "
"exits useful for custom post processing actions, such as: - minifying "
"js/css assets. - notify/ping search engines with an updated sitemap."
msgstr "所有generator执行完成后调用即pelican退出之前。这对于自定义后处理操作是非常有用的例如可以简化js/css资源、向搜索引擎告知更新后的sitemap。"
#: ../../plugins.rst:146 eecb5a5dc1b84f94a830db617122f365
msgid "generator_init"
msgstr "generator_init"
#: ../../plugins.rst:146 b01311f8da704b55b38e23149c60bc22
msgid "generator"
msgstr "generator"
#: ../../plugins.rst:146 a3c477e7a8d04e94af4ee7a82c873ef2
msgid "invoked in the Generator.__init__"
msgstr "在Generator.__init__中调用"
#: ../../plugins.rst:147 246a49eb99d34589ac409e5613f27069
msgid "all_generators_finalized"
msgstr "all_generators_finalized"
#: ../../plugins.rst:147 0dafe1a8f7224b1bbe1af3ebeeac0b31
msgid "generators"
msgstr "generators"
#: ../../plugins.rst:147 9d5130f91ac748e58d96cfba7711e8f6
msgid "invoked after all the generators are executed and before writing output"
msgstr "在所有generator执行完后写入输出内容前调用"
#: ../../plugins.rst:148 3a7f543549164bb684f47daa5b1b9bd1
msgid "readers_init"
msgstr "readers_init"
#: ../../plugins.rst:148 0946829014734c53a0b1e389df853daf
msgid "readers"
msgstr "readers"
#: ../../plugins.rst:148 380ba486fff24555b3c312bee4645d23
msgid "invoked in the Readers.__init__"
msgstr "在Readers.__init__中调用"
#: ../../plugins.rst:149 ../../plugins.rst:203 04aa2b44a0b84da9b62b952b627a2b5c
#: e725d629327b48e3a7dffad1d07d81d2
msgid "article_generator_context"
msgstr "article_generator_context"
#: ../../plugins.rst:149 f0c440ead7fc46e2a90685c3fdffb5d4
msgid "article_generator, metadata"
msgstr "article_generator, metadata"
#: ../../plugins.rst:150 ../../plugins.rst:205 2ed41de1aaed481195aeacbc841459be
#: e9e159b6d49d4cd29ebbe6eb6e0bb3b1
msgid "article_generator_preread"
msgstr "article_generator_preread"
#: ../../plugins.rst:150 ../../plugins.rst:152 ../../plugins.rst:153
#: ../../plugins.rst:156 37277bd83e254f47b6df91ba6790f79e
#: 9d3b745b96114ff7931cbcc372901c3e b89f87d254984ec59e25045227c708bf
#: d38f0e2931b84b82adcc5aca5a4c2233
msgid "article_generator"
msgstr "article_generator"
#: ../../plugins.rst:150 7a45243569e84c1e9d5d49b5c1a7b86a
msgid ""
"invoked before a article is read in ArticlesGenerator.generate_context; "
"use if code needs to do something before every article is parsed"
msgstr "在ArticlesGenerator.generate_context读取文章之前调用若代码需要在解析每篇文章前执行某些操作就可以使用此信号。"
#: ../../plugins.rst:152 87c8e4ad4a104cb889172025f1b0229b
msgid "article_generator_init"
msgstr "article_generator_init"
#: ../../plugins.rst:152 46c1e5fbb90a4668afda3d66e4520689
msgid "invoked in the ArticlesGenerator.__init__"
msgstr "在ArticlesGenerator.__init__中调用"
#: ../../plugins.rst:153 de4b631d41e946c485ebb813e3dd6b62
msgid "article_generator_pretaxonomy"
msgstr "article_generator_pretaxonomy"
#: ../../plugins.rst:153 697a45a251fe4188b1f32cec631427b9
msgid ""
"invoked before categories and tags lists are created useful when e.g. "
"modifying the list of articles to be generated so that removed articles "
"are not leaked in categories or tags"
msgstr "在创建类别和标签列表之前调用。例如,当需要变更要生成的文章列表时可以使用,如此可以避免一些已移除文章在分类或标签列表中泄露。"
#: ../../plugins.rst:156 ../../plugins.rst:204 051dcac75cbf4f5ea3a665e6da642324
#: 2360e283fdd142ab8d65792581522e72
msgid "article_generator_finalized"
msgstr "article_generator_finalized"
#: ../../plugins.rst:156 0c3c808d5b7044018f8566ccc6dd3010
msgid "invoked at the end of ArticlesGenerator.generate_context"
msgstr "在ArticlesGenerator.generate_context的最后调用"
#: ../../plugins.rst:157 60d78048da4843a7a0307218c078d151
msgid "article_generator_write_article"
msgstr "article_generator_write_article"
#: ../../plugins.rst:157 2ac0d0e7306a4d5086bb2e8b7b17ffb1
msgid "article_generator, content"
msgstr "article_generator, content"
#: ../../plugins.rst:157 565551e010964925b10a3b5734913119
msgid "invoked before writing each article, the article is passed as content"
msgstr "在写入每篇文章前调用,文章以内容的形式作为参数传入。"
#: ../../plugins.rst:158 fd7918c3200f4714b028c8d0a200df98
msgid "article_writer_finalized"
msgstr "article_writer_finalized"
#: ../../plugins.rst:158 e54633543dbf4e5fb2dd4c1bfc09b1c1
msgid "article_generator, writer"
msgstr "article_generator, writer"
#: ../../plugins.rst:158 965e61a0fd6347faa2d7224a50a98b76
msgid ""
"invoked after all articles and related pages have been written, but "
"before the article generator is closed."
msgstr "在所有文章及相关联页面写入完成后在文章generator关闭前调用。"
#: ../../plugins.rst:160 30df01c5c11a4ed58b006d78b007c68d
msgid "get_generators"
msgstr "get_generators"
#: ../../plugins.rst:160 758447f5e55a4738a14486b0e962034d
msgid ""
"invoked in Pelican.get_generator_classes, can return a Generator, or "
"several generators in a tuple or in a list."
msgstr "在Pelican.get_generator_classes中调用可以返回一个Generator也可以以一个元组或列表的形式返回多个generator。"
#: ../../plugins.rst:163 730e948388a24435be216830e0af5be6
msgid "get_writer"
msgstr "get_writer"
#: ../../plugins.rst:163 df9f9fef24984c4bad07b8834e79352f
msgid "invoked in Pelican.get_writer, can return a custom Writer."
msgstr "在Pelican.get_writer前调用可以返回一个自定义Writer。"
#: ../../plugins.rst:165 ../../plugins.rst:206 1c172b26e92543d2be488a88cceaf576
#: 252231854c504621b28243dfba9d88ab
msgid "page_generator_context"
msgstr "page_generator_context"
#: ../../plugins.rst:165 a830e240c6564552ba4952bc657120a9
msgid "page_generator, metadata"
msgstr "page_generator, metadata"
#: ../../plugins.rst:166 ../../plugins.rst:207 09add2ea39344ad8936296a07cfd8e82
#: 0fc3cf365d9d418b8225e8f1f5da76d0
msgid "page_generator_preread"
msgstr "page_generator_preread"
#: ../../plugins.rst:166 ../../plugins.rst:168 ../../plugins.rst:169
#: 3c31cfe2f4744cd987f1638a4b82e5de a80ec8c388cb477abbcfc4f558d34df7
#: d485c4f9c2c443748234827727cc887e
msgid "page_generator"
msgstr "page_generator"
#: ../../plugins.rst:166 4d8b96aa6ebf47d885cd978c336679ff
msgid ""
"invoked before a page is read in PageGenerator.generate_context; use if "
"code needs to do something before every page is parsed."
msgstr "在PageGenerator.generate_context读取页面前调用若代码需要在解析每个页面前执行某些操作就可以使用此信号。"
#: ../../plugins.rst:168 ../../plugins.rst:209 06adf06d2b204100b9f80850b84bdff0
#: c0988434a401410e8cf6b4528e6d2870
msgid "page_generator_init"
msgstr "page_generator_init"
#: ../../plugins.rst:168 d359da10912949fa999dc3ad5215be66
msgid "invoked in the PagesGenerator.__init__"
msgstr "在PagesGenerator.__init__中调用"
#: ../../plugins.rst:169 ../../plugins.rst:208 0994b38b87704caea04ef0671a7b1c67
#: a97cf5f236a64959aa09838dbe03dfdc
msgid "page_generator_finalized"
msgstr "page_generator_finalized"
#: ../../plugins.rst:169 4cfdfe952daf4e3ea5ea1c8b2cf7a664
msgid "invoked at the end of PagesGenerator.generate_context"
msgstr "在PagesGenerator.generate_context的最后调用"
#: ../../plugins.rst:170 7e2504584a1b4fa4ae88c5002bcbb26f
msgid "page_generator_write_page"
msgstr "page_generator_write_page"
#: ../../plugins.rst:170 ea204a5fe703472ea5afea283135b94d
msgid "page_generator, content"
msgstr "page_generator, content"
#: ../../plugins.rst:170 22dd198fe6dc498f944e2c0e2c595c6c
msgid "invoked before writing each page, the page is passed as content"
msgstr "在写入每个页面前调用,页面以内容形式作为参数传入"
#: ../../plugins.rst:171 84d5def2c4fc4a2489d2b4fc1fa445df
msgid "page_writer_finalized"
msgstr "page_writer_finalized"
#: ../../plugins.rst:171 c55d65276a4e49c58c34d12cc062c90d
msgid "page_generator, writer"
msgstr "page_generator, writer"
#: ../../plugins.rst:171 b2a3d1c7c2864a08829833bc16b3223e
msgid ""
"invoked after all pages have been written, but before the page generator "
"is closed."
msgstr "调用于所有页面写入完成后在页面generator关闭前。"
#: ../../plugins.rst:173 ../../plugins.rst:210 097c5b3dc1d34a5eb7c1b4ae67179b3e
#: a420152f887e4977bdd26a5fa7230915
msgid "static_generator_context"
msgstr "static_generator_context"
#: ../../plugins.rst:173 1bbacfe960644e4a902b9c866e3fffce
msgid "static_generator, metadata"
msgstr "static_generator, metadata"
#: ../../plugins.rst:174 ../../plugins.rst:211 c1242bcf76fc40568f67a2ce4e70c0bb
#: f407aa94870645c891bb349edc3ae9a4
msgid "static_generator_preread"
msgstr "static_generator_preread"
#: ../../plugins.rst:174 ../../plugins.rst:177 ../../plugins.rst:178
#: 36f5be5c982b42d097c0465f542e490f cf0ebefd743246dd9db1b37a8c6a43a8
#: d5cd54887d904bcca02b0df4f22580e9
msgid "static_generator"
msgstr "static_generator"
#: ../../plugins.rst:174 1b2fbadf156644429e66ad2e64d26658
msgid ""
"invoked before a static file is read in StaticGenerator.generate_context;"
" use if code needs to do something before every static file is added to "
"the staticfiles list."
msgstr "在StaticGenerator.generate_context读取静态文件前调用若代码需要在每个静态文件加入静态文件列表前进行一些修改就可以使用此信号。"
#: ../../plugins.rst:177 654377fe53434f77b3ba294b5689d1d4
msgid "static_generator_init"
msgstr "static_generator_init"
#: ../../plugins.rst:177 e9b3cbbde7a6443a81d025d1a4fe6145
msgid "invoked in the StaticGenerator.__init__"
msgstr "在StaticGenerator.__init__中调用"
#: ../../plugins.rst:178 202be739e43444f48f122d3e5f657a45
msgid "static_generator_finalized"
msgstr "static_generator_finalized"
#: ../../plugins.rst:178 06080672fd614d39a79aa6d3a783087f
msgid "invoked at the end of StaticGenerator.generate_context"
msgstr "在StaticGenerator.generate_context的最后调用"
#: ../../plugins.rst:179 ce174fb4533143518c13b16ab6dbe4c8
msgid "content_object_init"
msgstr "content_object_init"
#: ../../plugins.rst:179 5089a38bad1447cab62f350df8e76f31
msgid "content_object"
msgstr "content_object"
#: ../../plugins.rst:179 d105f652be424f5cad8bfaf7be69ec4b
msgid "invoked at the end of Content.__init__"
msgstr "在Content.__init__的最后调用"
#: ../../plugins.rst:180 dbda8a11bca744a4ba5fc51d044f1d6e
msgid "content_written"
msgstr "content_written"
#: ../../plugins.rst:180 c8ba95ebcc2e4c79ae79717a730fe504
msgid "path, context"
msgstr "path, context"
#: ../../plugins.rst:180 6d9caed8fa24400a86f8ede1c3ecb260
msgid "invoked each time a content file is written."
msgstr "每一次内容文件写入后调用。"
#: ../../plugins.rst:181 73a4265b050c4b32be186bb2cec59f30
msgid "feed_generated"
msgstr "feed_generated"
#: ../../plugins.rst:181 78fa3603986f417286f2e7440f5aff57
msgid "context, feed"
msgstr "context, feed"
#: ../../plugins.rst:181 13dcd9e5fb2f408db72b87b88877596b
msgid ""
"invoked each time a feed gets generated. Can be used to modify a feed "
"object before it gets written."
msgstr "每个feed生成前调用。可以用于在feed写入前修改之。"
#: ../../plugins.rst:183 3a959768d5704e459940cbfcf8e1459c
msgid "feed_written"
msgstr "feed_written"
#: ../../plugins.rst:183 86844bee049a445e87db283bdf325338
msgid "path, context, feed"
msgstr "path, context, feed"
#: ../../plugins.rst:183 e79185da7cb54bf5aa59a46846222391
msgid "invoked each time a feed file is written."
msgstr "每一个feed文件写入后调用。"
#: ../../plugins.rst:188 0fe0539bad1c4fcbbebbdaa98d328ee9
msgid ""
"Avoid ``content_object_init`` signal if you intend to read ``summary`` or"
" ``content`` properties of the content object. That combination can "
"result in unresolved links when :ref:`ref-linking-to-internal-content` "
"(see `pelican-plugins bug #314`_). Use ``_summary`` and ``_content`` "
"properties instead, or, alternatively, run your plugin at a later stage "
"(e.g. ``all_generators_finalized``)."
msgstr ""
"请避免使用 ``content_object_init`` 信号读取content对象的 ``summary`` 或 ``content`` "
"属性,这可能导致在 :ref:`ref-linking-to-internal-content` 时无法解析链接(请参阅 `pelican-"
"plugins bug #314`_ )。请改用 ``_summary`` 和 ``_content`` 属性,或者就在后续阶段再运行插件(例如 "
"``all_generators_finalized`` 时)。"
#: ../../plugins.rst:197 77ca681d0d7a4a9ea42f7eebf683f024
msgid ""
"After Pelican 3.2, signal names were standardized. Older plugins may "
"need to be updated to use the new names:"
msgstr "Pelican3.2之后,信号名都进行了标准化,较老的插件可能需要进行更新:"
#: ../../plugins.rst:201 c83f9215c5964ba49cb5ed849c777495
msgid "Old name"
msgstr "旧名称"
#: ../../plugins.rst:201 167435de345b443fa51c27b355121e14
msgid "New name"
msgstr "新名称"
#: ../../plugins.rst:203 bcdf136cbb2c4dedbd90f6e56f584c6b
msgid "article_generate_context"
msgstr "article_generate_context"
#: ../../plugins.rst:204 60fe5b91f4a54f0997f93d927b0d81c4
msgid "article_generate_finalized"
msgstr "article_generate_finalized"
#: ../../plugins.rst:205 31252537627f4042b7f7b4e0a4a33aeb
msgid "article_generate_preread"
msgstr "article_generate_preread"
#: ../../plugins.rst:206 719da4844a0a4b6fbb2cf2d9b7e51deb
msgid "pages_generate_context"
msgstr "pages_generate_context"
#: ../../plugins.rst:207 f7c865fd6824473aad024fc606235b48
msgid "pages_generate_preread"
msgstr "pages_generate_preread"
#: ../../plugins.rst:208 74c47460bacf4fd68f2536580efb1480
msgid "pages_generator_finalized"
msgstr "pages_generator_finalized"
#: ../../plugins.rst:209 b403e7f978c24d989d99587579f31d3c
msgid "pages_generator_init"
msgstr "pages_generator_init"
#: ../../plugins.rst:210 94e5184530c94cc48d00fd819fffd649
msgid "static_generate_context"
msgstr "static_generate_context"
#: ../../plugins.rst:211 00ca2c730ad840f584d3f9dd30daf0cd
msgid "static_generate_preread"
msgstr "static_generate_preread"
#: ../../plugins.rst:215 f8044e028ccd4d64954e24375a739cd2
msgid "Recipes"
msgstr "具体使用方法举例"
#: ../../plugins.rst:217 0c441d12047240199025f2d3ac954167
msgid ""
"We eventually realised some of the recipes to create plugins would be "
"best shared in the documentation somewhere, so here they are!"
msgstr "下面分享了一些创建插件的具体方法,请享用!"
#: ../../plugins.rst:221 bb96f2da7b3340cb9ed56ee1ad59796b
msgid "How to create a new reader"
msgstr "如何创建一个新的reader"
#: ../../plugins.rst:223 49dbbbd2c5ca4798a1b9d67b48630d36
msgid ""
"One thing you might want is to add support for your very own input "
"format. While it might make sense to add this feature in Pelican core, we"
" wisely chose to avoid this situation and instead have the different "
"readers defined via plugins."
msgstr "你可能需要添加对输入文件格式的特殊支持。这似乎可以作为Pelican核心的一个功能但我们选择避免将此功能放在核心中而是通过插件实现不同的reader。"
#: ../../plugins.rst:228 af8936c711204a0aa7c85835124065c5
msgid ""
"The rationale behind this choice is mainly that plugins are really easy "
"to write and don't slow down Pelican itself when they're not active."
msgstr "做出这个决定主要是因为实现这样的格式支持插件非常容易而且这样在不需要此功能时也不会影响Pelican自身的速度。"
#: ../../plugins.rst:231 11dac8bd71994c18a289086ec95a0273
msgid "No more talking — here is an example::"
msgstr "多说无益,下面是一个具体例子:"
#: ../../plugins.rst:267 f6bf903ae8de4ac183ecea699de568dc
msgid "Adding a new generator"
msgstr "添加新的generator"
#: ../../plugins.rst:269 50d39b45550446a493a6d5d6eb971103
msgid ""
"Adding a new generator is also really easy. You might want to have a look"
" at :doc:`internals` for more information on how to create your own "
"generator."
msgstr "添加一个generator也非常简单你可能会想要看一看 :doc:`internals` 其中有关于如何创建generator的内容。"
#: ../../plugins.rst:283 1b4bc8c2b02645dd81b06ffdbd759c36
msgid "Adding a new writer"
msgstr "添加新的writer"
#: ../../plugins.rst:285 ac526121b895429d8412605bca594684
msgid ""
"Adding a writer will allow you to output additional file formats to disk,"
" or change how the existing formats are written to disk. Note that only "
"one writer will be active at a time, so be sure to either subclass the "
"built-in Writer, or completely re-implement it."
msgstr "添加writer可以让你将其他文件格式输出到磁盘或者可以改变现有格式写入磁盘的方式。请注意一次只能启用一个writer因此请确保继承了内置的Writer并且完全重新实现之。"
#: ../../plugins.rst:290 4335016710cd417ca9b8068cb7a45d51
msgid "Here is a basic example of how to set up your own writer::"
msgstr "下面是启用你的自定义writer的一个基本例子"
#: ../../plugins.rst:310 c65b371d4bf740c49dfe190407c9af69
msgid "Using Plugins to Inject Content"
msgstr "使用插件添加内容"
#: ../../plugins.rst:312 9f180f86d09f43d7aff4607bb7deb6f1
msgid ""
"You can programmatically inject articles or pages using plugins. This can"
" be useful if you plan to fetch articles from an API, for example."
msgstr "可以通过插件以可编程的方式添加文章或页面。如果你打算从某些API获取文章这就会很有用。"
#: ../../plugins.rst:315 a65dd6bb4d0e48438dcf6d545bfaa053
msgid ""
"Following is a simple example of how one can build a plugin that injects "
"a custom article, using the ``article_generator_pretaxonomy`` signal::"
msgstr "下面是一个简单的示例,说明了如何使用 ``article_generator_pretaxonomy`` 信号构建一个添加自定义文章的插件:"

View file

@ -0,0 +1,329 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-25 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../publish.rst:2 65617cfb871b492589d55186b708a1ce
msgid "Publish your site"
msgstr "发布站点"
#: ../../publish.rst:7 dc4c9b1c1afd477d906b892dc592bdcd
msgid "Site generation"
msgstr "站点生成"
#: ../../publish.rst:9 610c37360e2b49ec8ea630ddc224d2b7
msgid ""
"Once Pelican is installed and you have some content (e.g., in Markdown or"
" reST format), you can convert your content into HTML via the ``pelican``"
" command, specifying the path to your content and (optionally) the path "
"to your :doc:`settings<settings>` file::"
msgstr ""
"您应该已经安装好Pelican并且已经创作了一些内容了吧以Markdown或是reST格式"
"现在就可以将这些内容通过 ``pelican`` 命令转换为HTML了在转换时需要指定"
"创作内容存放的路径;如果有需要, :doc:`配置<settings>` 文件的路径也可单独指定:"
#: ../../publish.rst:16 6f353c84f5204d2b84c49d1557010b19
msgid ""
"The above command will generate your site and save it in the ``output/`` "
"folder, using the default theme to produce a simple site. The default "
"theme consists of very simple HTML without styling and is provided so "
"folks may use it as a basis for creating their own themes."
msgstr ""
"上面的指令会在 ``output/`` 目录下生成站点,使用的是默认的主题。默认主题只使用"
"一些简单的HTML并且不包含样式大家往往以这个简单主题为基础来创作自己的主题。"
#: ../../publish.rst:21 bb5064d57ed144e6b85d7d3d0938f91c
msgid ""
"You can also tell Pelican to watch for your modifications, instead of "
"manually re-running it every time you want to see your changes. To enable"
" this, run the ``pelican`` command with the ``-r`` or ``--autoreload`` "
"option. On non-Windows environments, this option can also be combined "
"with the ``-l`` or ``--listen`` option to simultaneously both auto-"
"regenerate *and* serve the output at http://localhost:8000::"
msgstr ""
"你也可以让Pelican来监听对源内容文件的修改而不是在每次修改内容后重新手动执行命令"
"来生成站点。在执行 ``pelican`` 命令时,加上 ``-r`` 或者 ``--autoreload`` 选项"
"就可以做到这一点。在非Windows环境下这个选项还可以和 ``-l`` 或 ``--listen`` "
"搭配使用,这样就可以在自动重生成站点的基础上,同时提供在 http://localhost:8000 "
"上的访问:"
#: ../../publish.rst:30 40089a6762204e27bd16afaa038a8277
msgid ""
"Pelican has other command-line switches available. Have a look at the "
"help to see all the options you can use::"
msgstr ""
"Pelican还有一些其他的命令行选项。可以在帮助中看到所有可用选项"
#: ../../publish.rst:36 4484bb6f6e2b4bd49027c98be4fa2cd8
msgid "Viewing the generated files"
msgstr "浏览生成的文件"
#: ../../publish.rst:38 4dc83b844c964bcab17af21fabd5e6b2
msgid ""
"The files generated by Pelican are static files, so you don't actually "
"need anything special to view them. You can use your browser to open the "
"generated HTML files directly::"
msgstr ""
"Pelican生成的文件都是静态的也就是说不需要使用什么特殊的手段就可以浏览。"
"您可以直接使用浏览器打开生成的HTML文件"
#: ../../publish.rst:44 c5774634f7da4f64bb7c7d0adbcdb65b
msgid ""
"Because the above method may have trouble locating your CSS and other "
"linked assets, running Pelican's simple built-in web server will often "
"provide a more reliable previewing experience::"
msgstr ""
"事实上上面所说的直接打开的方式可能会使CSS或其他链接上出现问题"
"可以运行Pelican自带的简易web服务器如此便可以获得可靠的预览体验"
#: ../../publish.rst:50 b2eab6914b854b40bd769433fbad21b7
msgid ""
"Once the web server has been started, you can preview your site at: "
"http://localhost:8000/"
msgstr ""
"当web服务器启动后可以访问 http://localhost:8000/ 来预览您的站点。"
#: ../../publish.rst:54 3b7344cad46a4dfaa01c067dd1f4009b
msgid "Deployment"
msgstr "部署"
#: ../../publish.rst:56 de2815c211b84291a985a1d808ffbfe7
msgid ""
"After you have generated your site, previewed it in your local "
"development environment, and are ready to deploy it to production, you "
"might first re-generate your site with any production-specific settings "
"(e.g., analytics, feeds, etc.) that you may have defined::"
msgstr ""
"当您生成好站点后,可以在本地先进行预览,确认无误后,在部署前可能还需使用"
"生产环境特定的配置文件重新生成站点:"
#: ../../publish.rst:63 56e568114b72443ebcf1f741f07504dc
msgid ""
"To base your publish configuration on top of your ``pelicanconf.py``, you"
" can import your ``pelicanconf`` settings by including the following line"
" in your ``publishconf.py``::"
msgstr ""
"您可以基于 ``pelicanconf.py`` 进行设置文件的配置, 在 ``publishconf.py`` "
"中import ``pelicanconf`` 就可实现(译者注:配置文件其实本质上就是一些"
"Python变量因此import后就可以全部引入"
#: ../../publish.rst:69 b9e1243ed9ba409890d86ef8ff85499d
msgid ""
"If you have generated a ``publishconf.py`` using ``pelican-quickstart``, "
"this line is included by default."
msgstr ""
"如果 ``publishconf.py`` 是通过 ``pelican-quickstart`` 生成的,上面这行默认就有。"
#: ../../publish.rst:72 39671d42b0bb4c828fc51c63c351402c
msgid ""
"The steps for deploying your site will depend on where it will be hosted."
" If you have SSH access to a server running Nginx or Apache, you might "
"use the ``rsync`` tool to transmit your site files::"
msgstr ""
"部署站点的方法步骤取决于网站托管的位置。对于使用SSH访问的运行着Nginx或"
"Apache的服务器您可能需要使用 ``rsync`` 工具来传输站点文件:"
#: ../../publish.rst:78 523ed256e0164a968d8580310e4a9304
msgid ""
"There are many other deployment options, some of which can be configured "
"when first setting up your site via the ``pelican-quickstart`` command. "
"See the :doc:`Tips<tips>` page for detail on publishing via GitHub Pages."
msgstr ""
"还有很多其他的部署方式供您选择,有一些在第一次通过 ``pelican-quickstart`` "
"命令建立站点时就已经配置。在 :doc:`小技巧<tips>` 中可以查看如何通过"
"Github Pages部署站点。"
#: ../../publish.rst:83 c44ecc79922d419b8627706a6694dd8c
msgid "Automation"
msgstr "自动化"
#: ../../publish.rst:85 b892dcba14a84306aa6b39295b5f81e3
msgid ""
"While the ``pelican`` command is the canonical way to generate your site,"
" automation tools can be used to streamline the generation and "
"publication flow. One of the questions asked during the ``pelican-"
"quickstart`` process pertains to whether you want to automate site "
"generation and publication. If you answered \"yes\" to that question, a "
"``tasks.py`` and ``Makefile`` will be generated in the root of your "
"project. These files, pre-populated with certain information gleaned from"
" other answers provided during the ``pelican-quickstart`` process, are "
"meant as a starting point and should be customized to fit your particular"
" needs and usage patterns. If you find one or both of these automation "
"tools to be of limited utility, these files can be deleted at any time "
"and will not affect usage of the canonical ``pelican`` command."
msgstr ""
"``pelican`` 命令是生成站点的标准方法,但同时也有自动化工具可以用来简化生成与"
"发布流程。在 ``pelican-quickstart`` 的过程中,其中一个问题就是是否启用自动站点"
"生成与发布。若您选择了 “yes”在项目的根目录中就会生成 ``tasks.py`` "
"和 ``Makefile`` 。这些文件中预填充了一些从 ``pelican-quickstart`` 过程中"
"收集的信息,您应该从这个生成好的文件出发,再根据实际需要进一步修改。"
"另外,如果您认为这些自动化脚本文件没什么用,完全可以将他们删除,这不会对标准命令 "
"``pelican`` 产生任何影响。"
#: ../../publish.rst:98 4c49ca3a24e3462a984dda738875ed4e
msgid ""
"Following are automation tools that \"wrap\" the ``pelican`` command and "
"can simplify the process of generating, previewing, and uploading your "
"site."
msgstr ""
"下面是一些自动化工具,其中包装了 ``pelican`` 命令,可以用于简化生成、预览和"
"上传站点的过程。"
#: ../../publish.rst:102 103fb7405038442aae62b62ea0fcdbe5
msgid "Invoke"
msgstr "Invoke"
#: ../../publish.rst:104 d3e46bf8da96489e923f6497e8932538
msgid ""
"The advantage of Invoke_ is that it is written in Python and thus can be "
"used in a wide range of environments. The downside is that it must be "
"installed separately. Use the following command to install Invoke, "
"prefixing with ``sudo`` if your environment requires it::"
msgstr ""
"Invoke_ 工具使用Python作为编程语言并且能够用在很多不同的环境中。它需要使用"
"下面的命令单独安装,在某些操作系统中可能需要在前面加上 ``sudo`` "
#: ../../publish.rst:111 786359d08e8f45598df7b1c45e32ca0a
msgid ""
"Take a moment to open the ``tasks.py`` file that was generated in your "
"project root. You will see a number of commands, any one of which can be "
"renamed, removed, and/or customized to your liking. Using the out-of-the-"
"box configuration, you can generate your site via::"
msgstr ""
"可以打开 ``tasks.py`` 文件看看其中的代码,可以尝试更改和删除其中的命令,"
"也可以按照您的喜好自行进行其他修改。生成好的文件是开箱即用的,您可以通过"
"下面的命令生成站点:"
#: ../../publish.rst:118 ../../publish.rst:166 04c6045b58c24bc1a1fd594cdcf4ef5c
#: 1e9cf29276ec4446b1b0f4a55a1ef4b8
msgid ""
"If you'd prefer to have Pelican automatically regenerate your site every "
"time a change is detected (which is handy when testing locally), use the "
"following command instead::"
msgstr ""
"若您希望Pelican在检测到变化时自动重新生成站点在本地测试的时候很实用"
"可以使用下面的命令:"
#: ../../publish.rst:124 ../../publish.rst:172 fabe0ce08eca4c5ebd9ca65898dab138
#: ff42351e29b944a59e8df22b1cbb20f5
msgid ""
"To serve the generated site so it can be previewed in your browser at "
"http://localhost:8000/::"
msgstr ""
"下面的命令则可以让您在生成后通过浏览器访问 http://localhost:8000/ 来预览站点"
#: ../../publish.rst:129 e1b12a6c64b246f89aea105b8d7febbc
msgid ""
"To serve the generated site with automatic browser reloading every time a"
" change is detected, first ``python -m pip install livereload``, then use"
" the following command::"
msgstr ""
"在每次检测到修改重生成站点后,可以让浏览器自动进行重载。先运行 "
"``python -m pip install livereload`` 安装,再运行下面的这条命令就可以实现:"
#: ../../publish.rst:135 bf0d6c7770fe4a399b81b9ebdd48fa4e
msgid ""
"If during the ``pelican-quickstart`` process you answered \"yes\" when "
"asked whether you want to upload your site via SSH, you can use the "
"following command to publish your site via rsync over SSH::"
msgstr ""
"如果在 ``pelican-quickstart`` 过程中对是否要通过SSH上传站点问题回答了“yes”"
"您就可以使用下面的命令借助rsync在SSH上发布站点"
#: ../../publish.rst:141 9bea9f82ce164ee5ba07349a4c4d58ea
msgid ""
"These are just a few of the commands available by default, so feel free "
"to explore ``tasks.py`` and see what other commands are available. More "
"importantly, don't hesitate to customize ``tasks.py`` to suit your "
"specific needs and preferences."
msgstr ""
"默认就可以使用的命令远不止这些,在 ``tasks.py`` 中可以找到更多可用的命令。"
"更重要的是,当您有特定需求和偏好时,直接修改 ``tasks.py`` 即可。"
#: ../../publish.rst:147 06a6e7232c6243d79ab9f43ddc28590d
msgid "Make"
msgstr "Make"
#: ../../publish.rst:149 a2a5b589cf804fcd83ee2d0fbf98c12d
msgid ""
"A ``Makefile`` is also automatically created for you when you say \"yes\""
" to the relevant question during the ``pelican-quickstart`` process. The "
"advantage of this method is that the ``make`` command is built into most "
"POSIX systems and thus doesn't require installing anything else in order "
"to use it. The downside is that non-POSIX systems (e.g., Windows) do not "
"include ``make``, and installing it on those systems can be a non-trivial"
" task."
msgstr ""
"``Makefile`` 也是自动生成的。在大多数POSIX系统中都内置了 ``make`` 命令,"
"无需安装即可使用。但在非POSIX系统例如Windows中并没有 ``make`` ,在这些"
"系统中安装 ``make`` 则往往比较麻烦。"
#: ../../publish.rst:156 68c38c3eb34e4e6ca9cd4a2d3646d5cb
msgid ""
"If you want to use ``make`` to generate your site using the settings in "
"``pelicanconf.py``, run::"
msgstr ""
"使用 ``make`` 命令是以 ``pelicanconf.py`` 作为配置文件来生成站点的:"
#: ../../publish.rst:161 133e6e1ebf92412a85eedbe56e0b91af
msgid ""
"To generate the site for production, using the settings in "
"``publishconf.py``, run::"
msgstr ""
"使用 ``publishconf.py`` 作为配置文件来为生产环境生成站点:"
#: ../../publish.rst:177 f4e250949c2145ceb03b65c875767abc
msgid ""
"Normally you would need to run ``make regenerate`` and ``make serve`` in "
"two separate terminal sessions, but you can run both at once via::"
msgstr ""
"一般来说, ``make regenerate`` 和 ``make serve`` 需要在分别在单独的终端会话中"
"运行,下面的命令相当于同时运行上述两个命令:"
#: ../../publish.rst:182 1f83bbcf60134eef959370bb5ca402d9
msgid ""
"The above command will simultaneously run Pelican in regeneration mode as"
" well as serve the output at http://localhost:8000."
msgstr ""
"上面的命令会让Pelican在重生成模式下持续运行同样地您可以通过 "
"http://localhost:8000 访问生成的站点。"
#: ../../publish.rst:185 9274a68b1e3b4639bf638a044eda613d
msgid ""
"When you're ready to publish your site, you can upload it via the "
"method(s) you chose during the ``pelican-quickstart`` questionnaire. For "
"this example, we'll use rsync over ssh::"
msgstr ""
"当准备好发布站点时,可以使用在 ``pelican-quickstart`` 过程中选择的方法进行上传。"
"下面的例子使用rsync在ssh上完成这一工作"
#: ../../publish.rst:191 9d7e7927c183491f981aacebe14e5bf1
msgid "That's it! Your site should now be live."
msgstr "OK您的站点现在已经可以访问了。"
#: ../../publish.rst:193 8f570acd5f494f5b9645fdbca6db6fbb
msgid ""
"(The default ``Makefile`` and ``devserver.sh`` scripts use the ``python``"
" and ``pelican`` executables to complete its tasks. If you want to use "
"different executables, such as ``python3``, you can set the ``PY`` and "
"``PELICAN`` environment variables, respectively, to override the default "
"executable names.)"
msgstr ""
"(默认的 ``Makefile`` 和 ``devserver.sh`` 脚本执行 ``python`` 和 ``pelican`` "
"来完成任务。若您希望使用其他的可执行文件,例如 ``python3`` ,设置环境变量 ``PY`` "
"和 ``PELICAN`` 来覆盖默认的可执行文件名)"

View file

@ -0,0 +1,151 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-25 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../quickstart.rst:2 e5f32d61440744aab3f878488ef9e1e3
msgid "Quickstart"
msgstr "快速开始"
#: ../../quickstart.rst:4 d3762ec7c3934f85b25b04cf4024a90c
msgid ""
"Reading through all the documentation is highly recommended, but for the "
"truly impatient, following are some quick steps to get started."
msgstr ""
"强烈建议将所有文档完整地看一遍,但如果您目前没空,下面的步骤可以帮助您快速开始"
"使用Pelican。"
#: ../../quickstart.rst:8 c5982d5ecf7c445590254370b84995be
msgid "Installation"
msgstr "安装"
#: ../../quickstart.rst:10 fda7d08c05f14e2fa0c07a4a1d216db5
msgid ""
"Install Pelican (and optionally Markdown if you intend to use it) on "
"Python |min_python| by running the following command in your preferred "
"terminal, prefixing with ``sudo`` if permissions warrant::"
msgstr ""
"在命令行中执行下面的命令以安装Pelican如果您需要Markdown支持的话也可以同时安装之。"
"Pelican需要使用 |min_python| 以上版本的Python。在必要情况下请在命令前加上 ``sudo`` 。"
#: ../../quickstart.rst:17 9db650d9dc9d4ac48df4dd9fc0a246ac
msgid "Create a project"
msgstr "创建项目"
#: ../../quickstart.rst:19 2e9a72a878754604abdb27d9ec37937e
msgid ""
"First, choose a name for your project, create an appropriately-named "
"directory for your site, and switch to that directory::"
msgstr ""
"首先,给您的项目想个名字,并以合适的名字创建一个文件夹来存放您的站点。"
"接着,进入这个新创建的文件夹:"
#: ../../quickstart.rst:25 da759420dd8440b485936a5a054f142a
msgid ""
"Create a skeleton project via the ``pelican-quickstart`` command, which "
"begins by asking some questions about your site::"
msgstr ""
"通过 ``pelican-quickstart`` 命令创建一个项目的框架,执行这个命令后,"
"您需要输入一些站点相关的信息:"
#: ../../quickstart.rst:30 eb2d702c9f5a4981a93f805e98674cfe
msgid ""
"For questions that have default values denoted in brackets, feel free to "
"use the Return key to accept those default values [#tzlocal_fn]_. When "
"asked for your URL prefix, enter your domain name as indicated (e.g., "
"``https://example.com``)."
msgstr ""
"对于那些在括号中写了默认值的问题,完全可以直接回车以使用预设值 [#tzlocal_fn]_。"
"在输入站点URL的前缀prefix请根据提示的格式输入站点的域名例如 "
"``https://example.com``)。"
#: ../../quickstart.rst:36 66d29d63cce0488a8ec9e43ce97035f9
msgid "Create an article"
msgstr "创作文章"
#: ../../quickstart.rst:38 03af35552ef84e4491b46d8bf8c0f51e
msgid ""
"You cannot run Pelican until you have created some content. Use your "
"preferred text editor to create your first article with the following "
"content::"
msgstr ""
"您可以使用喜欢的文本编辑器来创建第一篇文章。下面是一个样例,可以将它作为您的第一篇文章:"
#: ../../quickstart.rst:47 165d46a3f9da4f949375c70115fdeb3b
msgid ""
"Given that this example article is in Markdown format, save it as "
"``~/projects/yoursite/content/keyboard-review.md``."
msgstr ""
"上面这篇文章是以Markdown的格式完成的一定要将其保存在站点目录的content文件夹下例如 "
"``~/projects/yoursite/content/keyboard-review.md``。"
#: ../../quickstart.rst:51 5cc306848439434f81708eddee812f0e
msgid "Generate your site"
msgstr "生成站点"
#: ../../quickstart.rst:53 03037d0c3b0b4a64b957f8284f008c9d
msgid ""
"From your project root directory, run the ``pelican`` command to generate"
" your site::"
msgstr ""
"在项目的根目录下,直接运行命令 ``pelican`` 就可以生成您自己的站点了:"
#: ../../quickstart.rst:57 abadae17b6f94e36b8603bad69f6e24f
msgid ""
"Your site has now been generated inside the ``output/`` directory. (You "
"may see a warning related to feeds, but that is normal when developing "
"locally and can be ignored for now.)"
msgstr ""
"站点会生成在 ``output/`` 目录下。此时可能会显示和feeds有关的警告这和当前的"
"本地开发环境有关,目前可以忽略之)"
#: ../../quickstart.rst:62 7cf36e609f544f02a0c800f8412cf79c
msgid "Preview your site"
msgstr "预览站点"
#: ../../quickstart.rst:64 1a64015c5cc9401bac0a6ac953164fb3
msgid ""
"Open a new terminal session, navigate to your project root directory, and"
" run the following command to launch Pelican's web server::"
msgstr ""
"打开一个新的命令行进入刚才项目的根目录执行下面的命令以运行一个Pelican web服务器"
#: ../../quickstart.rst:69 eb286b4785304d22a46e90884d26de07
msgid "Preview your site by navigating to http://localhost:8000/ in your browser."
msgstr "打开浏览器,进入 http://localhost:8000/ 就可以看到刚刚生成的站点了。"
#: ../../quickstart.rst:71 1dc30b5cb267402c9da251303ff59dbf
msgid ""
"Continue reading the other documentation sections for more detail, and "
"check out the Pelican wiki's Tutorials_ page for links to community-"
"published tutorials."
msgstr ""
"请继续阅读文档中的其他部分来了解Pelican的更多用法也可以前往Pelican的"
"wiki 教程_ 页面获取社区发布的教程。"
#: ../../quickstart.rst:78 6c135ea1cbb44400b446c0f9074e0fc5
msgid "Footnotes"
msgstr "脚注"
#: ../../quickstart.rst:80 911df4217fd94e6184502153ed0e53dc
msgid ""
"You can help localize default fields by installing the optional `tzlocal "
"<https://pypi.org/project/tzlocal/>`_ module."
msgstr ""
"您可以安装可选模块 `tzlocal <https://pypi.org/project/tzlocal/>`_ 来"
"本地化默认字段。"

View file

@ -0,0 +1,249 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../report.rst:2 bc25575efa494c7b9455e02eb5c514ab
msgid "Some history about Pelican"
msgstr "Pelican的一些历史"
#: ../../report.rst:6 959bbe068d2e4fd19e48be22706070d2
msgid ""
"This page comes from a report the original author (Alexis Métaireau) "
"wrote right after writing Pelican, in December 2010. The information may "
"not be up-to-date."
msgstr ""
"此页面来自原作者 Alexis Métaireau 在2010年12月完成Pelican后作的一篇报告因此"
"其中涉及的具体内容可能和最新的Pelican有些出入。"
#: ../../report.rst:10 598beb4776eb4a7bb1c928979752b1f1
msgid ""
"Pelican is a simple static blog generator. It parses markup files "
"(Markdown or reStructuredText for now) and generates an HTML folder with "
"all the files in it. I've chosen to use Python to implement Pelican "
"because it seemed to be simple and to fit to my needs. I did not wanted "
"to define a class for each thing, but still wanted to keep my things "
"loosely coupled. It turns out that it was exactly what I wanted. From "
"time to time, thanks to the feedback of some users, it took me a very few"
" time to provide fixes on it. So far, I've re-factored the Pelican code "
"by two times; each time took less than 30 minutes."
msgstr ""
"Pelican是一个简单的静态博客生成器。它解析标记文件目前主要是Markdown和"
"reStructuredText并生成一个文件夹其中包含了对应于标记文件的HTML。由于Python"
"很简单并且符合需求我选择使用Python来实现Pelican。我不想为每个东西定义一个类"
"但同时又想要各部件之间低耦合。事实证明,这正是我想要的。在发展过程中,多亏了用户"
"给的反馈我花了些时间修复了一些问题。到目前为止我已经将Pelican的代码重构了两次"
"每次重构都不会超过30分钟。"
#: ../../report.rst:21 1709ab99c3144cb692afd1d1bc388921
msgid "Use case"
msgstr "使用场景"
#: ../../report.rst:23 119f315a8e6c409d98783a636ac2147c
msgid ""
"I was previously using WordPress, a solution you can host on a web server"
" to manage your blog. Most of the time, I prefer using markup languages "
"such as Markdown or reStructuredText to type my articles. To do so, I use"
" vim. I think it is important to let the people choose the tool they want"
" to write the articles. In my opinion, a blog manager should just allow "
"you to take any kind of input and transform it to a weblog. That's what "
"Pelican does. You can write your articles using the tool you want, and "
"the markup language you want, and then generate a static HTML weblog."
msgstr ""
"我之前使用的是WordPress你可以将它部署在Web服务器上来管理博客。大多数时候"
"我更喜欢使用Markdown或reStructuredText等标记语言来撰写文章。为此我一般用vim"
"来写这些文章。我认为让大家自行选择用于写文章的工具是很重要的。在我看来,博客管理器"
"应该能够接受任何类型的输入并将其转换为博客站。Pelican就采取这一思想。您可以选择自己"
"喜欢的工具以及标记语言来撰写文章然后生成静态的HTML博客站。"
#: ../../report.rst:34 1a087a07690c4c35873a7f4ce18ba52b
msgid ""
"To be flexible enough, Pelican has template support, so you can easily "
"write your own themes if you want to."
msgstr ""
"为了足够的灵活性Pelican中支持使用模板这样你就可以编写自己的主题了。"
#: ../../report.rst:38 fca5a0962a0d4c27aa163f2aec94b1cf
msgid "Design process"
msgstr "设计过程"
#: ../../report.rst:40 073dd0b024fa4701acc0078b84c45648
msgid ""
"Pelican came from a need I have. I started by creating a single file "
"application, and I have make it grow to support what it does by now. To "
"start, I wrote a piece of documentation about what I wanted to do. Then, "
"I created the content I wanted to parse (the reStructuredText files) and "
"started experimenting with the code. Pelican was 200 lines long and "
"contained almost ten functions and one class when it was first usable."
msgstr ""
"Pelican来源于我的需求。从单文件应用程序出发不断成长为现在功能丰富的应用。首先我"
"写了一份需求文档然后创建了我想要解析的内容reStructuredText文件并开始"
"实验性的编写代码。Pelican的第一个能够使用的版本包含了200行代码、10个函数以及1个类。"
#: ../../report.rst:47 f407fc9ad9434f1082014eeca8c4cc89
msgid ""
"I have been facing different problems all over the time and wanted to add"
" features to Pelican while using it. The first change I have done was to "
"add the support of a settings file. It is possible to pass the options to"
" the command line, but can be tedious if there is a lot of them. In the "
"same way, I have added the support of different things over time: Atom "
"feeds, multiple themes, multiple markup support, etc. At some point, it "
"appears that the \"only one file\" mantra was not good enough for "
"Pelican, so I decided to rework a bit all that, and split this in "
"multiple different files."
msgstr ""
"我不断遇到各种问题在使用过程中还想要往Pelican中添加功能。在对代码的第一次修改中"
"添加了对配置文件的支持。虽然可以在命令行中往里传入选项,但当配置项多起来后,就会变得"
"异常冗长。同样地Pelican支持了越来越多的功能Atom订阅源、多主体支持、多标记语言"
"支持等等。在某一时刻单文件应用已经不适合Pelican了因此我决定多做些工作将应用分离"
"到多个文件中。"
#: ../../report.rst:56 57b3d1ba492646e28e20396b78df8ea0
msgid "Ive separated the logic in different classes and concepts:"
msgstr "我将系统整体逻辑分为如下几个类和概念:"
#: ../../report.rst:58 2d4090dba6674569a7e1088919185aa5
msgid ""
"*writers* are responsible of all the writing process of the files. They "
"are responsible of writing .html files, RSS feeds and so on. Since those "
"operations are commonly used, the object is created once, and then passed"
" to the generators."
msgstr ""
"**Writers** 负责文件的写入工作,即负责完成 html、RSS订阅源等文件的写入。因为这些"
"操作都是比较常用的这个类只会被创建一次然后再传给Generators。"
#: ../../report.rst:63 a4cff6dceb8f430791edaeb3b2280924
msgid ""
"*readers* are used to read from various formats (Markdown and "
"reStructuredText for now, but the system is extensible). Given a file, "
"they return metadata (author, tags, category, etc) and content (HTML "
"formatted)."
msgstr ""
"**Readers** 用于读取不同格式的文件目前支持Markdown、reStructuredText"
"但可以继续扩展)。向 **Readers** 输入一个文件,它会返回文档的元数据(作者、标签、"
"分类等等与HTML格式的文档正文内容。"
#: ../../report.rst:67 6ed9719c06c2477ea05ea30e4806ad14
msgid ""
"*generators* generate the different outputs. For instance, Pelican comes "
"with an ArticlesGenerator and PagesGenerator, into others. Given a "
"configuration, they can do whatever you want them to do. Most of the time"
" it's generating files from inputs (user inputs and files)."
msgstr ""
"**Generators** 用以生成不同的输出Pelican自带了 ``ArticlesGenerator`` 和 "
"``PageGenerator`` 。给定一套配置信息, **Generators** 可以做几乎任何事。"
"但大多数情况下,它的工作就是从输入生成文件。"
#: ../../report.rst:72 cb5129c105b04d788a908f580a83e7e1
msgid ""
"I also deal with contents objects. They can be ``Articles``, ``Pages``, "
"``Quotes``, or whatever you want. They are defined in the ``contents.py``"
" module and represent some content to be used by the program."
msgstr ""
"同样,还要处理正文对象。正文对象可以是 ``Articles`` 、 ``Pages`` 、 ``Quotes`` "
"或者其他你想要的类型。这些对象在 ``contents.py`` 模块中完成定义,同时代表了应用中"
"使用到的内容。"
#: ../../report.rst:77 4123da2b628448359aa9ed20b2ca87d2
msgid "In more detail"
msgstr "更细节的内容"
#: ../../report.rst:79 8482492940524edf8244fc220553cd3c
msgid "Here is an overview of the classes involved in Pelican."
msgstr "以下是Pelican中涉及的类的概述。"
#: ../../report.rst:83 a8a39a1ccc154604b8bb000dff44982d
msgid ""
"The interface does not really exist, and I have added it only to clarify "
"the whole picture. I do use duck typing and not interfaces."
msgstr ""
"上图中的接口事实上并不存在,我是为了整张图的完整性才加上去的。在实际实现中,使用了"
"鸭子类型而不是接口。"
#: ../../report.rst:86 889dfae0dc4242f0b21ce831c7172001
msgid "Internally, the following process is followed:"
msgstr "应用内部按以下流程进行处理:"
#: ../../report.rst:88 fc5cbf8ca65c456c90c56c00cf5ab93f
msgid ""
"First of all, the command line is parsed, and some content from the user "
"is used to initialize the different generator objects."
msgstr ""
"首先解析命令行并根据用户给入的一些内容来初始化不同的generator对象。"
#: ../../report.rst:91 5d0c1dc643364248820fad76c204f663
msgid ""
"A ``context`` is created. It contains the settings from the command line "
"and a settings file if provided."
msgstr ""
"创建一个 ``context`` ,其中包含了来自命令行和文件的配置信息。"
#: ../../report.rst:93 36725875f2c14e0bb8fc60b16afa1367
msgid ""
"The ``generate_context`` method of each generator is called, updating the"
" context."
msgstr ""
"调用各generator对象的 ``generate_context`` 方法来更新 ``context`` 。"
#: ../../report.rst:95 d50a4b2e38884eb38f1b66fdf7fb1eda
msgid ""
"The writer is created and given to the ``generate_output`` method of each"
" generator."
msgstr ""
"创建 **Writers** 并将其给入generator的 ``generate_output`` 方法。"
#: ../../report.rst:98 da8d9096940044f2849112fb5efcb4cb
msgid ""
"I make two calls because it is important that when the output is "
"generated by the generators, the context will not change. In other words,"
" the first method ``generate_context`` should modify the context, whereas"
" the second ``generate_output`` method should not."
msgstr ""
"由于当generator生成输出时并不会改变上下文我进行了两次调用。换句话说第一个方法 "
"``generate_context`` 会修改上下文,而第二个方法 ``generate_output`` 不会。"
#: ../../report.rst:103 a6350edba931463fb92ae51dd9bc253a
msgid ""
"Then, it is up to the generators to do what the want, in the "
"``generate_context`` and ``generate_content`` method. Taking the "
"``ArticlesGenerator`` class will help to understand some others concepts."
" Here is what happens when calling the ``generate_context`` method:"
msgstr ""
"然后事情就取决于各generator在 ``generate_context`` 和 ``generate_content`` "
"中做的操作了。拿 ``ArticlesGenerator`` 举例可以帮助理解其他的一些概念。下面是调用 "
"``generate_context`` 方法后会发生的事情:"
#: ../../report.rst:108 4b99ddf2cf344d0b8fbd080c15adfb64
msgid ""
"Read the folder “path”, looking for restructured text files, load each of"
" them, and construct a content object (``Article``) with it. To do so, "
"use ``Reader`` objects."
msgstr ""
"读取文件夹路径查找并加载每个restructured文件并为每个文件构建一个正文内容对象 "
"``Article`` )。此工作是由 ``Reader`` 对象完成的。"
#: ../../report.rst:111 176a7a5896904f2e9929623ef652660b
msgid "Update the ``context`` with all those articles."
msgstr "根据所有的文章更新 ``context`` 。"
#: ../../report.rst:113 bb88942c85004c4c9e0b55a72076b18f
msgid ""
"Then, the ``generate_content`` method uses the ``context`` and the "
"``writer`` to generate the wanted output."
msgstr ""
"然后, ``generate_content`` 方法使用 ``context`` 和 ``writer`` 来生成想要的输出。"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
#: ../../_templates/page.html:68 697aead398874e06aa15cfd74d134745
msgid "Back to top"
msgstr "返回顶部"
#: ../../_templates/page.html:101 f91a64e54aae49c2bd09a944ea693193
msgid "Next"
msgstr "下一节"
#: ../../_templates/page.html:113 6c3ad069077b4e2cb6e1f77cc2962881
msgid "Previous"
msgstr "前一节"
#: ../../_templates/page.html:116 e83e03d0b50c4065a9f87db25a23b3ee
msgid "Home"
msgstr "首页"
#: ../../_templates/page.html:129 1d0fdb4c0b4e420283101ba5c21ac985
#, python-format
msgid "<a href=\"%(path)s\">Copyright</a> &#169; %(copyright)s"
msgstr "<a href=\"%(path)s\">Copyright</a> &#169; %(copyright)s"
#: ../../_templates/page.html:133 0a35c662e6574da48f7ac5c6b2c82874
#, python-format
msgid ""
"Copyright &#169; %(copyright)s, <a "
"href=\"https://justinmayer.com\">Justin Mayer</a>, Alexis Metaireau, and "
"contributors"
msgstr ""
"Copyright &#169; %(copyright)s, <a "
"href=\"https://justinmayer.com\">Justin Mayer</a>, Alexis Metaireau, and "
"contributors"
#: ../../_templates/page.html:141 07b89372db484251bfcd3b54e0845bf0
#, python-format
msgid "Last updated on %(last_updated)s"
msgstr "最后更新于 %(last_updated)s"
#: ../../_templates/page.html:187 2eb9f1b479a7405290a91d8e1962f265
msgid "On this page"
msgstr "本页目录"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,723 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 20102024
# This file is distributed under the same license as the PELICAN package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PELICAN 4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-07 16:25+0800\n"
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
"Language: zh_CN\n"
"Language-Team: zh_CN <LL@li.org>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.16.0\n"
#: ../../tips.rst:2 9c4618aaecd44b0d93537cb760e227fa
msgid "Tips"
msgstr "小技巧"
#: ../../tips.rst:4 f49ab5e1ef034ca29140bac3832e8e1c
msgid "Here are some tips about Pelican that you might find useful."
msgstr "以下是一些实用的小技巧。"
#: ../../tips.rst:7 ../../tips.rst:309 95bea35d0347495bb551fe9486bcd29d
#: b64b7ed713b64f588ea7488c6d0b0441
msgid "Custom 404 Pages"
msgstr "自定义404页面"
#: ../../tips.rst:9 d59dc30de5954aa1abc7c46fbac596c6
msgid ""
"When a browser requests a resource that the web server cannot find, the "
"web server usually displays a generic \"File not found\" (404) error page"
" that can be stark and unsightly. One way to provide an error page that "
"matches the theme of your site is to create a custom 404 page (*not* an "
"article), such as this Markdown-formatted example stored in "
"``content/pages/404.md``::"
msgstr ""
"当浏览器请求的资源无法在服务器中找到时web服务器常常会显示一个通用的“File not found "
"404”的错误页面这可能会不太美观。为了能使用一个与站点主题相匹配的404页面注意是页面而 **不是** "
"文章例如下面这个Markdown格式的例子将此文件存为了 ``content/pages/404.md`` "
#: ../../tips.rst:22 416f9b3eeaac4af8bdc9f32b7cdcba39
msgid ""
"The next step is to configure your web server to display this custom page"
" instead of its default 404 page. For Nginx, add the following to your "
"configuration file's ``location`` block::"
msgstr ""
"接下来就是要配置web服务器使其显示此自定义页面而不是默认的404页面。例如对于Nginx在配置文件的 ``location`` "
"块中添加下面的命令:"
#: ../../tips.rst:28 5d52fbcc9d9d4603b3f9d97360face10
msgid "For Apache::"
msgstr "对于Apache"
#: ../../tips.rst:32 5413c6bcff6a41688ffcede94b9955e4
msgid ""
"For Amazon S3, first navigate to the ``Static Site Hosting`` menu in the "
"bucket settings on your AWS console. From there::"
msgstr "对于Amazon S3实例先在控制台的设置中找到 ``Static Site Hosting`` ,并添加:"
#: ../../tips.rst:38 9b02aa39367a4c33918bddef02d1788d
msgid "Publishing to GitHub Pages"
msgstr "发布到GitHub Pages"
#: ../../tips.rst:40 ca3f1deb69a04d40a89576f580d63781
msgid ""
"If you use `GitHub <https://github.com/>`_ for your Pelican site you can "
"publish your site to `GitHub Pages <https://pages.github.com/>`_ for "
"free. Your site will be published to ``https://<username>.github.io`` if "
"it's a user or organization site or to "
"``https://<username>.github.io/<repository>`` if it's a project site. "
"It's also possible to `use a custom domain with GitHub Pages "
"<https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-"
"github-pages-site>`_."
msgstr ""
"如果将Pelican站点放在了 `GitHub <https://github.com/>`_ 上,那么你就可以将站点免费发布在 `GitHub "
"Pages <https://pages.github.com/>`_ 上。如果是用户或组织的站点,发布的地址为 "
"``https://<username>.github.io`` ;如果是某个项目的站点,发布的地址则为 "
"``https://<username>.github.io/<repository>`` 。当然也可以 `在GitHub "
"Pages上使用自定义域名 <https://docs.github.com/en/pages/configuring-a-custom-"
"domain-for-your-github-pages-site>`_ 。"
#: ../../tips.rst:46 5962c3cb4a0b41289d6b08b9edd2fdee
msgid ""
"There are `two ways to publish a site to GitHub Pages "
"<https://docs.github.com/en/pages/getting-started-with-github-"
"pages/configuring-a-publishing-source-for-your-github-pages-site>`_:"
msgstr ""
"总的来说,有 `两种将站点发布到GitHub Pages的方法 <https://docs.github.com/en/pages"
"/getting-started-with-github-pages/configuring-a-publishing-source-for-"
"your-github-pages-site>`_ "
#: ../../tips.rst:48 ad6f071b3cdc4529a41776f799347da0
msgid ""
"**Publishing from a branch:** run ``pelican`` locally and push the output"
" directory to a special branch of your GitHub repo. GitHub will then "
"publish the contents of this branch to your GitHub Pages site."
msgstr ""
"**从某一分支发布:** 在本地运行 ``pelican`` "
"后将输出文件夹push到GitHub仓库的某一分支。GitHub就会将该分支的内容发布到GitHub Pages上。"
#: ../../tips.rst:51 6237e147cf4142d9b172588964ec00d2
msgid ""
"**Publishing with a custom GitHub Actions workflow:** just push the "
"source files of your Pelican site to your GitHub repo's default branch "
"and have a custom GitHub Actions workflow run ``pelican`` for you to "
"generate the output directory and publish it to your GitHub Pages site. "
"This way you don't need to run ``pelican`` locally. You can even edit "
"your site's source files using GitHub's web interface and any changes "
"that you commit will be published."
msgstr ""
"**从自定义GitHub Actions工作流发布** 将内容源文件推送到GitHub仓库的默认分支然后在GitHub "
"Actions工作流中执行 ``pelican`` 以生成输出文件夹最后将其发布到你的GitHub Pages站点。此种方法下就无需在本地执行 "
"``pelican`` 命令了。甚至可以直接在GitHub的网页中在线修改站点内容源文件。"
#: ../../tips.rst:60 f2655b8ab23147e58fd68e2385a7624a
msgid "Publishing a Project Site to GitHub Pages from a Branch"
msgstr "从某一分支发布项目站点到GitHub Pages"
#: ../../tips.rst:62 1a156c5a8019400d86a33ce306b521ac
msgid ""
"To publish a Pelican site as a Project Page you need to *push* the "
"content of the ``output`` dir generated by Pelican to a repository's "
"``gh-pages`` branch on GitHub."
msgstr ""
"要将Pelican站点发布为项目页面你需要将Pelican生成的 ``output`` 目录 **push** 到GitHub仓库的 ``gh-"
"pages`` 分支。"
#: ../../tips.rst:66 22caeeba90b24dbe9f0305370de074fc
msgid ""
"The excellent `ghp-import <https://github.com/davisp/ghp-import>`_, which"
" can be installed with ``pip``, makes this process really easy."
msgstr ""
"可通过 ``pip`` 安装的 `ghp-import <https://github.com/davisp/ghp-import>`_ "
"使这一步变得非常简单。"
#: ../../tips.rst:69 6ea08af050644b58ae5255dafb4f4d8b
msgid ""
"For example, if the source of your Pelican site is contained in a GitHub "
"repository, and if you want to publish that Pelican site in the form of "
"Project Pages to this repository, you can then use the following::"
msgstr "例如当Pelican站点的源文件已经包含在GitHub仓库中时可以将其作为此仓库的项目页面"
#: ../../tips.rst:77 355b81e8a2194cf9b91bee0f4ee6dca9
msgid ""
"The ``ghp-import output`` command updates the local ``gh-pages`` branch "
"with the content of the ``output`` directory (creating the branch if it "
"doesn't already exist). The ``git push origin gh-pages`` command updates "
"the remote ``gh-pages`` branch, effectively publishing the Pelican site."
msgstr ""
"``ghp-import output`` 命令会用 ``output`` 目录下的内容更新本地的 ``gh-pages`` "
"分支(如果此分支不存在则会先创建)。接着再用 ``git push origin gh-pages`` 命令更新远程分支 ``gh-"
"pages`` 如此就能够发布Pelican站点了。"
#: ../../tips.rst:84 8a3fd725eba44fa99541376722601cce
msgid ""
"The ``github`` target of the Makefile (and the ``gh_pages`` task of "
"``tasks.py``) created by the ``pelican-quickstart`` command publishes the"
" Pelican site as Project Pages, as described above."
msgstr ""
"``pelican-quickstart`` 在Makefile文件中所生成的 ``github`` 目标(以及为 ``gh_pages`` "
"任务生成的 ``tasks.py`` 使得Pelican站点能像上面描述的那样被发布为项目页面。"
#: ../../tips.rst:89 e8ebf23099ed45e7a65d23b9a7e4ccbd
msgid "Publishing a User Site to GitHub Pages from a Branch"
msgstr "从某一分支发布用户站点到GitHub Pages"
#: ../../tips.rst:91 7dc8ae1992b7411d9d6db7cc4a0127cb
msgid ""
"To publish a Pelican site in the form of User Pages, you need to *push* "
"the content of the ``output`` dir generated by Pelican to the ``main`` "
"branch of your ``<username>.github.io`` repository on GitHub."
msgstr ""
"要以用户页面形式发布Pelican站点你需要将Pelican生成的 ``output`` 目录内容 **push** 到 "
"``<username>.github.io`` 仓库的 ``master`` 分支上。"
#: ../../tips.rst:95 da706340ef5f4d18bfb183596a4196c9
msgid "Again, you can take advantage of ``ghp-import``::"
msgstr "同样的,此处也可以使用 ``ghp-import`` "
#: ../../tips.rst:101 61aa6f0d9fdf407682d3f781ae5475c6
msgid ""
"The ``git push`` command pushes the local ``gh-pages`` branch (freshly "
"updated by the ``ghp-import`` command) to the ``elemoine.github.io`` "
"repository's ``main`` branch on GitHub."
msgstr ""
"``git push`` 命令将本地的 ``gh-pages`` 分支(此分支在刚刚通过 ``ghp-import`` "
"命令进行了更新push到了GitHub仓库 ``elemoine.github.io`` 的 ``master`` 分支。"
#: ../../tips.rst:107 f74afbf668a1472d901fe0a16472ab98
msgid ""
"To publish your Pelican site as User Pages, feel free to adjust the "
"``github`` target of the Makefile."
msgstr "要将Pelican站点发布为用户页面可以根据需要修改Makefile中的 ``github`` 目标。"
#: ../../tips.rst:110 d69dcdb58a4b4b38aa8b8bf8e4fd733a
msgid ""
"Another option for publishing to User Pages is to generate the output "
"files in the root directory of the project."
msgstr "发布用户页面的另一种方法就是将输出文件生成在项目的根目录下。"
#: ../../tips.rst:113 4991892f24df40b982faf01ddb292175
msgid ""
"For example, your main project folder is ``<username>.github.io`` and you"
" can create the Pelican project in a subdirectory called ``Pelican``. "
"Then from inside the ``Pelican`` folder you can run::"
msgstr ""
"例如,项目的主文件夹是 ``<username>.github.io`` ,你可以在子目录 ``Pelican`` "
"中创建一个Pelican项目。然后你可以在这个 ``Pelican`` 文件夹中执行下面的命令:"
#: ../../tips.rst:119 ca5939f8c58b44b69ebfb2f953a4a73b
msgid ""
"Now you can push the whole project ``<username>.github.io`` to the main "
"branch of your GitHub repository::"
msgstr "接着可以将整个项目 ``<username>.github.io`` push到GitHub仓库的master分支中"
#: ../../tips.rst:124 54962439805d47abb121ca9454e7a4cc
msgid "(assuming origin is set to your remote repository)."
msgstr "此处假设远程仓库命名为origin。"
#: ../../tips.rst:127 b3fe320a90904fbda8c7ed8c7bddbd6e
msgid "Publishing to GitHub Pages Using a Custom GitHub Actions Workflow"
msgstr "使用自定义GitHub Actions工作流将站点发布GitHub Pages中"
#: ../../tips.rst:129 3b368bc0a307473dae560671fd9527be
msgid ""
"Pelican-powered sites can be published to GitHub Pages via a `custom "
"workflow "
"<https://github.com/getpelican/pelican/blob/main/.github/workflows/github_pages.yml>`_."
" To use it:"
msgstr ""
"Pelican已经给你准备了一份 `自定义工作流 "
"<https://github.com/getpelican/pelican/blob/main/.github/workflows/github_pages.yml>`_"
" ,你可以直接使用此工作流发布站点:"
#: ../../tips.rst:133 a7b1be522b694d9a8beb186b4603a7aa
msgid ""
"Enable GitHub Pages in your repo: go to **Settings → Pages** and choose "
"**GitHub Actions** for the **Source** setting."
msgstr ""
"首先为仓库开启GitHub Pages **Settings → Pages** 中有个 **Source** 设置项,将其选择为 "
"**GitHub Actions** 。"
#: ../../tips.rst:136 9cc114d8a6b44ff49fa7fecbdbcd012f
msgid ""
"Commit a ``.github/workflows/pelican.yml`` file to your repo with these "
"contents:"
msgstr "往你的仓库中commit一个 ``.github/workflows/pelican.yml`` 文件,文件内容如下:"
#: ../../tips.rst:155 f7d029425d7047deae43e9506c7f4779
msgid ""
"You may want to replace the ``@main`` with the ID of a specific commit in"
" this repo in order to pin the version of the reusable workflow that "
"you're using: ``uses: "
"getpelican/pelican/.github/workflows/github_pages.yml@<COMMIT_ID>``. If "
"you do this you might want to get Dependabot to send you automated pull "
"requests to update that commit ID whenever new versions of this workflow "
"are published, like so:"
msgstr ""
"你可能想要将 ``@main`` 替换为这个仓库中某个特定commit的ID以便将你使用的可重用工作流的版本固定下来此时可以使用 "
"``uses: "
"getpelican/pelican/.github/workflows/github_pages.yml@<COMMIT_ID>`` "
"。在这种情况下你可能想让Dependabot自动向你发送PR以便在发布新版本的工作流时更新commit ID如下所示:"
#: ../../tips.rst:172 fd060b5d5d824ab8825b384d37872894
msgid ""
"See `GitHub's docs about using Dependabot to keep your actions up to date"
" <https://docs.github.com/en/code-security/dependabot/working-with-"
"dependabot/keeping-your-actions-up-to-date-with-dependabot>`_."
msgstr ""
"请参阅 `GitHub文档 <https://docs.github.com/en/code-security/dependabot"
"/working-with-dependabot/keeping-your-actions-up-to-date-with-"
"dependabot>`_ 了解如何使用Dependabot使您的action保持最新。"
#: ../../tips.rst:174 1b862876e15c4fcd898c4d9b3ba616c5
msgid ""
"Go to the **Actions** tab in your repo "
"(``https://github.com/<username>/<repository>/actions``) and you should "
"see a **Deploy to GitHub Pages** action running."
msgstr ""
"选中仓库的 **Actions** 标签栏( "
"``https://github.com/<username>/<repository>/actions`` ),此时你应该会看到已经有一个名为 "
"**Deploy to GitHub Pages** 的action正在运行。"
#: ../../tips.rst:178 f8413793636140f9b017abad379b3429
msgid ""
"Once the action completes you should see your Pelican site deployed at "
"your repo's GitHub Pages URL: ``https://<username>.github.io`` for a user"
" or organization site or ``https://<username>.github.io/<repository>>`` "
"for a project site."
msgstr ""
"当此action执行完成就能够通过仓库的GitHub Pages地址 ``https://<username>.github.io`` "
"看到部署好了的用户或组织站点了,对于项目站点,可通过 ``https://<username>.github.io/<repository>`` "
"访问。"
#: ../../tips.rst:183 d792bb046c474f70aa98b2c16a5b1254
msgid "Notes:"
msgstr "注意事项:"
#: ../../tips.rst:185 89472d2b7231439faf9e51eda07d8323
msgid ""
"You don't need to set ``SITEURL`` or ``FEED_DOMAIN`` in your Pelican "
"settings: the workflow will set them correctly for you"
msgstr "无需在Pelican配置文件中设置 ``SITEURL`` ,工作流会帮你进行设置。"
#: ../../tips.rst:188 ea2b632160804a6e9bf1b4cecb7de716
msgid ""
"You don't need to commit your ``--output`` / ``OUTPUT_PATH`` directory "
"(``output/``) to git: the workflow will run ``pelican`` to build the "
"output directory for you on GitHub Actions"
msgstr ""
"无需commit ``--output`` 或 ``OUTPUT_PATH`` 所指定的目录( ``output/`` ):工作流会自己执行 "
"``pelican`` 命令来构建输出目录。"
#: ../../tips.rst:192 fd9fb772fba844f099cac781f2b0642f
msgid ""
"See `GitHub's docs about reusable workflows "
"<https://docs.github.com/en/actions/using-workflows/reusing-workflows>`_ "
"for more information."
msgstr ""
"更多信息请参阅 `GitHub可重用工作流文档 <https://docs.github.com/en/actions/using-"
"workflows/reusing-workflows>`_ 。"
#: ../../tips.rst:195 f9c527704af24f6da0b4229b7882a25b
msgid ""
"A number of optional inputs can be added to the ``with:`` block when "
"calling the workflow, for example:"
msgstr "有一些可选输入可以添加到工作流的 ``with:`` 块中:"
#: ../../tips.rst:206 956f5bae1fc64096acd2a2540a29004c
msgid "Here's the complete list of workflow inputs:"
msgstr "下面是工作流可用输入参数的完整列表:"
#: ../../tips.rst:209 eb37c894d7bc4278ab1a92e3b82c5603
msgid "Name"
msgstr "名称"
#: ../../tips.rst:209 446faf9e7d544e6aa47d4a1eca506c01
msgid "Required"
msgstr "是否必需"
#: ../../tips.rst:209 de96e4f5cd09488296f97f569fe1fb90
msgid "Description"
msgstr "描述"
#: ../../tips.rst:209 181bbfff09144f5b9c241b2fc79c989d
msgid "Type"
msgstr "值的类型"
#: ../../tips.rst:209 c3d44d1e7be6421a83bae2f5dc6e578f
msgid "Default"
msgstr "默认值"
#: ../../tips.rst:211 305d9d73681b4c6c80161cc906d60bbd
msgid "``settings``"
msgstr "``settings``"
#: ../../tips.rst:211 dbe6210f19914ae3b11e4caec7a945f0
msgid "Yes"
msgstr "是"
#: ../../tips.rst:211 bbd2306b324d4b5eae513cb7a7683286
msgid ""
"The path to your Pelican settings file (``pelican``'s ``--settings`` "
"option), for example: ``\"publishconf.py\"``"
msgstr ""
"Pelican配置文件的路径会被用于 ``pelican`` 命令的 ``--settings`` 选项),例如 "
"``\"publishconf.py\"`` 。"
#: ../../tips.rst:211 ../../tips.rst:216 ../../tips.rst:223 ../../tips.rst:227
#: ../../tips.rst:231 ../../tips.rst:237 ../../tips.rst:243
#: 073e18d8ae29406eb05040d4e3a9ae60 7d43e6cfb091410ebec7464da05b61b4
#: 8837cc8935f148fb80f05cc5d3d53629 b2da1f7640f948039230cd835c49accd
#: bfe3d052cdc443bb81fed82e77acf3c1 c93816e00a254ef69c69f05833e8762b
#: ee35302c7e034070af1d234ab919c32a
msgid "string"
msgstr "string"
#: ../../tips.rst:216 4eab6faa96244f13a09754112a783f2f
msgid "``requirements``"
msgstr "``requirements``"
#: ../../tips.rst:216 ../../tips.rst:223 ../../tips.rst:227 ../../tips.rst:231
#: ../../tips.rst:237 ../../tips.rst:243 ../../tips.rst:249
#: 197d6ee11fce4a50996a0c458cfdbdad 2086d667b9b1475cb0f002924cdfde12
#: 25e940621f5b48c9af487d898d7f93cf 5664232c9fdd46c7b8278b8ecef8e3b1
#: 6693126a0da74c61b67e14ca8e535ec3 7f8a93a2048140748fa73537bfae2a54
#: 85fd40a29f31490bb23b20f05e574aaa
msgid "No"
msgstr "否"
#: ../../tips.rst:216 9d5bdd70e7da4794805180cc758ebe37
msgid ""
"The Python requirements to install, for example to enable markdown and "
"typogrify use: ``\"pelican[markdown] typogrify\"`` or if you have a "
"requirements file: ``\"-r requirements.txt\"``"
msgstr ""
"需要安装的Python模块例如要开启markdown和typogrify可指定 ``\"pelican[markdown] "
"typogrify\"`` 或者可以指定一个requirements文件 ``\"-r requirements.txt\"`` "
#: ../../tips.rst:216 03ad0b322a714032bcce9f56ce66318d
msgid "``\"pelican\"``"
msgstr "``\"pelican\"``"
#: ../../tips.rst:223 e568553782b443dbacecaa7ded4c391c
msgid "``output-path``"
msgstr "``output-path``"
#: ../../tips.rst:223 2920ae9de5a64ae1ad82bd2287fa7c1e
msgid "Where to output the generated files (``pelican``'s ``--output`` option)"
msgstr "生成文件的输出位置(会被用于 ``pelican`` 命令的 ``--output`` 选项)"
#: ../../tips.rst:223 41b90747f0954a5799c8baf4a59d99fd
msgid "``\"output/\"``"
msgstr "``\"output/\"``"
#: ../../tips.rst:227 e2cc62185182463abc5140244a808e6d
msgid "``theme``"
msgstr "``theme``"
#: ../../tips.rst:227 cd3b78d03dcd4554a8ce10a873f5ff9f
msgid ""
"The GitHub repo URL of a custom theme to use, for example: "
"``\"https://github.com/seanh/sidecar.git\"``"
msgstr "要使用的自定义主题的GitHub仓库URL例如 ``\"https://github.com/seanh/sidecar.git\"``"
#: ../../tips.rst:227 d94f331173334fb2a84b1caadffb72df
msgid "``\"\"``"
msgstr "``\"\"``"
#: ../../tips.rst:231 44ceb2743481486b95c1c739d543f15d
msgid "``python``"
msgstr "``python``"
#: ../../tips.rst:231 4b5cddab44d24c7c8560e16991b784c7
msgid ""
"The version of Python to use to build the site, for example: ``\"3.12\"``"
" (to use the most recent version of Python 3.12, this is faster) or "
"``\"3.12.1\"`` (to use an exact version, slower)"
msgstr "构建站点时使用的Python版本例如 ``\"3.12\"`` 或 ``\"3.12.1\"``"
#: ../../tips.rst:231 919c0e36e8ff40bcbcc4480081b49ce5
msgid "``\"3.12\"``"
msgstr "``\"3.12\"``"
#: ../../tips.rst:237 842af56c539f4a74a97c7a5b1525eb35
msgid "``siteurl``"
msgstr "``siteurl``"
#: ../../tips.rst:237 7fc0777d6e174d6f8d757926a61aa3c8
msgid ""
"The base URL of your web site (Pelican's ``SITEURL`` setting). If not "
"passed this will default to the URL of your GitHub Pages site, which is "
"correct in most cases."
msgstr "站点的基URL会用于配置项 ``SITEURL`` 。若未指定默认值为GitHub Pages站点的URL这适用于大部分情况。"
#: ../../tips.rst:237 ../../tips.rst:243 082f65333e224d71817b82b1e4f515c4
#: 3d786e828a4745db849bdb8f47738db8
msgid "The URL of your GitHub Pages site."
msgstr "GitHub Pages站点的URL"
#: ../../tips.rst:243 e5adb69f985547b7b3cc2bd3f31d4cc3
msgid "``feed_domain``"
msgstr "``feed_domain``"
#: ../../tips.rst:243 c88f037c9f1f4148bef6347228257f7d
msgid ""
"The domain to be prepended to feed URLs (Pelican's ``FEED_DOMAIN`` "
"setting). If not passed this will default to the URL of your GitHub Pages"
" site, which is correct in most cases."
msgstr ""
"订阅源URL前要附加的域名会用于配置项 ``FEED_DOMAIN`` 。若未指定默认值为GitHub "
"Pages站点的URL这适用于大部分情况。"
#: ../../tips.rst:249 358c5aa434cd4ad09beab02df88413d5
msgid "``deploy``"
msgstr "``deploy``"
#: ../../tips.rst:249 b8748aeace5a448d9382e225be98f90c
msgid ""
"This is used to determine whether you will deploy the site or not to "
"GitHub Pages. This is most useful if you want to test a change to your "
"website in a pull request before deploying those change."
msgstr "此项配置用于表示是否要将站点部署至GitHub Pages。当对站点做了更改并且在正式部署前进行测试就可以用到此项。"
#: ../../tips.rst:249 034006b9b71b4cb486f230b8aad873ce
msgid "bool"
msgstr "bool"
#: ../../tips.rst:249 078ac613a8b74703af98c75bb5a007c1
msgid "``true``"
msgstr "``true``"
#: ../../tips.rst:257 e63cf881e3204be8b52ee5d8635ba4cf
msgid "Testing Your Build in a GitHub Pull Request"
msgstr "在Github拉取请求时进行测试"
#: ../../tips.rst:259 a2f6bd3420eb46a08f54efda35a6eaf4
msgid ""
"If you want to test your build in a pull request before deploying to "
"GitHub, your workflow might look something like this:"
msgstr "如果想在正式部署到 GitHub 前在PR中进行测试下面是一个可用的 workflow 示例"
#: ../../tips.rst:288 84393693279741efa82c5ee6b27cbd28
msgid ""
"The ``on`` section of the workflow defines the events that will trigger "
"the workflow. In this example, the workflow will run on pushes to the "
"main branch, pull requests to the main branch, and manual runs of the "
"workflow."
msgstr "工作流的 ``on`` 部分定义了工作流的触发器。在此示例中工作流将在main分支收到push、有PR提起到主分支以及"
"手动运行工作流时执行。"
#: ../../tips.rst:290 cd3c13b2af974a32aa4291d07fc11e9c
msgid ""
"``workflow_dispatch`` defines the deploy boolean to be true by default. "
"This means that if you run the workflow manually, it will deploy the "
"site."
msgstr "``workflow_dispatch`` 将 deploy 的默认值设为 true。也就是说当手动运行工作流时更改的内容就会正式部署。"
#: ../../tips.rst:292 5402cd211d5b4aa8a244c916bb381a5b
msgid ""
"The ``deploy`` input for the job is using a set of standard GitHub "
"workflow variables to control when ``deploy`` will either be true or "
"false (you can customize this to your needs)."
msgstr "job中的 ``deploy`` 使用了一些 GitHub workflow 变量来计算 ``deploy`` 值为 true 还是 false您可以根据需要自定义。"
#: ../../tips.rst:294 d084908e3a0749f0b802b43626cfe2c4
msgid ""
"In this example, the ``deploy`` will be true if the event is a push to "
"the main branch (or merging into main from a PR) or a manual run of the "
"workflow. If the event is a pull request, the ``deploy`` will be false "
"and it will only build an artifact for the site."
msgstr "在此示例中,如果触发事件是推送到主分支(或从 PR 合并到主分支)或手动运行工作流,则 deploy 将为 true"
"如果触发事件只是Pull Request则 ``deploy`` 将为 false并且此时只会为站点构建一个artifact。"
#: ../../tips.rst:297 85e70fc3faa04208979f7bbe92b025ef
msgid "\"Insecure content\" warnings from browsers"
msgstr "浏览器报“不安全的内容Insecure content”警告"
#: ../../tips.rst:299 34f7075cf31f416da2aeb529c616d97d
msgid ""
"If your site uses ``https://`` and is broken because the browser is "
"blocking network requests (for example for CSS files) due to \"insecure "
"content\" this may be because GitHub Pages is generating ``http://`` URLs"
" for your site."
msgstr ""
"当站点使用 ``https://`` "
"时可能会损坏无法正常显示这是由于浏览器阻拦了一些对“不安全内容”的网络请求。可能的原因之一是GitHub Pages给你的站点生成了 "
"``http://`` URL。"
#: ../../tips.rst:303 47271df82577424c8e2c31a9e76a553a
msgid ""
"To fix this go into your site repo's settings and enable the **Enforce "
"HTTPS** setting: go to **Settings → Pages** and check **Enforce HTTPS**. "
"Then re-run the workflow to re-deploy your site. Alternatively, you can "
"use the workflow's ``siteurl`` and ``feed_domain`` settings."
msgstr ""
"要想解决这一问题,需要为站点所在仓库开启 **强制使用HTTPS** :点击 **Settings → Pages** 并在其中勾选 "
"**Enforce HTTPS** ,接着再重新执行工作流以重新部署站点。也可以尝试通过配置 ``siteurl`` 与 "
"``feed_domain`` 解决问题。"
#: ../../tips.rst:311 e69189ef4a8440fb8940d8012b4f19d6
msgid ""
"GitHub Pages will display the custom 404 page described above, as noted "
"in the relevant `GitHub docs "
"<https://help.github.com/articles/custom-404-pages/>`_."
msgstr ""
"如果按前述进行配置GitHub Pages是能够正确显示自定义的404页面的相关内容在 `GitHub的文档中 "
"<https://help.github.com/articles/custom-404-pages/>`_ 也有提到。"
#: ../../tips.rst:315 1b8c2457f44a4d61a033363830b8bd90
msgid "Update your site on each commit"
msgstr "在每次commit后都更新站点"
#: ../../tips.rst:317 476dbdb670924c02a962e78d6a7854c1
msgid ""
"To automatically update your Pelican site on each commit, you can create "
"a post-commit hook. For example, you can add the following to "
"``.git/hooks/post-commit``::"
msgstr ""
"要想在每次commit后自动更新Pelican站点你可以创建一个post-commit钩子。例如可以将下面的内容保存为 "
"``.git/hooks/post-commit`` "
#: ../../tips.rst:324 36dc5f05eaf84573acada36c59d8d2fc
msgid "Copy static files to the root of your site"
msgstr "将静态文件拷贝到站点根目录"
#: ../../tips.rst:326 4a0722ad68e944ee80e6378259cc1dd6
msgid ""
"To use a `custom domain <https://help.github.com/articles/setting-up-a"
"-custom-domain-with-pages>`_ with GitHub Pages, you need to put the "
"domain of your site (e.g., ``blog.example.com``) inside a ``CNAME`` file "
"at the root of your site. To do this, create the ``content/extra/`` "
"directory and add a ``CNAME`` file to it. Then use the ``STATIC_PATHS`` "
"setting to tell Pelican to copy this file to your output directory. For "
"example::"
msgstr ""
"要将 `自定义域名 <https://help.github.com/articles/setting-up-a-custom-domain-"
"with-pages>`_ 与GitHub Pages一起使用需要将站点的域名例如 ``blog.example.com`` "
")添加到站点根目录的 ``CNAME`` 文件中。为此,请创建 ``content/extra/`` 目录,并在里面添加一个 ``CNAME`` "
"文件。然后使用Pelican的 ``STATIC_PATHS`` 来告诉Pelican将此文件复制到输出目录"
#: ../../tips.rst:337 8ad906848762400d9e2462034d151a16
msgid "Note: use forward slashes, ``/``, even on Windows."
msgstr "请注意:务必使用正斜杠 ``/`` 在Windows上也是。"
#: ../../tips.rst:339 7b109f4944064382babc9158567c8e82
msgid ""
"You can also use the ``EXTRA_PATH_METADATA`` mechanism to place a "
"``favicon.ico`` or ``robots.txt`` at the root of any site."
msgstr ""
"利用 ``EXTRA_PATH_METADATA`` 机制,你可以将 ``favicon.ico`` 或 ``robots.txt`` "
"也拷贝到站点的根目录下。"
#: ../../tips.rst:343 678eea0644b5400496ad9173d05368d5
msgid "How to add YouTube or Vimeo Videos"
msgstr "如何添加YouTube或Vimeo视频"
#: ../../tips.rst:345 ca57b327dd6b432d82cdc91193bde6bb
msgid ""
"The easiest way is to paste the embed code of the video from these sites "
"directly into your source content."
msgstr "最简单的方法是将这些网站的视频嵌入代码直接粘贴到您的源内容文件中。"
#: ../../tips.rst:348 0a4f27e2edbe494ab52f73595646986e
msgid ""
"Alternatively, you can also use Pelican plugins like ``liquid_tags``, "
"``pelican_youtube``, or ``pelican_vimeo`` to embed videos in your "
"content."
msgstr ""
"或者,您还可以使用例如 ``liquid_tags`` 、``pelican_youtube`` 或 ``pelican_vimeo`` "
"等Pelican插件将视频嵌入。"
#: ../../tips.rst:351 e73517b72da347738421784b776b1f1c
msgid ""
"Moreover, markup languages like reST and Markdown have plugins that let "
"you embed videos in the markup. You can use `reST video directive "
"<https://gist.github.com/dbrgn/2922648>`_ for reST or `mdx_video plugin "
"<https://github.com/italomaia/mdx-video>`_ for Markdown."
msgstr ""
"此外像reST和 Markdown这样的标记语言都有对应插件可以让你在其中嵌入视频。可以使用 `reST的视频指令 "
"<https://gist.github.com/dbrgn/2922648>`_ 或者 `Markdown的mdx_video插件 "
"<https://github.com/italomaia/mdx-video>`_ 。"
#: ../../tips.rst:358 b9d27cda716048b2ab7c13646d7faf09
msgid "Develop Locally Using SSL"
msgstr "在本地使用SSL进行开发"
#: ../../tips.rst:360 50df9ec072aa47eabbae132fd8f5cb68
msgid "Here's how you can set up your local pelican server to support SSL."
msgstr "以下描述了如何在本地Pelican服务器上配置SSL。"
#: ../../tips.rst:362 9b5045375a874c4d9c29f7109f05c539
msgid ""
"First, create a self-signed certificate and key using ``openssl`` (this "
"creates ``cert.pem`` and ``key.pem``)::"
msgstr "首先,通过 ``openssl`` 创建自签名的证书和密钥,这会生成 ``cert.pem`` 和 ``key.pem`` 文件:"
#: ../../tips.rst:366 2f1cfa536fc540f69d671f8a118769d7
msgid ""
"And use this command to launch the server (the server starts within your "
"``output`` directory)::"
msgstr "接着使用下面的命令来开启服务器(此服务器会在 ``output`` 目录下开启):"
#: ../../tips.rst:370 029ea2b0e4fe4b0f814158ae33e3a8ff
msgid "If you are using ``develop-server.sh``, add this to the top::"
msgstr "如果你使用的是 ``develop-server.sh`` 脚本,在脚本的开头添加:"
#: ../../tips.rst:375 c2784fdd9fdb433799d57f903d0e49d8
msgid "and modify the ``pelican.server`` line as follows::"
msgstr "然后修改按照下述修改 ``pelican.server`` 一行:"
#~ msgid ""
#~ "To publish a Pelican site in the"
#~ " form of User Pages, you need "
#~ "to *push* the content of the "
#~ "``output`` dir generated by Pelican to"
#~ " the ``master`` branch of your "
#~ "``<username>.github.io`` repository on GitHub."
#~ msgstr ""
#~ msgid ""
#~ "The ``git push`` command pushes the "
#~ "local ``gh-pages`` branch (freshly "
#~ "updated by the ``ghp-import`` command)"
#~ " to the ``elemoine.github.io`` repository's "
#~ "``master`` branch on GitHub."
#~ msgstr ""
#~ msgid ""
#~ "Now you can push the whole project"
#~ " ``<username>.github.io`` to the master "
#~ "branch of your GitHub repository::"
#~ msgstr ""
#~ msgid ""
#~ "Pelican-powered sites can be published"
#~ " to GitHub Pages via a `custom "
#~ "workflow "
#~ "<https://github.com/getpelican/pelican/blob/master/.github/workflows/github_pages.yml>`_."
#~ " To use it:"
#~ msgstr ""
#~ msgid ""
#~ "You may want to replace the "
#~ "``@master`` with the ID of a "
#~ "specific commit in this repo in "
#~ "order to pin the version of the"
#~ " reusable workflow that you're using: "
#~ "``uses: "
#~ "getpelican/pelican/.github/workflows/github_pages.yml@<COMMIT_ID>``."
#~ " If you do this you might want"
#~ " to get Dependabot to send you "
#~ "automated pull requests to update that"
#~ " commit ID whenever new versions of"
#~ " this workflow are published, like "
#~ "so:"
#~ msgstr ""

View file

@ -21,7 +21,7 @@ Optional arguments:
"""""""""""""""""""
-h, --help Show the help an exit
-h, --help Show the help and exit
-l, --list Show the themes already installed
@ -29,7 +29,7 @@ Optional arguments:
-r theme_name, --remove theme_name One or more themes to remove
-s theme_path, --symlink theme_path Same as "--install", but create a symbolic link instead of copying the theme.
-s theme_path, --symlink theme_path Same as ``--install``, but create a symbolic link instead of copying the theme.
Useful for theme development
-v, --verbose Verbose output
@ -62,7 +62,7 @@ or ``--list`` option:
In this example, we can see there are three themes available: ``notmyidea``,
``simple``, and ``two-column``.
``two-column`` is prefixed with an ``@`` because this theme is not copied to
``two-column`` is followed by an ``@`` because this theme is not copied to
the Pelican theme path, but is instead just linked to it (see `Creating
symbolic links`_ for details about creating symbolic links).
@ -82,7 +82,7 @@ Installing themes
You can install one or more themes using the ``-i`` or ``--install`` option.
This option takes as argument the path(s) of the theme(s) you want to install,
and can be combined with the verbose option:
and can be combined with the ``--verbose`` option:
.. code-block:: console
@ -154,7 +154,7 @@ This is useful for theme development:
Doing several things at once
""""""""""""""""""""""""""""
The ``--install``, ``--remove`` and ``--symlink`` option are not mutually
The ``--install``, ``--remove`` and ``--symlink`` options are not mutually
exclusive, so you can combine them in the same command line to do more than one
operation at time, like this:

View file

@ -94,9 +94,14 @@ which you map the signals to your plugin logic. Let's take a simple example::
your ``register`` callable or they will be garbage-collected before the
signal is emitted.
If multiple plugins connect to the same signal, there is no way to guarantee or
control in which order the plugins will be executed. This is a limitation
inherited from Blinker_, the dependency Pelican uses to implement signals.
If multiple plugins connect to the same signal, plugins will be invoked in the
order they are registered. When the ``PLUGINS`` setting is defined, plugin
invocation order will be the order in which the plugins are listed in the
``PLUGINS`` setting. If you rely on auto-discovered namespace plugins and have
no ``PLUGINS`` setting defined, plugins will be invoked in the same order that
they are discovered (the same order as listed in the output of the
``pelican-plugins`` command). If you want to specify the order explicitly,
disable auto-discovery by defining ``PLUGINS`` in the desired order.
Namespace plugin structure
--------------------------
@ -274,6 +279,70 @@ Adding a new generator is also really easy. You might want to have a look at
signals.get_generators.connect(get_generators)
Adding a new writer
-------------------
Adding a writer will allow you to output additional file formats to disk, or
change how the existing formats are written to disk. Note that only one writer
will be active at a time, so be sure to either subclass the built-in Writer, or
completely re-implement it.
Here is a basic example of how to set up your own writer::
from pelican.writers import Writer
from pelican import signals
class MyWriter(Writer):
# define new writer functionality
pass
def add_writer(pelican_object):
# use pelican_instance to setup stuff if needed
return MyWriter
def register():
signals.get_writer.connect(add_writer)
Using Plugins to Inject Content
-------------------------------
You can programmatically inject articles or pages using plugins. This can be
useful if you plan to fetch articles from an API, for example.
Following is a simple example of how one can build a plugin that injects a
custom article, using the ``article_generator_pretaxonomy`` signal::
import datetime
from pelican import signals
from pelican.contents import Article
from pelican.readers import BaseReader
def addArticle(articleGenerator):
settings = articleGenerator.settings
# Author, category, and tags are objects, not strings, so they need to
# be handled using BaseReader's process_metadata() function.
baseReader = BaseReader(settings)
content = "I am the body of an injected article!"
newArticle = Article(content, {
"title": "Injected Article!",
"date": datetime.datetime.now(),
"category": baseReader.process_metadata("category", "fromAPI"),
"tags": baseReader.process_metadata("tags", "tagA, tagB")
})
articleGenerator.articles.insert(0, newArticle)
def register():
signals.article_generator_pretaxonomy.connect(addArticle)
.. _Pip: https://pip.pypa.io/
.. _pelican-plugins bug #314: https://github.com/getpelican/pelican-plugins/issues/314
.. _Blinker: https://pythonhosted.org/blinker/

View file

@ -18,18 +18,6 @@ folder, using the default theme to produce a simple site. The default theme
consists of very simple HTML without styling and is provided so folks may use
it as a basis for creating their own themes.
When working on a single article or page, it is possible to generate only the
file that corresponds to that content. To do this, use the ``--write-selected``
argument, like so::
pelican --write-selected output/posts/my-post-title.html
Note that you must specify the path to the generated *output* file — not the
source content. To determine the output file name and location, use the
``--debug`` flag. If desired, ``--write-selected`` can take a comma-separated
list of paths or can be configured as a setting. (See:
:ref:`writing_only_selected_content`)
You can also tell Pelican to watch for your modifications, instead of manually
re-running it every time you want to see your changes. To enable this, run the
``pelican`` command with the ``-r`` or ``--autoreload`` option. On non-Windows
@ -67,7 +55,7 @@ Deployment
After you have generated your site, previewed it in your local development
environment, and are ready to deploy it to production, you might first
re-generate your site with any production-specific settings (e.g., analytics
re-generate your site with any production-specific settings (e.g., analytics,
feeds, etc.) that you may have defined::
pelican content -s publishconf.py
@ -104,7 +92,7 @@ information gleaned from other answers provided during the
``pelican-quickstart`` process, are meant as a starting point and should be
customized to fit your particular needs and usage patterns. If you find one or
both of these automation tools to be of limited utility, these files can
deleted at any time and will not affect usage of the canonical ``pelican``
be deleted at any time and will not affect usage of the canonical ``pelican``
command.
Following are automation tools that "wrap" the ``pelican`` command and can

View file

@ -8,7 +8,7 @@ Installation
------------
Install Pelican (and optionally Markdown if you intend to use it) on Python
3.6+ by running the following command in your preferred terminal, prefixing
|min_python| by running the following command in your preferred terminal, prefixing
with ``sudo`` if permissions warrant::
python -m pip install "pelican[markdown]"

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,23 @@
.. _theming-pelican:
Creating themes
###############
Themes
######
There is a community-managed repository of `Pelican Themes`_ for people to share
and use.
Please note that while we do our best to review and merge theme contributions,
they are submitted by the Pelican community and thus may have varying levels of
support and interoperability.
Creating Themes
~~~~~~~~~~~~~~~
To generate its HTML output, Pelican uses the `Jinja
<https://palletsprojects.com/p/jinja/>`_ templating engine due to its flexibility and
straightforward syntax. If you want to create your own theme, feel free to take
inspiration from the `"simple" theme
<https://github.com/getpelican/pelican/tree/master/pelican/themes/simple/templates>`_.
<https://github.com/getpelican/pelican/tree/main/pelican/themes/simple/templates>`_.
To generate your site using a theme you have created (or downloaded manually
and then modified), you can specify that theme via the ``-t`` flag::
@ -24,11 +34,10 @@ Structure
To make your own theme, you must follow the following structure::
├── static
   ├── css
   └── images
├── css
└── images
└── templates
├── archives.html // to display archives
├── period_archives.html // to display time-period archives
├── article.html // processed for each article
├── author.html // processed for each author
├── authors.html // must list all the authors
@ -36,6 +45,7 @@ To make your own theme, you must follow the following structure::
├── category.html // processed for each category
├── index.html // the index (list all the articles)
├── page.html // processed for each page
├── period_archives.html // to display time-period archives
├── tag.html // processed for each tag
└── tags.html // must list all the tags. Can be a tag cloud.
@ -50,7 +60,7 @@ To make your own theme, you must follow the following structure::
.. _templates-variables:
Templates and variables
Templates and Variables
=======================
The idea is to use a simple syntax that you can embed into your HTML pages.
@ -61,14 +71,16 @@ All templates will receive the variables defined in your settings file, as long
as they are in all-caps. You can access them directly.
Common variables
.. _common_variables:
Common Variables
----------------
All of these settings will be available to all templates.
============= ===================================================
=============== ===================================================
Variable Description
============= ===================================================
=============== ===================================================
output_file The name of the file currently being generated. For
instance, when Pelican is rendering the home page,
output_file will be "index.html".
@ -80,7 +92,12 @@ articles The list of articles, ordered descending by date.
in the `all_articles` variable.
dates The same list of articles, but ordered by date,
ascending.
hidden_articles The list of hidden articles
drafts The list of draft articles
period_archives A dictionary containing elements related to
time-period archives (if enabled). See the section
:ref:`Listing and Linking to Period Archives
<period_archives_variable>` for details.
authors A list of (author, articles) tuples, containing all
the authors and corresponding articles (values)
categories A list of (category, articles) tuples, containing
@ -90,7 +107,7 @@ tags A list of (tag, articles) tuples, containing all
pages The list of pages
hidden_pages The list of hidden pages
draft_pages The list of draft pages
============= ===================================================
=============== ===================================================
Sorting
@ -104,7 +121,7 @@ that allow them to be easily sorted by name::
If you want to sort based on different criteria, `Jinja's sort command`__ has a
number of options.
__ https://jinja.palletsprojects.com/en/master/templates/#sort
__ https://jinja.palletsprojects.com/en/latest/templates/#sort
Date Formatting
@ -123,6 +140,23 @@ your date according to the locale given in your settings::
.. _datetime: https://docs.python.org/3/library/datetime.html#datetime-objects
.. _strftime: https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
Checking Loaded Plugins
-----------------------
Pelican provides a ``plugin_enabled`` Jinja test for checking if a certain plugin
is enabled. This test accepts a plugin name as a string and will return a Boolean.
Namespace plugins can be specified by full name (``pelican.plugins.plugin_name``)
or short name (``plugin_name``). The following example uses the ``webassets`` plugin
to minify CSS if the plugin is enabled and otherwise falls back to regular CSS::
{% if "webassets" is plugin_enabled %}
{% assets filters="cssmin", output="css/style.min.css", "css/style.scss" %}
<link rel="stylesheet" href="{{SITEURL}}/{{ASSET_URL}}">
{% endassets %}
{% else %}
<link rel="stylesheet" href="{{SITEURL}}/css/style.css}">
{% endif %}
index.html
----------
@ -327,12 +361,71 @@ period A tuple of the form (`year`, `month`, `day`) that
given year. It contains both `year` and `month`
if the time period is over years and months and
so on.
period_num A tuple of the form (``year``, ``month``, ``day``),
as in ``period``, except all values are numbers.
=================== ===================================================
You can see an example of how to use `period` in the `"simple" theme
period_archives.html template
<https://github.com/getpelican/pelican/blob/master/pelican/themes/simple/templates/period_archives.html>`_.
<https://github.com/getpelican/pelican/blob/main/pelican/themes/simple/templates/period_archives.html>`_.
.. _period_archives_variable:
Listing and Linking to Period Archives
""""""""""""""""""""""""""""""""""""""
The ``period_archives`` variable can be used to generate a list of links to
the set of period archives that Pelican generates. As a :ref:`common variable
<common_variables>`, it is available for use in any template, so you
can implement such an index in a custom direct template, or in a sidebar
visible across different site pages.
``period_archives`` is a dict that may contain ``year``, ``month``, and/or
``day`` keys, depending on which ``*_ARCHIVE_SAVE_AS`` settings are enabled.
The corresponding value is a list of dicts, where each dict in turn represents
a time period (ordered according to the ``NEWEST_FIRST_ARCHIVES`` setting)
with the following keys and values:
=================== ===================================================
Key Value
=================== ===================================================
period The same tuple as described in
``period_archives.html``, e.g.
``(2023, 'June', 18)``.
period_num The same tuple as described in
``period_archives.html``, e.g. ``(2023, 6, 18)``.
url The URL to the period archive page, e.g.
``posts/2023/06/18/``. This is controlled by the
corresponding ``*_ARCHIVE_URL`` setting.
save_as The path to the save location of the period archive
page file, e.g. ``posts/2023/06/18/index.html``.
This is used internally by Pelican and is usually
not relevant to themes.
articles A list of :ref:`Article <object-article>` objects
that fall under the time period.
dates Same list as ``articles``, but ordered according
to the ``NEWEST_FIRST_ARCHIVES`` setting.
=================== ===================================================
Here is an example of how ``period_archives`` can be used in a template:
.. code-block:: html+jinja
<ul>
{% for archive in period_archives.month %}
<li>
<a href="{{ SITEURL }}/{{ archive.url }}">
{{ archive.period | reverse | join(' ') }} ({{ archive.articles|count }})
</a>
</li>
{% endfor %}
</ul>
You can change ``period_archives.month`` in the ``for`` statement to
``period_archives.year`` or ``period_archives.day`` as appropriate, depending
on the time period granularity desired.
Objects
@ -452,14 +545,14 @@ The feed variables changed in 3.0. Each variable now explicitly lists ATOM or
RSS in the name. ATOM is still the default. Old themes will need to be updated.
Here is a complete list of the feed variables::
FEED_ATOM
FEED_RSS
FEED_ALL_ATOM
FEED_ALL_RSS
CATEGORY_FEED_ATOM
CATEGORY_FEED_RSS
AUTHOR_FEED_ATOM
AUTHOR_FEED_RSS
CATEGORY_FEED_ATOM
CATEGORY_FEED_RSS
FEED_ALL_ATOM
FEED_ALL_RSS
FEED_ATOM
FEED_RSS
TAG_FEED_ATOM
TAG_FEED_RSS
TRANSLATION_FEED_ATOM
@ -568,3 +661,8 @@ Download
""""""""
You can download this example theme :download:`here <_static/theme-basic.zip>`.
.. Links
.. _`Pelican Themes`: https://github.com/getpelican/pelican-themes

View file

@ -30,21 +30,34 @@ For Apache::
ErrorDocument 404 /404.html
For Amazon S3, first navigate to the ``Static Site Hosting`` menu in the bucket
settings on your AWS cosole. From there::
settings on your AWS console. From there::
Error Document: 404.html
Publishing to GitHub
====================
Publishing to GitHub Pages
==========================
`GitHub Pages <https://help.github.com/categories/20/articles>`_ offer an easy
and convenient way to publish Pelican sites. There are `two types of GitHub
Pages <https://help.github.com/articles/user-organization-and-project-pages>`_:
*Project Pages* and *User Pages*. Pelican sites can be published as both
Project Pages and User Pages.
If you use `GitHub <https://github.com/>`_ for your Pelican site you can
publish your site to `GitHub Pages <https://pages.github.com/>`_ for free.
Your site will be published to ``https://<username>.github.io`` if it's a user or
organization site or to ``https://<username>.github.io/<repository>`` if it's a
project site. It's also possible to `use a custom domain with GitHub Pages <https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site>`_.
Project Pages
-------------
There are `two ways to publish a site to GitHub Pages <https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site>`_:
1. **Publishing from a branch:** run ``pelican`` locally and push the output
directory to a special branch of your GitHub repo. GitHub will then publish
the contents of this branch to your GitHub Pages site.
2. **Publishing with a custom GitHub Actions workflow:** just push the source
files of your Pelican site to your GitHub repo's default branch and have a
custom GitHub Actions workflow run ``pelican`` for you to generate the
output directory and publish it to your GitHub Pages site. This way you
don't need to run ``pelican`` locally. You can even edit your site's source
files using GitHub's web interface and any changes that you commit will be
published.
Publishing a Project Site to GitHub Pages from a Branch
-------------------------------------------------------
To publish a Pelican site as a Project Page you need to *push* the content of
the ``output`` dir generated by Pelican to a repository's ``gh-pages`` branch
@ -72,44 +85,226 @@ already exist). The ``git push origin gh-pages`` command updates the remote
``tasks.py``) created by the ``pelican-quickstart`` command publishes the
Pelican site as Project Pages, as described above.
User Pages
----------
Publishing a User Site to GitHub Pages from a Branch
----------------------------------------------------
To publish a Pelican site in the form of User Pages, you need to *push* the
content of the ``output`` dir generated by Pelican to the ``master`` branch of
content of the ``output`` dir generated by Pelican to the ``main`` branch of
your ``<username>.github.io`` repository on GitHub.
Again, you can take advantage of ``ghp-import``::
$ pelican content -o output -s pelicanconf.py
$ ghp-import output -b gh-pages
$ git push git@github.com:elemoine/elemoine.github.io.git gh-pages:master
$ git push git@github.com:elemoine/elemoine.github.io.git gh-pages:main
The ``git push`` command pushes the local ``gh-pages`` branch (freshly updated
by the ``ghp-import`` command) to the ``elemoine.github.io`` repository's
``master`` branch on GitHub.
``main`` branch on GitHub.
.. note::
To publish your Pelican site as User Pages, feel free to adjust the
``github`` target of the Makefile.
Another option for publishing to User Pages is to generate the output files in
the root directory of the project.
For example, your main project folder is ``<username>.github.io`` and you can
create the Pelican project in a subdirectory called ``Pelican``. Then from
inside the ``Pelican`` folder you can run::
$ pelican content -o .. -s pelicanconf.py
Now you can push the whole project ``<username>.github.io`` to the master
Now you can push the whole project ``<username>.github.io`` to the main
branch of your GitHub repository::
$ git push origin master
$ git push origin main
(assuming origin is set to your remote repository).
Publishing to GitHub Pages Using a Custom GitHub Actions Workflow
-----------------------------------------------------------------
Pelican-powered sites can be published to GitHub Pages via a `custom workflow
<https://github.com/getpelican/pelican/blob/main/.github/workflows/github_pages.yml>`_.
To use it:
1. Enable GitHub Pages in your repo: go to **Settings → Pages** and choose
**GitHub Actions** for the **Source** setting.
2. Commit a ``.github/workflows/pelican.yml`` file to your repo with these contents:
.. code-block:: yaml
name: Deploy to GitHub Pages
on:
push:
branches: ["main"]
workflow_dispatch:
jobs:
deploy:
uses: "getpelican/pelican/.github/workflows/github_pages.yml@main"
permissions:
contents: "read"
pages: "write"
id-token: "write"
with:
settings: "publishconf.py"
You may want to replace the ``@main`` with the ID of a specific commit in
this repo in order to pin the version of the reusable workflow that you're using:
``uses: getpelican/pelican/.github/workflows/github_pages.yml@<COMMIT_ID>``.
If you do this you might want to get Dependabot to send you automated pull
requests to update that commit ID whenever new versions of this workflow are
published, like so:
.. code-block:: yaml
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
See `GitHub's docs about using Dependabot to keep your actions up to date <https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot>`_.
3. Go to the **Actions** tab in your repo
(``https://github.com/<username>/<repository>/actions``) and you should see a
**Deploy to GitHub Pages** action running.
4. Once the action completes you should see your Pelican site deployed at your
repo's GitHub Pages URL: ``https://<username>.github.io`` for a user or
organization site or ``https://<username>.github.io/<repository>>`` for a
project site.
Notes:
* You don't need to set ``SITEURL`` or ``FEED_DOMAIN`` in your Pelican
settings: the workflow will set them correctly for you
* You don't need to commit your ``--output`` / ``OUTPUT_PATH`` directory
(``output/``) to git: the workflow will run ``pelican`` to build the output
directory for you on GitHub Actions
See `GitHub's docs about reusable workflows <https://docs.github.com/en/actions/using-workflows/reusing-workflows>`_
for more information.
A number of optional inputs can be added to the ``with:`` block when calling
the workflow, for example:
.. code-block:: yaml
with:
settings: "publishconf.py"
requirements: "pelican[markdown] typogrify"
theme: "https://github.com/seanh/sidecar.git"
python: "3.12"
Here's the complete list of workflow inputs:
+------------------+----------+--------------------------------------------+--------+---------------+
| Name | Required | Description | Type | Default |
+==================+==========+============================================+========+===============+
| ``settings`` | Yes | The path to your Pelican settings | string | |
| | | file (``pelican``'s | | |
| | | ``--settings`` option), | | |
| | | for example: ``"publishconf.py"`` | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``requirements`` | No | The Python requirements to | string | ``"pelican"`` |
| | | install, for example to enable | | |
| | | markdown and typogrify use: | | |
| | | ``"pelican[markdown] typogrify"`` | | |
| | | or if you have a requirements | | |
| | | file: ``"-r requirements.txt"`` | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``output-path`` | No | Where to output the generated | string | ``"output/"`` |
| | | files (``pelican``'s ``--output`` | | |
| | | option) | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``theme`` | No | The GitHub repo URL of a custom | string | ``""`` |
| | | theme to use, for example: | | |
| | | ``"https://github.com/seanh/sidecar.git"`` | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``python`` | No | The version of Python to use to build the | string | ``"3.12"`` |
| | | site, for example: ``"3.12"`` (to use the | | |
| | | most recent version of Python 3.12, this | | |
| | | is faster) or ``"3.12.1"`` (to use an | | |
| | | exact version, slower) | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``siteurl`` | No | The base URL of your web site (Pelican's | string | The URL of |
| | | ``SITEURL`` setting). If not passed this | | your GitHub |
| | | will default to the URL of your GitHub | | Pages site. |
| | | Pages site, which is correct in most | | |
| | | cases. | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``feed_domain`` | No | The domain to be prepended to feed URLs | string | The URL of |
| | | (Pelican's ``FEED_DOMAIN`` setting). If | | your GitHub |
| | | not passed this will default to the URL of | | Pages site. |
| | | your GitHub Pages site, which is correct | | |
| | | in most cases. | | |
+------------------+----------+--------------------------------------------+--------+---------------+
| ``deploy`` | No | This is used to determine whether you will | bool | ``true`` |
| | | deploy the site or not to GitHub Pages. | | |
| | | This is most useful if you want to test a | | |
| | | change to your website in a pull request | | |
| | | before deploying those change. | | |
+------------------+----------+--------------------------------------------+--------+---------------+
Testing Your Build in a GitHub Pull Request
"""""""""""""""""""""""""""""""""""""""""""
If you want to test your build in a pull request before deploying to GitHub, your workflow might look something like this:
.. code-block:: yaml
name: Build and Deploy Site
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch:
inputs:
deploy:
required: false
default: true
description: "Whether to deploy the site. If checked, then build the site and deploy it. If not checked, then just test that the site builds successfully but don't deploy anything."
type: boolean
jobs:
deploy:
uses: "getpelican/pelican/.github/workflows/github_pages.yml@main"
permissions:
id-token: write
contents: read
pages: write
with:
settings: "publishconf.py"
requirements: "-r requirements.txt"
deploy: ${{ (github.event_name == 'workflow_dispatch' && inputs.deploy == true) || (github.event_name == 'push' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch) }}
The ``on`` section of the workflow defines the events that will trigger the workflow. In this example, the workflow will run on pushes to the main branch, pull requests to the main branch, and manual runs of the workflow.
``workflow_dispatch`` defines the deploy boolean to be true by default. This means that if you run the workflow manually, it will deploy the site.
The ``deploy`` input for the job is using a set of standard GitHub workflow variables to control when ``deploy`` will either be true or false (you can customize this to your needs).
In this example, the ``deploy`` will be true if the event is a push to the main branch (or merging into main from a PR) or a manual run of the workflow. If the event is a pull request, the ``deploy`` will be false and it will only build an artifact for the site.
"Insecure content" warnings from browsers
"""""""""""""""""""""""""""""""""""""""""
If your site uses ``https://`` and is broken because the browser is blocking
network requests (for example for CSS files) due to "insecure content" this
may be because GitHub Pages is generating ``http://`` URLs for your site.
To fix this go into your site repo's settings and enable the **Enforce HTTPS** setting:
go to **Settings → Pages** and check **Enforce HTTPS**.
Then re-run the workflow to re-deploy your site.
Alternatively, you can use the workflow's ``siteurl`` and ``feed_domain`` settings.
Custom 404 Pages
----------------
@ -179,4 +374,4 @@ If you are using ``develop-server.sh``, add this to the top::
and modify the ``pelican.server`` line as follows::
$PY -m pelican.server $port --ssl --cert="$CERT" --key="$KEY" &
$PY -m pelican.server $port --ssl --cert="$CERT" --key="$KEY" &

View file

@ -1,4 +1,6 @@
import argparse
import importlib.metadata
import json
import logging
import multiprocessing
import os
@ -7,40 +9,44 @@ import sys
import time
import traceback
from collections.abc import Iterable
# Combines all paths to `pelican` package accessible from `sys.path`
# Makes it possible to install `pelican` and namespace plugins into different
# locations in the file system (e.g. pip with `-e` or `--user`)
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
# pelican.log has to be the first pelican module to be loaded
# because logging.setLoggerClass has to be called before logging.getLogger
from pelican.log import console, DEFAULT_LOG_HANDLER # noqa: I001
from pelican.log import init as init_logging
from pelican.generators import (ArticlesGenerator, # noqa: I100
PagesGenerator, SourceFileGenerator,
StaticGenerator, TemplatePagesGenerator)
from pelican.generators import (
ArticlesGenerator,
PagesGenerator,
SourceFileGenerator,
StaticGenerator,
TemplatePagesGenerator,
)
from pelican.plugins import signals
from pelican.plugins._utils import get_plugin_name, load_plugins
from pelican.readers import Readers
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
from pelican.settings import coerce_overrides, read_settings
from pelican.utils import (FileSystemWatcher, clean_output_dir, maybe_pluralize)
from pelican.settings import read_settings
from pelican.utils import clean_output_dir, maybe_pluralize, wait_for_changes
from pelican.writers import Writer
try:
__version__ = __import__('pkg_resources') \
.get_distribution('pelican').version
__version__ = importlib.metadata.version("pelican")
except Exception:
__version__ = "unknown"
DEFAULT_CONFIG_NAME = 'pelicanconf.py'
DEFAULT_CONFIG_NAME = "pelicanconf.py"
logger = logging.getLogger(__name__)
class Pelican:
def __init__(self, settings):
"""Pelican initialisation
"""Pelican initialization
Performs some checks on the environment before doing anything else.
"""
@ -48,35 +54,41 @@ class Pelican:
# define the default settings
self.settings = settings
self.path = settings['PATH']
self.theme = settings['THEME']
self.output_path = settings['OUTPUT_PATH']
self.ignore_files = settings['IGNORE_FILES']
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
self.output_retention = settings['OUTPUT_RETENTION']
self.path = settings["PATH"]
self.theme = settings["THEME"]
self.output_path = settings["OUTPUT_PATH"]
self.ignore_files = settings["IGNORE_FILES"]
self.delete_outputdir = settings["DELETE_OUTPUT_DIRECTORY"]
self.output_retention = settings["OUTPUT_RETENTION"]
self.init_path()
self.init_plugins()
signals.initialized.send(self)
def init_path(self):
if not any(p in sys.path for p in ['', os.curdir]):
if not any(p in sys.path for p in ["", os.curdir]):
logger.debug("Adding current directory to system path")
sys.path.insert(0, '')
sys.path.insert(0, "")
def init_plugins(self):
self.plugins = []
for plugin in load_plugins(self.settings):
name = get_plugin_name(plugin)
logger.debug('Registering plugin `%s`', name)
logger.debug("Registering plugin `%s`", name)
try:
plugin.register()
self.plugins.append(plugin)
except Exception as e:
logger.error('Cannot register plugin `%s`\n%s',
name, e)
logger.error(
"Cannot register plugin `%s`\n%s",
name,
e,
stacklevel=2,
)
if self.settings.get("DEBUG", False):
console.print_exception()
self.settings['PLUGINS'] = [get_plugin_name(p) for p in self.plugins]
self.settings["PLUGINS"] = [get_plugin_name(p) for p in self.plugins]
def run(self):
"""Run the generators and return"""
@ -85,10 +97,10 @@ class Pelican:
context = self.settings.copy()
# Share these among all the generators and content objects
# They map source paths to Content objects or None
context['generated_content'] = {}
context['static_links'] = set()
context['static_content'] = {}
context['localsiteurl'] = self.settings['SITEURL']
context["generated_content"] = {}
context["static_links"] = set()
context["static_content"] = {}
context["localsiteurl"] = self.settings["SITEURL"]
generators = [
cls(
@ -97,79 +109,98 @@ class Pelican:
path=self.path,
theme=self.theme,
output_path=self.output_path,
) for cls in self._get_generator_classes()
)
for cls in self._get_generator_classes()
]
# Delete the output directory if (1) the appropriate setting is True
# and (2) that directory is not the parent of the source directory
if (self.delete_outputdir
and os.path.commonpath([os.path.realpath(self.output_path)]) !=
os.path.commonpath([os.path.realpath(self.output_path),
os.path.realpath(self.path)])):
if self.delete_outputdir and os.path.commonpath(
[os.path.realpath(self.output_path)]
) != os.path.commonpath(
[os.path.realpath(self.output_path), os.path.realpath(self.path)]
):
clean_output_dir(self.output_path, self.output_retention)
for p in generators:
if hasattr(p, 'generate_context'):
if hasattr(p, "generate_context"):
p.generate_context()
if hasattr(p, "check_disabled_readers"):
p.check_disabled_readers()
for p in generators:
if hasattr(p, 'refresh_metadata_intersite_links'):
p.refresh_metadata_intersite_links()
# for plugins that create/edit the summary
logger.debug("Signal all_generators_finalized.send(<generators>)")
signals.all_generators_finalized.send(generators)
# update links in the summary, etc
for p in generators:
if hasattr(p, "refresh_metadata_intersite_links"):
p.refresh_metadata_intersite_links()
writer = self._get_writer()
for p in generators:
if hasattr(p, 'generate_output'):
if hasattr(p, "generate_output"):
p.generate_output(writer)
signals.finalized.send(self)
articles_generator = next(g for g in generators
if isinstance(g, ArticlesGenerator))
pages_generator = next(g for g in generators
if isinstance(g, PagesGenerator))
articles_generator = next(
g for g in generators if isinstance(g, ArticlesGenerator)
)
pages_generator = next(g for g in generators if isinstance(g, PagesGenerator))
pluralized_articles = maybe_pluralize(
(len(articles_generator.articles) +
len(articles_generator.translations)),
'article',
'articles')
(len(articles_generator.articles) + len(articles_generator.translations)),
"article",
"articles",
)
pluralized_drafts = maybe_pluralize(
(len(articles_generator.drafts) +
len(articles_generator.drafts_translations)),
'draft',
'drafts')
(
len(articles_generator.drafts)
+ len(articles_generator.drafts_translations)
),
"draft",
"drafts",
)
pluralized_hidden_articles = maybe_pluralize(
(
len(articles_generator.hidden_articles)
+ len(articles_generator.hidden_translations)
),
"hidden article",
"hidden articles",
)
pluralized_pages = maybe_pluralize(
(len(pages_generator.pages) +
len(pages_generator.translations)),
'page',
'pages')
(len(pages_generator.pages) + len(pages_generator.translations)),
"page",
"pages",
)
pluralized_hidden_pages = maybe_pluralize(
(len(pages_generator.hidden_pages) +
len(pages_generator.hidden_translations)),
'hidden page',
'hidden pages')
(
len(pages_generator.hidden_pages)
+ len(pages_generator.hidden_translations)
),
"hidden page",
"hidden pages",
)
pluralized_draft_pages = maybe_pluralize(
(len(pages_generator.draft_pages) +
len(pages_generator.draft_translations)),
'draft page',
'draft pages')
(
len(pages_generator.draft_pages)
+ len(pages_generator.draft_translations)
),
"draft page",
"draft pages",
)
print('Done: Processed {}, {}, {}, {} and {} in {:.2f} seconds.'
.format(
pluralized_articles,
pluralized_drafts,
pluralized_pages,
pluralized_hidden_pages,
pluralized_draft_pages,
time.time() - start_time))
console.print(
f"Done: Processed {pluralized_articles}, {pluralized_drafts}, {pluralized_hidden_articles}, {pluralized_pages}, {pluralized_hidden_pages} and {pluralized_draft_pages} in {time.time() - start_time:.2f} seconds."
)
def _get_generator_classes(self):
discovered_generators = [
(ArticlesGenerator, "internal"),
(PagesGenerator, "internal")
(PagesGenerator, "internal"),
]
if self.settings["TEMPLATE_PAGES"]:
@ -215,193 +246,307 @@ class Pelican:
writer = writers[0]
logger.debug("Found writer: %s", writer)
logger.debug("Found writer: %s (%s)", writer.__name__, writer.__module__)
return writer(self.output_path, settings=self.settings)
class PrintSettings(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
instance, settings = get_instance(namespace)
del option_string # Unused argument
init_logging(name=__name__)
try:
instance, settings = get_instance(namespace)
except Exception as e:
logger.critical("%s: %s", e.__class__.__name__, e)
console.print_exception()
sys.exit(getattr(e, "exitcode", 1))
if values:
# One or more arguments provided, so only print those settings
for setting in values:
if setting in settings:
# Only add newline between setting name and value if dict
if isinstance(settings[setting], dict):
setting_format = '\n{}:\n{}'
if isinstance(settings[setting], (dict, tuple, list)):
setting_format = "\n{}:\n{}"
else:
setting_format = '\n{}: {}'
print(setting_format.format(
setting,
pprint.pformat(settings[setting])))
setting_format = "\n{}: {}"
console.print(
setting_format.format(
setting, pprint.pformat(settings[setting])
)
)
else:
print('\n{} is not a recognized setting.'.format(setting))
console.print(f"\n{setting} is not a recognized setting.")
break
else:
# No argument was given to --print-settings, so print all settings
pprint.pprint(settings)
console.print(settings)
parser.exit()
class ParseDict(argparse.Action):
class ParseOverrides(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
d = {}
if values:
for item in values:
split_items = item.split("=", 1)
key = split_items[0].strip()
value = split_items[1].strip()
d[key] = value
setattr(namespace, self.dest, d)
del parser, option_string # Unused arguments
overrides = {}
for item in values:
try:
k, v = item.split("=", 1)
except ValueError:
raise ValueError(
"Extra settings must be specified as KEY=VALUE pairs "
f"but you specified {item}"
) from None
try:
overrides[k] = json.loads(v)
except json.decoder.JSONDecodeError:
raise ValueError(
f"Invalid JSON value: {v}. "
"Values specified via -e / --extra-settings flags "
"must be in JSON notation. "
"Use -e KEY='\"string\"' to specify a string value; "
"-e KEY=null to specify None; "
"-e KEY=false (or true) to specify False (or True)."
) from None
setattr(namespace, self.dest, overrides)
LOG_HANDLERS = {"plain": None, "rich": DEFAULT_LOG_HANDLER}
def parse_arguments(argv=None):
parser = argparse.ArgumentParser(
description='A tool to generate a static blog, '
' with restructured text input files.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter
description="A tool to generate a static blog, "
" with restructured text input files.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(dest='path', nargs='?',
help='Path where to find the content files.',
default=None)
parser.add_argument(
dest="path",
nargs="?",
help="Path where to find the content files.",
default=None,
)
parser.add_argument('-t', '--theme-path', dest='theme',
help='Path where to find the theme templates. If not '
'specified, it will use the default one included with '
'pelican.')
parser.add_argument(
"-t",
"--theme-path",
dest="theme",
help="Path where to find the theme templates. If not "
"specified, it will use the default one included with "
"pelican.",
)
parser.add_argument('-o', '--output', dest='output',
help='Where to output the generated files. If not '
'specified, a directory will be created, named '
'"output" in the current path.')
parser.add_argument(
"-o",
"--output",
dest="output",
help="Where to output the generated files. If not "
"specified, a directory will be created, named "
'"output" in the current path.',
)
parser.add_argument('-s', '--settings', dest='settings',
help='The settings of the application, this is '
'automatically set to {} if a file exists with this '
'name.'.format(DEFAULT_CONFIG_NAME))
parser.add_argument(
"-s",
"--settings",
dest="settings",
help="The settings of the application, this is "
f"automatically set to {DEFAULT_CONFIG_NAME} if a file exists with this "
"name.",
)
parser.add_argument('-d', '--delete-output-directory',
dest='delete_outputdir', action='store_true',
default=None, help='Delete the output directory.')
parser.add_argument(
"-d",
"--delete-output-directory",
dest="delete_outputdir",
action="store_true",
default=None,
help="Delete the output directory.",
)
parser.add_argument('-v', '--verbose', action='store_const',
const=logging.INFO, dest='verbosity',
help='Show all messages.')
parser.add_argument(
"-v",
"--verbose",
action="store_const",
const=logging.INFO,
dest="verbosity",
help="Show all messages.",
)
parser.add_argument('-q', '--quiet', action='store_const',
const=logging.CRITICAL, dest='verbosity',
help='Show only critical errors.')
parser.add_argument(
"-q",
"--quiet",
action="store_const",
const=logging.CRITICAL,
dest="verbosity",
help="Show only critical errors.",
)
parser.add_argument('-D', '--debug', action='store_const',
const=logging.DEBUG, dest='verbosity',
help='Show all messages, including debug messages.')
parser.add_argument(
"-D",
"--debug",
action="store_const",
const=logging.DEBUG,
dest="verbosity",
help="Show all messages, including debug messages.",
)
parser.add_argument('--version', action='version', version=__version__,
help='Print the pelican version and exit.')
parser.add_argument(
"--version",
action="version",
version=__version__,
help="Print the pelican version and exit.",
)
parser.add_argument('-r', '--autoreload', dest='autoreload',
action='store_true',
help='Relaunch pelican each time a modification occurs'
' on the content files.')
parser.add_argument(
"-r",
"--autoreload",
dest="autoreload",
action="store_true",
help="Relaunch pelican each time a modification occurs on the content files.",
)
parser.add_argument('--print-settings', dest='print_settings', nargs='*',
action=PrintSettings, metavar='SETTING_NAME',
help='Print current configuration settings and exit. '
'Append one or more setting name arguments to see the '
'values for specific settings only.')
parser.add_argument(
"--print-settings",
dest="print_settings",
nargs="*",
action=PrintSettings,
metavar="SETTING_NAME",
help="Print current configuration settings and exit. "
"Append one or more setting name arguments to see the "
"values for specific settings only.",
)
parser.add_argument('--relative-urls', dest='relative_paths',
action='store_true',
help='Use relative urls in output, '
'useful for site development')
parser.add_argument(
"--relative-urls",
dest="relative_paths",
action="store_true",
help="Use relative urls in output, useful for site development",
)
parser.add_argument('--cache-path', dest='cache_path',
help=('Directory in which to store cache files. '
'If not specified, defaults to "cache".'))
parser.add_argument(
"--cache-path",
dest="cache_path",
help=(
"Directory in which to store cache files. "
'If not specified, defaults to "cache".'
),
)
parser.add_argument('--ignore-cache', action='store_true',
dest='ignore_cache', help='Ignore content cache '
'from previous runs by not loading cache files.')
parser.add_argument(
"--ignore-cache",
action="store_true",
dest="ignore_cache",
help="Ignore content cache from previous runs by not loading cache files.",
)
parser.add_argument('-w', '--write-selected', type=str,
dest='selected_paths', default=None,
help='Comma separated list of selected paths to write')
parser.add_argument(
"--fatal",
metavar="errors|warnings",
choices=("errors", "warnings"),
default="",
help=(
"Exit the program with non-zero status if any errors/warnings encountered."
),
)
parser.add_argument('--fatal', metavar='errors|warnings',
choices=('errors', 'warnings'), default='',
help=('Exit the program with non-zero status if any '
'errors/warnings encountered.'))
parser.add_argument(
"--log-handler",
default="rich",
choices=LOG_HANDLERS,
help=(
"Which handler to use to format log messages. "
"The `rich` handler prints output in columns."
),
)
parser.add_argument('--logs-dedup-min-level', default='WARNING',
choices=('DEBUG', 'INFO', 'WARNING', 'ERROR'),
help=('Only enable log de-duplication for levels equal'
' to or above the specified value'))
parser.add_argument(
"--logs-dedup-min-level",
default="WARNING",
choices=("DEBUG", "INFO", "WARNING", "ERROR"),
help=(
"Only enable log de-duplication for levels equal"
" to or above the specified value"
),
)
parser.add_argument('-l', '--listen', dest='listen', action='store_true',
help='Serve content files via HTTP and port 8000.')
parser.add_argument(
"-l",
"--listen",
dest="listen",
action="store_true",
help="Serve content files via HTTP and port 8000.",
)
parser.add_argument('-p', '--port', dest='port', type=int,
help='Port to serve HTTP files at. (default: 8000)')
parser.add_argument(
"-p",
"--port",
dest="port",
type=int,
help="Port to serve HTTP files at. (default: 8000)",
)
parser.add_argument('-b', '--bind', dest='bind',
help='IP to bind to when serving files via HTTP '
'(default: 127.0.0.1)')
parser.add_argument(
"-b",
"--bind",
dest="bind",
help="IP to bind to when serving files via HTTP (default: 127.0.0.1)",
)
parser.add_argument('-e', '--extra-settings', dest='overrides',
help='Specify one or more SETTING=VALUE pairs to '
'override settings. If VALUE contains spaces, '
'add quotes: SETTING="VALUE". Values other than '
'integers and strings can be specified via JSON '
'notation. (e.g., SETTING=none)',
nargs='*',
action=ParseDict
)
parser.add_argument(
"-e",
"--extra-settings",
dest="overrides",
help="Specify one or more SETTING=VALUE pairs to "
"override settings. VALUE must be in JSON notation: "
"specify string values as SETTING='\"some string\"'; "
"booleans as SETTING=true or SETTING=false; "
"None as SETTING=null.",
nargs="*",
action=ParseOverrides,
default={},
)
args = parser.parse_args(argv)
if args.port is not None and not args.listen:
logger.warning('--port without --listen has no effect')
logger.warning("--port without --listen has no effect")
if args.bind is not None and not args.listen:
logger.warning('--bind without --listen has no effect')
logger.warning("--bind without --listen has no effect")
return args
def get_config(args):
"""Builds a config dictionary based on supplied `args`."""
config = {}
if args.path:
config['PATH'] = os.path.abspath(os.path.expanduser(args.path))
config["PATH"] = os.path.abspath(os.path.expanduser(args.path))
if args.output:
config['OUTPUT_PATH'] = \
os.path.abspath(os.path.expanduser(args.output))
config["OUTPUT_PATH"] = os.path.abspath(os.path.expanduser(args.output))
if args.theme:
abstheme = os.path.abspath(os.path.expanduser(args.theme))
config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme
config["THEME"] = abstheme if os.path.exists(abstheme) else args.theme
if args.delete_outputdir is not None:
config['DELETE_OUTPUT_DIRECTORY'] = args.delete_outputdir
config["DELETE_OUTPUT_DIRECTORY"] = args.delete_outputdir
if args.ignore_cache:
config['LOAD_CONTENT_CACHE'] = False
config["LOAD_CONTENT_CACHE"] = False
if args.cache_path:
config['CACHE_PATH'] = args.cache_path
if args.selected_paths:
config['WRITE_SELECTED'] = args.selected_paths.split(',')
config["CACHE_PATH"] = args.cache_path
if args.relative_paths:
config['RELATIVE_URLS'] = args.relative_paths
config["RELATIVE_URLS"] = args.relative_paths
if args.port is not None:
config['PORT'] = args.port
config["PORT"] = args.port
if args.bind is not None:
config['BIND'] = args.bind
config['DEBUG'] = args.verbosity == logging.DEBUG
config.update(coerce_overrides(args.overrides))
config["BIND"] = args.bind
config["DEBUG"] = args.verbosity == logging.DEBUG
config.update(args.overrides)
return config
def get_instance(args):
config_file = args.settings
if config_file is None and os.path.isfile(DEFAULT_CONFIG_NAME):
config_file = DEFAULT_CONFIG_NAME
@ -409,9 +554,9 @@ def get_instance(args):
settings = read_settings(config_file, override=get_config(args))
cls = settings['PELICAN_CLASS']
cls = settings["PELICAN_CLASS"]
if isinstance(cls, str):
module, cls_name = cls.rsplit('.', 1)
module, cls_name = cls.rsplit(".", 1)
module = __import__(module)
cls = getattr(module, cls_name)
@ -419,29 +564,25 @@ def get_instance(args):
def autoreload(args, excqueue=None):
print(' --- AutoReload Mode: Monitoring `content`, `theme` and'
' `settings` for changes. ---')
console.print(
" --- AutoReload Mode: Monitoring `content`, `theme` and"
" `settings` for changes. ---"
)
pelican, settings = get_instance(args)
watcher = FileSystemWatcher(args.settings, Readers, settings)
sleep = False
settings_file = os.path.abspath(args.settings)
while True:
try:
# Don't sleep first time, but sleep afterwards to reduce cpu load
if sleep:
time.sleep(0.5)
else:
sleep = True
pelican.run()
modified = watcher.check()
changed_files = wait_for_changes(args.settings, settings)
changed_files = {c[1] for c in changed_files}
if modified['settings']:
if settings_file in changed_files:
pelican, settings = get_instance(args)
watcher.update_watchers(settings)
if any(modified.values()):
print('\n-> Modified: {}. re-generating...'.format(
', '.join(k for k, v in modified.items() if v)))
pelican.run()
console.print(
"\n-> Modified: {}. re-generating...".format(", ".join(changed_files))
)
except KeyboardInterrupt:
if excqueue is not None:
@ -450,22 +591,24 @@ def autoreload(args, excqueue=None):
raise
except Exception as e:
if (args.verbosity == logging.DEBUG):
if args.verbosity == logging.DEBUG:
if excqueue is not None:
excqueue.put(
traceback.format_exception_only(type(e), e)[-1])
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
else:
raise
logger.warning(
'Caught exception:\n"%s".', e,
exc_info=settings.get('DEBUG', False))
'Caught exception:\n"%s".', e, exc_info=settings.get("DEBUG", False)
)
def listen(server, port, output, excqueue=None):
# set logging level to at least "INFO" (so we can see the server requests)
if logger.level < logging.INFO:
logger.setLevel(logging.INFO)
RootedHTTPServer.allow_reuse_address = True
try:
httpd = RootedHTTPServer(
output, (server, port), ComplexHTTPRequestHandler)
httpd = RootedHTTPServer(output, (server, port), ComplexHTTPRequestHandler)
except OSError as e:
logging.error("Could not listen on port %s, server %s.", port, server)
if excqueue is not None:
@ -473,8 +616,7 @@ def listen(server, port, output, excqueue=None):
return
try:
print("\nServing site at: http://{}:{} - Tap CTRL-C to stop".format(
server, port))
console.print(f"Serving site at: http://{server}:{port} - Tap CTRL-C to stop")
httpd.serve_forever()
except Exception as e:
if excqueue is not None:
@ -491,46 +633,55 @@ def listen(server, port, output, excqueue=None):
def main(argv=None):
args = parse_arguments(argv)
logs_dedup_min_level = getattr(logging, args.logs_dedup_min_level)
init_logging(args.verbosity, args.fatal,
logs_dedup_min_level=logs_dedup_min_level)
init_logging(
level=args.verbosity,
fatal=args.fatal,
name=__name__,
handler=LOG_HANDLERS[args.log_handler],
logs_dedup_min_level=logs_dedup_min_level,
)
logger.debug('Pelican version: %s', __version__)
logger.debug('Python version: %s', sys.version.split()[0])
logger.debug("Pelican version: %s", __version__)
logger.debug("Python version: %s", sys.version.split()[0])
try:
pelican, settings = get_instance(args)
if args.autoreload and args.listen:
excqueue = multiprocessing.Queue()
p1 = multiprocessing.Process(
target=autoreload,
args=(args, excqueue))
p1 = multiprocessing.Process(target=autoreload, args=(args, excqueue))
p2 = multiprocessing.Process(
target=listen,
args=(settings.get('BIND'), settings.get('PORT'),
settings.get("OUTPUT_PATH"), excqueue))
p1.start()
p2.start()
exc = excqueue.get()
p1.terminate()
p2.terminate()
if exc is not None:
logger.critical(exc)
args=(
settings.get("BIND"),
settings.get("PORT"),
settings.get("OUTPUT_PATH"),
excqueue,
),
)
try:
p1.start()
p2.start()
exc = excqueue.get()
if exc is not None:
logger.critical(exc)
finally:
p1.terminate()
p2.terminate()
elif args.autoreload:
autoreload(args)
elif args.listen:
listen(settings.get('BIND'), settings.get('PORT'),
settings.get("OUTPUT_PATH"))
listen(
settings.get("BIND"), settings.get("PORT"), settings.get("OUTPUT_PATH")
)
else:
watcher = FileSystemWatcher(args.settings, Readers, settings)
watcher.check()
pelican.run()
with console.status("Generating..."):
pelican.run()
except KeyboardInterrupt:
logger.warning('Keyboard interrupt received. Exiting.')
logger.warning("Keyboard interrupt received. Exiting.")
except Exception as e:
logger.critical('%s', e)
logger.critical("%s: %s", e.__class__.__name__, e)
if args.verbosity == logging.DEBUG:
raise
else:
sys.exit(getattr(e, 'exitcode', 1))
console.print_exception()
sys.exit(getattr(e, "exitcode", 1))

View file

@ -4,6 +4,5 @@ python -m pelican module entry point to run via python -m
from . import main
if __name__ == '__main__':
if __name__ == "__main__":
main()

View file

@ -1,3 +1,4 @@
import gzip
import hashlib
import logging
import os
@ -19,29 +20,33 @@ class FileDataCacher:
Sets caching policy according to *caching_policy*.
"""
self.settings = settings
self._cache_path = os.path.join(self.settings['CACHE_PATH'],
cache_name)
self._cache_path = os.path.join(self.settings["CACHE_PATH"], cache_name)
self._cache_data_policy = caching_policy
if self.settings['GZIP_CACHE']:
import gzip
if self.settings["GZIP_CACHE"]:
self._cache_open = gzip.open
else:
self._cache_open = open
if load_policy:
try:
with self._cache_open(self._cache_path, 'rb') as fhandle:
with self._cache_open(self._cache_path, "rb") as fhandle:
self._cache = pickle.load(fhandle)
except (OSError, UnicodeDecodeError) as err:
logger.debug('Cannot load cache %s (this is normal on first '
'run). Proceeding with empty cache.\n%s',
self._cache_path, err)
logger.debug(
"Cannot load cache %s (this is normal on first "
"run). Proceeding with empty cache.\n%s",
self._cache_path,
err,
)
self._cache = {}
except pickle.PickleError as err:
logger.warning('Cannot unpickle cache %s, cache may be using '
'an incompatible protocol (see pelican '
'caching docs). '
'Proceeding with empty cache.\n%s',
self._cache_path, err)
logger.warning(
"Cannot unpickle cache %s, cache may be using "
"an incompatible protocol (see pelican "
"caching docs). "
"Proceeding with empty cache.\n%s",
self._cache_path,
err,
)
self._cache = {}
else:
self._cache = {}
@ -62,26 +67,27 @@ class FileDataCacher:
"""Save the updated cache"""
if self._cache_data_policy:
try:
mkdir_p(self.settings['CACHE_PATH'])
with self._cache_open(self._cache_path, 'wb') as fhandle:
mkdir_p(self.settings["CACHE_PATH"])
with self._cache_open(self._cache_path, "wb") as fhandle:
pickle.dump(self._cache, fhandle)
except (OSError, pickle.PicklingError) as err:
logger.warning('Could not save cache %s\n ... %s',
self._cache_path, err)
except (OSError, pickle.PicklingError, TypeError) as err:
logger.warning(
"Could not save cache %s\n ... %s", self._cache_path, err
)
class FileStampDataCacher(FileDataCacher):
"""Subclass that also caches the stamp of the file"""
def __init__(self, settings, cache_name, caching_policy, load_policy):
"""This sublcass additionally sets filestamp function
"""This subclass additionally sets filestamp function
and base path for filestamping operations
"""
super().__init__(settings, cache_name, caching_policy, load_policy)
method = self.settings['CHECK_MODIFIED_METHOD']
if method == 'mtime':
method = self.settings["CHECK_MODIFIED_METHOD"]
if method == "mtime":
self._filestamp_func = os.path.getmtime
else:
try:
@ -89,12 +95,12 @@ class FileStampDataCacher(FileDataCacher):
def filestamp_func(filename):
"""return hash of file contents"""
with open(filename, 'rb') as fhandle:
with open(filename, "rb") as fhandle:
return hash_func(fhandle.read()).digest()
self._filestamp_func = filestamp_func
except AttributeError as err:
logger.warning('Could not get hashing function\n\t%s', err)
logger.warning("Could not get hashing function\n\t%s", err)
self._filestamp_func = None
def cache_data(self, filename, data):
@ -115,9 +121,8 @@ class FileStampDataCacher(FileDataCacher):
try:
return self._filestamp_func(filename)
except (OSError, TypeError) as err:
logger.warning('Cannot get modification stamp for %s\n\t%s',
filename, err)
return ''
logger.warning("Cannot get modification stamp for %s\n\t%s", filename, err)
return ""
def get_cached_data(self, filename, default=None):
"""Get the cached data for the given filename

View file

@ -5,18 +5,31 @@ import logging
import os
import re
from html import unescape
from urllib.parse import unquote, urljoin, urlparse, urlunparse
from typing import Any, Optional
from urllib.parse import ParseResult, unquote, urljoin, urlparse, urlunparse
try:
from zoneinfo import ZoneInfo
except ModuleNotFoundError:
from backports.zoneinfo import ZoneInfo
import pytz
from pelican.plugins import signals
from pelican.settings import DEFAULT_CONFIG
from pelican.utils import (deprecated_attribute, memoized, path_to_url,
posixize_path, sanitised_join, set_date_tzinfo,
slugify, truncate_html_words)
from pelican.settings import DEFAULT_CONFIG, Settings
# Import these so that they're avalaible when you import from pelican.contents.
from pelican.urlwrappers import (Author, Category, Tag, URLWrapper) # NOQA
# Import these so that they're available when you import from pelican.contents.
from pelican.urlwrappers import Author, Category, Tag, URLWrapper # NOQA
from pelican.utils import (
deprecated_attribute,
memoized,
path_to_url,
posixize_path,
sanitised_join,
set_date_tzinfo,
slugify,
truncate_html_paragraphs,
truncate_html_words,
)
logger = logging.getLogger(__name__)
@ -31,12 +44,22 @@ class Content:
:param context: The shared context between generators.
"""
@deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0))
default_template: Optional[str] = None
mandatory_properties: tuple[str, ...] = ()
@deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0))
def filename():
return None
def __init__(self, content, metadata=None, settings=None,
source_path=None, context=None):
def __init__(
self,
content: str,
metadata: Optional[dict[str, Any]] = None,
settings: Optional[Settings] = None,
source_path: Optional[str] = None,
context: Optional[dict[Any, Any]] = None,
):
if metadata is None:
metadata = {}
if settings is None:
@ -49,13 +72,13 @@ class Content:
self._context = context
self.translations = []
local_metadata = dict()
local_metadata = {}
local_metadata.update(metadata)
# set metadata as attributes
for key, value in local_metadata.items():
if key in ('save_as', 'url'):
key = 'override_' + key
if key in ("save_as", "url"):
key = "override_" + key
setattr(self, key.lower(), value)
# also keep track of the metadata attributes available
@ -66,53 +89,52 @@ class Content:
# First, read the authors from "authors", if not, fallback to "author"
# and if not use the settings defined one, if any.
if not hasattr(self, 'author'):
if hasattr(self, 'authors'):
if not hasattr(self, "author"):
if hasattr(self, "authors"):
self.author = self.authors[0]
elif 'AUTHOR' in settings:
self.author = Author(settings['AUTHOR'], settings)
elif "AUTHOR" in settings:
self.author = Author(settings["AUTHOR"], settings)
if not hasattr(self, 'authors') and hasattr(self, 'author'):
if not hasattr(self, "authors") and hasattr(self, "author"):
self.authors = [self.author]
# XXX Split all the following code into pieces, there is too much here.
# manage languages
self.in_default_lang = True
if 'DEFAULT_LANG' in settings:
default_lang = settings['DEFAULT_LANG'].lower()
if not hasattr(self, 'lang'):
if "DEFAULT_LANG" in settings:
default_lang = settings["DEFAULT_LANG"].lower()
if not hasattr(self, "lang"):
self.lang = default_lang
self.in_default_lang = (self.lang == default_lang)
self.in_default_lang = self.lang == default_lang
# create the slug if not existing, generate slug according to
# setting of SLUG_ATTRIBUTE
if not hasattr(self, 'slug'):
if (settings['SLUGIFY_SOURCE'] == 'title' and
hasattr(self, 'title')):
if not hasattr(self, "slug"):
if settings["SLUGIFY_SOURCE"] == "title" and hasattr(self, "title"):
value = self.title
elif (settings['SLUGIFY_SOURCE'] == 'basename' and
source_path is not None):
elif settings["SLUGIFY_SOURCE"] == "basename" and source_path is not None:
value = os.path.basename(os.path.splitext(source_path)[0])
else:
value = None
if value is not None:
self.slug = slugify(
value,
regex_subs=settings.get('SLUG_REGEX_SUBSTITUTIONS', []),
preserve_case=settings.get('SLUGIFY_PRESERVE_CASE', False),
use_unicode=settings.get('SLUGIFY_USE_UNICODE', False))
regex_subs=settings.get("SLUG_REGEX_SUBSTITUTIONS", []),
preserve_case=settings.get("SLUGIFY_PRESERVE_CASE", False),
use_unicode=settings.get("SLUGIFY_USE_UNICODE", False),
)
self.source_path = source_path
self.relative_source_path = self.get_relative_source_path()
# manage the date format
if not hasattr(self, 'date_format'):
if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:
self.date_format = settings['DATE_FORMATS'][self.lang]
if not hasattr(self, "date_format"):
if hasattr(self, "lang") and self.lang in settings["DATE_FORMATS"]:
self.date_format = settings["DATE_FORMATS"][self.lang]
else:
self.date_format = settings['DEFAULT_DATE_FORMAT']
self.date_format = settings["DEFAULT_DATE_FORMAT"]
if isinstance(self.date_format, tuple):
locale_string = self.date_format[0]
@ -120,43 +142,43 @@ class Content:
self.date_format = self.date_format[1]
# manage timezone
default_timezone = settings.get('TIMEZONE', 'UTC')
timezone = getattr(self, 'timezone', default_timezone)
self.timezone = pytz.timezone(timezone)
default_timezone = settings.get("TIMEZONE", "UTC")
timezone = getattr(self, "timezone", default_timezone)
self.timezone = ZoneInfo(timezone)
if hasattr(self, 'date'):
if hasattr(self, "date"):
self.date = set_date_tzinfo(self.date, timezone)
self.locale_date = self.date.strftime(self.date_format)
if hasattr(self, 'modified'):
if hasattr(self, "modified"):
self.modified = set_date_tzinfo(self.modified, timezone)
self.locale_modified = self.modified.strftime(self.date_format)
# manage status
if not hasattr(self, 'status'):
if not hasattr(self, "status"):
# Previous default of None broke comment plugins and perhaps others
self.status = getattr(self, 'default_status', '')
self.status = getattr(self, "default_status", "")
# store the summary metadata if it is set
if 'summary' in metadata:
self._summary = metadata['summary']
if "summary" in metadata:
self._summary = metadata["summary"]
signals.content_object_init.send(self)
def __str__(self):
def __str__(self) -> str:
return self.source_path or repr(self)
def _has_valid_mandatory_properties(self):
def _has_valid_mandatory_properties(self) -> bool:
"""Test mandatory properties are set."""
for prop in self.mandatory_properties:
if not hasattr(self, prop):
logger.error(
"Skipping %s: could not find information about '%s'",
self, prop)
"Skipping %s: could not find information about '%s'", self, prop
)
return False
return True
def _has_valid_save_as(self):
def _has_valid_save_as(self) -> bool:
"""Return true if save_as doesn't write outside output path, false
otherwise."""
try:
@ -177,58 +199,65 @@ class Content:
return True
def _has_valid_status(self):
if hasattr(self, 'allowed_statuses'):
def _has_valid_status(self) -> bool:
if hasattr(self, "allowed_statuses"):
if self.status not in self.allowed_statuses:
logger.error(
"Unknown status '%s' for file %s, skipping it.",
"Unknown status '%s' for file %s, skipping it. (Not in %s)",
self.status,
self
self,
self.allowed_statuses,
)
return False
# if undefined we allow all
return True
def is_valid(self):
def is_valid(self) -> bool:
"""Validate Content"""
# Use all() to not short circuit and get results of all validations
return all([self._has_valid_mandatory_properties(),
self._has_valid_save_as(),
self._has_valid_status()])
return all(
[
self._has_valid_mandatory_properties(),
self._has_valid_save_as(),
self._has_valid_status(),
]
)
@property
def url_format(self):
def url_format(self) -> dict[str, Any]:
"""Returns the URL, formatted with the proper values"""
metadata = copy.copy(self.metadata)
path = self.metadata.get('path', self.get_relative_source_path())
metadata.update({
'path': path_to_url(path),
'slug': getattr(self, 'slug', ''),
'lang': getattr(self, 'lang', 'en'),
'date': getattr(self, 'date', datetime.datetime.now()),
'author': self.author.slug if hasattr(self, 'author') else '',
'category': self.category.slug if hasattr(self, 'category') else ''
})
path = self.metadata.get("path", self.get_relative_source_path())
metadata.update(
{
"path": path_to_url(path),
"slug": getattr(self, "slug", ""),
"lang": getattr(self, "lang", "en"),
"date": getattr(self, "date", datetime.datetime.now()),
"author": self.author.slug if hasattr(self, "author") else "",
"category": self.category.slug if hasattr(self, "category") else "",
}
)
return metadata
def _expand_settings(self, key, klass=None):
def _expand_settings(self, key: str, klass: Optional[str] = None) -> str:
if not klass:
klass = self.__class__.__name__
fq_key = ('{}_{}'.format(klass, key)).upper()
return self.settings[fq_key].format(**self.url_format)
fq_key = (f"{klass}_{key}").upper()
return str(self.settings[fq_key]).format(**self.url_format)
def get_url_setting(self, key):
if hasattr(self, 'override_' + key):
return getattr(self, 'override_' + key)
key = key if self.in_default_lang else 'lang_%s' % key
def get_url_setting(self, key: str) -> str:
if hasattr(self, "override_" + key):
return getattr(self, "override_" + key)
key = key if self.in_default_lang else f"lang_{key}"
return self._expand_settings(key)
def _link_replacer(self, siteurl, m):
what = m.group('what')
value = urlparse(m.group('value'))
def _link_replacer(self, siteurl: str, m: re.Match) -> str:
what = m.group("what")
value = urlparse(m.group("value"))
path = value.path
origin = m.group('path')
origin = m.group("path")
# urllib.parse.urljoin() produces `a.html` for urljoin("..", "a.html")
# so if RELATIVE_URLS are enabled, we fall back to os.path.join() to
@ -236,7 +265,7 @@ class Content:
# `baz/http://foo/bar.html` for join("baz", "http://foo/bar.html")
# instead of correct "http://foo/bar.html", so one has to pick a side
# as there is no silver bullet.
if self.settings['RELATIVE_URLS']:
if self.settings["RELATIVE_URLS"]:
joiner = os.path.join
else:
joiner = urljoin
@ -246,20 +275,21 @@ class Content:
# os.path.join()), so in order to get a correct answer one needs to
# append a trailing slash to siteurl in that case. This also makes
# the new behavior fully compatible with Pelican 3.7.1.
if not siteurl.endswith('/'):
siteurl += '/'
if not siteurl.endswith("/"):
siteurl += "/"
# XXX Put this in a different location.
if what in {'filename', 'static', 'attach'}:
def _get_linked_content(key, url):
if what in {"filename", "static", "attach"}:
def _get_linked_content(key: str, url: ParseResult) -> Optional[Content]:
nonlocal value
def _find_path(path):
if path.startswith('/'):
def _find_path(path: str) -> Optional[Content]:
if path.startswith("/"):
path = path[1:]
else:
# relative to the source path of this content
path = self.get_relative_source_path(
path = self.get_relative_source_path( # type: ignore
os.path.join(self.relative_dir, path)
)
return self._context[key].get(path, None)
@ -282,69 +312,74 @@ class Content:
return result
# check if a static file is linked with {filename}
if what == 'filename' and key == 'generated_content':
linked_content = _get_linked_content('static_content', value)
if what == "filename" and key == "generated_content":
linked_content = _get_linked_content("static_content", value)
if linked_content:
logger.warning(
'{filename} used for linking to static'
' content %s in %s. Use {static} instead',
"{filename} used for linking to static"
" content %s in %s. Use {static} instead",
value.path,
self.get_relative_source_path())
self.get_relative_source_path(),
)
return linked_content
return None
if what == 'filename':
key = 'generated_content'
if what == "filename":
key = "generated_content"
else:
key = 'static_content'
key = "static_content"
linked_content = _get_linked_content(key, value)
if linked_content:
if what == 'attach':
linked_content.attach_to(self)
if what == "attach":
linked_content.attach_to(self) # type: ignore
origin = joiner(siteurl, linked_content.url)
origin = origin.replace('\\', '/') # for Windows paths.
origin = origin.replace("\\", "/") # for Windows paths.
else:
logger.warning(
"Unable to find '%s', skipping url replacement.",
value.geturl(), extra={
'limit_msg': ("Other resources were not found "
"and their urls not replaced")})
elif what == 'category':
value.geturl(),
extra={
"limit_msg": (
"Other resources were not found and their urls not replaced"
)
},
)
elif what == "category":
origin = joiner(siteurl, Category(path, self.settings).url)
elif what == 'tag':
elif what == "tag":
origin = joiner(siteurl, Tag(path, self.settings).url)
elif what == 'index':
origin = joiner(siteurl, self.settings['INDEX_SAVE_AS'])
elif what == 'author':
elif what == "index":
origin = joiner(siteurl, self.settings["INDEX_SAVE_AS"])
elif what == "author":
origin = joiner(siteurl, Author(path, self.settings).url)
else:
logger.warning(
"Replacement Indicator '%s' not recognized, "
"skipping replacement",
what)
"Replacement Indicator %r not recognized in %r, skipping replacement",
what,
origin,
)
# keep all other parts, such as query, fragment, etc.
parts = list(value)
parts[2] = origin
origin = urlunparse(parts)
return ''.join((m.group('markup'), m.group('quote'), origin,
m.group('quote')))
return "".join((m.group("markup"), m.group("quote"), origin, m.group("quote")))
def _get_intrasite_link_regex(self):
intrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']
regex = r"""
def _get_intrasite_link_regex(self) -> re.Pattern:
intrasite_link_regex = self.settings["INTRASITE_LINK_REGEX"]
regex = rf"""
(?P<markup><[^\>]+ # match tag with all url-value attributes
(?:href|src|poster|data|cite|formaction|action)\s*=\s*)
(?:href|src|poster|data|cite|formaction|action|content)\s*=\s*)
(?P<quote>["\']) # require value to be quoted
(?P<path>{}(?P<value>.*?)) # the url value
\2""".format(intrasite_link_regex)
(?P<path>{intrasite_link_regex}(?P<value>.*?)) # the url value
(?P=quote)"""
return re.compile(regex, re.X)
def _update_content(self, content, siteurl):
def _update_content(self, content: str, siteurl: str) -> str:
"""Update the content attribute.
Change all the relative paths of the content to relative paths
@ -360,98 +395,108 @@ class Content:
hrefs = self._get_intrasite_link_regex()
return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content)
def get_static_links(self):
def get_static_links(self) -> set[str]:
static_links = set()
hrefs = self._get_intrasite_link_regex()
for m in hrefs.finditer(self._content):
what = m.group('what')
value = urlparse(m.group('value'))
what = m.group("what")
value = urlparse(m.group("value"))
path = value.path
if what not in {'static', 'attach'}:
if what not in {"static", "attach"}:
continue
if path.startswith('/'):
if path.startswith("/"):
path = path[1:]
else:
# relative to the source path of this content
path = self.get_relative_source_path(
os.path.join(self.relative_dir, path)
)
path = path.replace('%20', ' ')
path = path.replace("%20", " ") # type: ignore
static_links.add(path)
return static_links
def get_siteurl(self):
return self._context.get('localsiteurl', '')
def get_siteurl(self) -> str:
return self._context.get("localsiteurl", "")
@memoized
def get_content(self, siteurl):
if hasattr(self, '_get_content'):
def get_content(self, siteurl: str) -> str:
if hasattr(self, "_get_content"):
content = self._get_content()
else:
content = self._content
return self._update_content(content, siteurl)
@property
def content(self):
def content(self) -> str:
return self.get_content(self.get_siteurl())
@memoized
def get_summary(self, siteurl):
def get_summary(self, _siteurl: str) -> str:
"""Returns the summary of an article.
This is based on the summary metadata if set, otherwise truncate the
content.
"""
if 'summary' in self.metadata:
return self.metadata['summary']
if "summary" in self.metadata:
return self.metadata["summary"]
if self.settings['SUMMARY_MAX_LENGTH'] is None:
return self.content
content = self.content
max_paragraphs = self.settings.get("SUMMARY_MAX_PARAGRAPHS")
if max_paragraphs is not None:
content = truncate_html_paragraphs(self.content, max_paragraphs)
return truncate_html_words(self.content,
self.settings['SUMMARY_MAX_LENGTH'],
self.settings['SUMMARY_END_SUFFIX'])
if self.settings["SUMMARY_MAX_LENGTH"] is None:
return content
return truncate_html_words(
content,
self.settings["SUMMARY_MAX_LENGTH"],
self.settings["SUMMARY_END_SUFFIX"],
)
@property
def summary(self):
def summary(self) -> str:
return self.get_summary(self.get_siteurl())
def _get_summary(self):
def _get_summary(self) -> str:
"""deprecated function to access summary"""
logger.warning('_get_summary() has been deprecated since 3.6.4. '
'Use the summary decorator instead')
logger.warning(
"_get_summary() has been deprecated since 3.6.4. "
"Use the summary decorator instead"
)
return self.summary
@summary.setter
def summary(self, value):
def summary(self, value: str):
"""Dummy function"""
pass
@property
def status(self):
def status(self) -> str:
return self._status
@status.setter
def status(self, value):
def status(self, value: str) -> None:
# TODO maybe typecheck
self._status = value.lower()
@property
def url(self):
return self.get_url_setting('url')
def url(self) -> str:
return self.get_url_setting("url")
@property
def save_as(self):
return self.get_url_setting('save_as')
def save_as(self) -> str:
return self.get_url_setting("save_as")
def _get_template(self):
if hasattr(self, 'template') and self.template is not None:
def _get_template(self) -> str:
if hasattr(self, "template") and self.template is not None:
return self.template
else:
return self.default_template
def get_relative_source_path(self, source_path=None):
def get_relative_source_path(
self, source_path: Optional[str] = None
) -> Optional[str]:
"""Return the relative path (from the content path) to the given
source_path.
@ -465,115 +510,136 @@ class Content:
return posixize_path(
os.path.relpath(
os.path.abspath(os.path.join(
self.settings['PATH'],
source_path)),
os.path.abspath(self.settings['PATH'])
))
os.path.abspath(os.path.join(self.settings["PATH"], source_path)),
os.path.abspath(self.settings["PATH"]),
)
)
@property
def relative_dir(self):
def relative_dir(self) -> str:
return posixize_path(
os.path.dirname(
os.path.relpath(
os.path.abspath(self.source_path),
os.path.abspath(self.settings['PATH']))))
def refresh_metadata_intersite_links(self):
for key in self.settings['FORMATTED_FIELDS']:
if key in self.metadata and key != 'summary':
value = self._update_content(
self.metadata[key],
self.get_siteurl()
os.path.abspath(self.settings["PATH"]),
)
)
)
def refresh_metadata_intersite_links(self) -> None:
for key in self.settings["FORMATTED_FIELDS"]:
if key in self.metadata and key != "summary":
value = self._update_content(self.metadata[key], self.get_siteurl())
self.metadata[key] = value
setattr(self, key.lower(), value)
# _summary is an internal variable that some plugins may be writing to,
# so ensure changes to it are picked up
if ('summary' in self.settings['FORMATTED_FIELDS'] and
'summary' in self.metadata):
self._summary = self._update_content(
self._summary,
self.get_siteurl()
)
self.metadata['summary'] = self._summary
# so ensure changes to it are picked up, and write summary back to it
if "summary" in self.settings["FORMATTED_FIELDS"]:
if hasattr(self, "_summary"):
self.metadata["summary"] = self._summary
if "summary" in self.metadata:
self.metadata["summary"] = self._update_content(
self.metadata["summary"], self.get_siteurl()
)
self._summary = self.metadata["summary"]
class SkipStub(Content):
"""Stub class representing content that should not be processed in any way."""
def __init__(
self, content, metadata=None, settings=None, source_path=None, context=None
):
del content, metadata, settings, context # Unused arguments
self.source_path = source_path
def is_valid(self):
return False
@property
def content(self):
raise NotImplementedError("Stub content should not be read")
@property
def save_as(self):
raise NotImplementedError("Stub content cannot be saved")
class Page(Content):
mandatory_properties = ('title',)
allowed_statuses = ('published', 'hidden', 'draft')
default_status = 'published'
default_template = 'page'
mandatory_properties = ("title",)
allowed_statuses = ("published", "hidden", "draft", "skip")
default_status = "published"
default_template = "page"
def _expand_settings(self, key):
klass = 'draft_page' if self.status == 'draft' else None
def _expand_settings(self, key: str) -> str:
klass = "draft_page" if self.status == "draft" else None
return super()._expand_settings(key, klass)
class Article(Content):
mandatory_properties = ('title', 'date', 'category')
allowed_statuses = ('published', 'draft')
default_status = 'published'
default_template = 'article'
mandatory_properties = ("title", "date", "category")
allowed_statuses = ("published", "hidden", "draft", "skip")
default_status = "published"
default_template = "article"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# handle WITH_FUTURE_DATES (designate article to draft based on date)
if not self.settings['WITH_FUTURE_DATES'] and hasattr(self, 'date'):
if not self.settings["WITH_FUTURE_DATES"] and hasattr(self, "date"):
if self.date.tzinfo is None:
now = datetime.datetime.now()
else:
now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
now = datetime.datetime.now(datetime.timezone.utc)
if self.date > now:
self.status = 'draft'
self.status = "draft"
# if we are a draft and there is no date provided, set max datetime
if not hasattr(self, 'date') and self.status == 'draft':
if not hasattr(self, "date") and self.status == "draft":
self.date = datetime.datetime.max.replace(tzinfo=self.timezone)
def _expand_settings(self, key):
klass = 'draft' if self.status == 'draft' else 'article'
def _expand_settings(self, key: str) -> str:
klass = "draft" if self.status == "draft" else "article"
return super()._expand_settings(key, klass)
class Static(Content):
mandatory_properties = ('title',)
default_status = 'published'
mandatory_properties = ("title",)
default_status = "published"
default_template = None
def __init__(self, *args, **kwargs):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._output_location_referenced = False
@deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))
@deprecated_attribute(old="filepath", new="source_path", since=(3, 2, 0))
def filepath():
return None
@deprecated_attribute(old='src', new='source_path', since=(3, 2, 0))
@deprecated_attribute(old="src", new="source_path", since=(3, 2, 0))
def src():
return None
@deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0))
@deprecated_attribute(old="dst", new="save_as", since=(3, 2, 0))
def dst():
return None
@property
def url(self):
def url(self) -> str:
# Note when url has been referenced, so we can avoid overriding it.
self._output_location_referenced = True
return super().url
@property
def save_as(self):
def save_as(self) -> str:
# Note when save_as has been referenced, so we can avoid overriding it.
self._output_location_referenced = True
return super().save_as
def attach_to(self, content):
"""Override our output directory with that of the given content object.
"""
def attach_to(self, content: Content) -> None:
"""Override our output directory with that of the given content object."""
# Determine our file's new output path relative to the linking
# document. If it currently lives beneath the linking
@ -584,8 +650,7 @@ class Static(Content):
tail_path = os.path.relpath(self.source_path, linking_source_dir)
if tail_path.startswith(os.pardir + os.sep):
tail_path = os.path.basename(tail_path)
new_save_as = os.path.join(
os.path.dirname(content.save_as), tail_path)
new_save_as = os.path.join(os.path.dirname(content.save_as), tail_path)
# We do not build our new url by joining tail_path with the linking
# document's url, because we cannot know just by looking at the latter
@ -598,18 +663,20 @@ class Static(Content):
new_url = path_to_url(new_save_as)
def _log_reason(reason):
def _log_reason(reason: str) -> None:
logger.warning(
"The {attach} link in %s cannot relocate "
"%s because %s. Falling back to "
"{filename} link behavior instead.",
content.get_relative_source_path(),
self.get_relative_source_path(), reason,
extra={'limit_msg': "More {attach} warnings silenced."})
self.get_relative_source_path(),
reason,
extra={"limit_msg": "More {attach} warnings silenced."},
)
# We never override an override, because we don't want to interfere
# with user-defined overrides that might be in EXTRA_PATH_METADATA.
if hasattr(self, 'override_save_as') or hasattr(self, 'override_url'):
if hasattr(self, "override_save_as") or hasattr(self, "override_url"):
if new_save_as != self.save_as or new_url != self.url:
_log_reason("its output location was already overridden")
return

File diff suppressed because it is too large Load diff

View file

@ -1,80 +1,13 @@
import logging
import os
import sys
import warnings
from collections import defaultdict
from collections.abc import Mapping
__all__ = [
'init'
]
from rich.console import Console
from rich.logging import RichHandler
__all__ = ["init"]
class BaseFormatter(logging.Formatter):
def __init__(self, fmt=None, datefmt=None):
FORMAT = '%(customlevelname)s %(message)s'
super().__init__(fmt=FORMAT, datefmt=datefmt)
def format(self, record):
customlevel = self._get_levelname(record.levelname)
record.__dict__['customlevelname'] = customlevel
# format multiline messages 'nicely' to make it clear they are together
record.msg = record.msg.replace('\n', '\n | ')
if not isinstance(record.args, Mapping):
record.args = tuple(arg.replace('\n', '\n | ') if
isinstance(arg, str) else
arg for arg in record.args)
return super().format(record)
def formatException(self, ei):
''' prefix traceback info for better representation '''
s = super().formatException(ei)
# fancy format traceback
s = '\n'.join(' | ' + line for line in s.splitlines())
# separate the traceback from the preceding lines
s = ' |___\n{}'.format(s)
return s
def _get_levelname(self, name):
''' NOOP: overridden by subclasses '''
return name
class ANSIFormatter(BaseFormatter):
ANSI_CODES = {
'red': '\033[1;31m',
'yellow': '\033[1;33m',
'cyan': '\033[1;36m',
'white': '\033[1;37m',
'bgred': '\033[1;41m',
'bggrey': '\033[1;100m',
'reset': '\033[0;m'}
LEVEL_COLORS = {
'INFO': 'cyan',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'bgred',
'DEBUG': 'bggrey'}
def _get_levelname(self, name):
color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')]
if name == 'INFO':
fmt = '{0}->{2}'
else:
fmt = '{0}{1}{2}:'
return fmt.format(color, name, self.ANSI_CODES['reset'])
class TextFormatter(BaseFormatter):
"""
Convert a `logging.LogRecord' object into text.
"""
def _get_levelname(self, name):
if name == 'INFO':
return '->'
else:
return name + ':'
console = Console()
class LimitFilter(logging.Filter):
@ -100,8 +33,8 @@ class LimitFilter(logging.Filter):
return True
# extract group
group = record.__dict__.get('limit_msg', None)
group_args = record.__dict__.get('limit_args', ())
group = record.__dict__.get("limit_msg", None)
group_args = record.__dict__.get("limit_args", ())
# ignore record if it was already raised
message_key = (record.levelno, record.getMessage())
@ -116,7 +49,7 @@ class LimitFilter(logging.Filter):
if logger_level > logging.DEBUG:
template_key = (record.levelno, record.msg)
message_key = (record.levelno, record.getMessage())
if (template_key in self._ignore or message_key in self._ignore):
if template_key in self._ignore or message_key in self._ignore:
return False
# check if we went over threshold
@ -153,56 +86,69 @@ class FatalLogger(LimitLogger):
warnings_fatal = False
errors_fatal = False
def warning(self, *args, **kwargs):
super().warning(*args, **kwargs)
if FatalLogger.warnings_fatal:
raise RuntimeError('Warning encountered')
def warning(self, *args, stacklevel=1, **kwargs):
"""
Displays a logging warning.
def error(self, *args, **kwargs):
super().error(*args, **kwargs)
Wrapping it here allows Pelican to filter warnings, and conditionally
make warnings fatal.
Args:
stacklevel (int): the stacklevel that would be used to display the
calling location, except for this function. Adjusting the
stacklevel allows you to see the "true" calling location of the
warning, rather than this wrapper location.
"""
stacklevel += 1
super().warning(*args, stacklevel=stacklevel, **kwargs)
if FatalLogger.warnings_fatal:
raise RuntimeError("Warning encountered")
def error(self, *args, stacklevel=1, **kwargs):
"""
Displays a logging error.
Wrapping it here allows Pelican to filter errors, and conditionally
make errors non-fatal.
Args:
stacklevel (int): the stacklevel that would be used to display the
calling location, except for this function. Adjusting the
stacklevel allows you to see the "true" calling location of the
error, rather than this wrapper location.
"""
stacklevel += 1
super().error(*args, stacklevel=stacklevel, **kwargs)
if FatalLogger.errors_fatal:
raise RuntimeError('Error encountered')
raise RuntimeError("Error encountered")
logging.setLoggerClass(FatalLogger)
# force root logger to be of our preferred class
logging.getLogger().__class__ = FatalLogger
def supports_color():
"""
Returns True if the running system's terminal supports color,
and False otherwise.
from django.core.management.color
"""
plat = sys.platform
supported_platform = plat != 'Pocket PC' and \
(plat != 'win32' or 'ANSICON' in os.environ)
# isatty is not always implemented, #6223.
is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
if not supported_platform or not is_a_tty:
return False
return True
DEFAULT_LOG_HANDLER = RichHandler(console=console)
def get_formatter():
if supports_color():
return ANSIFormatter()
else:
return TextFormatter()
def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
logs_dedup_min_level=None):
FatalLogger.warnings_fatal = fatal.startswith('warning')
def init(
level=None,
fatal="",
handler=DEFAULT_LOG_HANDLER,
name=None,
logs_dedup_min_level=None,
):
FatalLogger.warnings_fatal = fatal.startswith("warning")
FatalLogger.errors_fatal = bool(fatal)
logger = logging.getLogger(name)
LOG_FORMAT = "%(message)s"
logging.basicConfig(
level=level,
format=LOG_FORMAT,
datefmt="[%H:%M:%S]",
handlers=[handler] if handler else [],
)
handler.setFormatter(get_formatter())
logger.addHandler(handler)
logger = logging.getLogger(name)
if level:
logger.setLevel(level)
@ -211,18 +157,17 @@ def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
def log_warnings():
import warnings
logging.captureWarnings(True)
warnings.simplefilter("default", DeprecationWarning)
init(logging.DEBUG, name='py.warnings')
init(logging.DEBUG, name="py.warnings")
if __name__ == '__main__':
init(level=logging.DEBUG)
if __name__ == "__main__":
init(level=logging.DEBUG, name=__name__)
root_logger = logging.getLogger()
root_logger.debug('debug')
root_logger.info('info')
root_logger.warning('warning')
root_logger.error('error')
root_logger.critical('critical')
root_logger = logging.getLogger(__name__)
root_logger.debug("debug")
root_logger.info("info")
root_logger.warning("warning")
root_logger.error("error")
root_logger.critical("critical")

View file

@ -5,9 +5,9 @@ from collections import namedtuple
from math import ceil
logger = logging.getLogger(__name__)
PaginationRule = namedtuple(
'PaginationRule',
'min_page URL SAVE_AS',
PaginationRule = namedtuple( # noqa: PYI024
"PaginationRule",
"min_page URL SAVE_AS",
)
@ -19,7 +19,7 @@ class Paginator:
self.settings = settings
if per_page:
self.per_page = per_page
self.orphans = settings['DEFAULT_ORPHANS']
self.orphans = settings["DEFAULT_ORPHANS"]
else:
self.per_page = len(object_list)
self.orphans = 0
@ -32,22 +32,30 @@ class Paginator:
top = bottom + self.per_page
if top + self.orphans >= self.count:
top = self.count
return Page(self.name, self.url, self.object_list[bottom:top], number,
self, self.settings)
return Page(
self.name,
self.url,
self.object_list[bottom:top],
number,
self,
self.settings,
)
def _get_count(self):
"Returns the total number of objects, across all pages."
if self._count is None:
self._count = len(self.object_list)
return self._count
count = property(_get_count)
def _get_num_pages(self):
"Returns the total number of pages."
if self._num_pages is None:
hits = max(1, self.count - self.orphans)
self._num_pages = int(ceil(hits / (float(self.per_page) or 1)))
self._num_pages = ceil(hits / (float(self.per_page) or 1))
return self._num_pages
num_pages = property(_get_num_pages)
def _get_page_range(self):
@ -56,6 +64,7 @@ class Paginator:
a template for loop.
"""
return list(range(1, self.num_pages + 1))
page_range = property(_get_page_range)
@ -64,7 +73,7 @@ class Page:
self.full_name = name
self.name, self.extension = os.path.splitext(name)
dn, fn = os.path.split(name)
self.base_name = dn if fn in ('index.htm', 'index.html') else self.name
self.base_name = dn if fn in ("index.htm", "index.html") else self.name
self.base_url = url
self.object_list = object_list
self.number = number
@ -72,7 +81,7 @@ class Page:
self.settings = settings
def __repr__(self):
return '<Page {} of {}>'.format(self.number, self.paginator.num_pages)
return f"<Page {self.number} of {self.paginator.num_pages}>"
def has_next(self):
return self.number < self.paginator.num_pages
@ -117,32 +126,31 @@ class Page:
rule = None
# find the last matching pagination rule
for p in self.settings['PAGINATION_PATTERNS']:
for p in self.settings["PAGINATION_PATTERNS"]:
if p.min_page == -1:
if not self.has_next():
rule = p
break
else:
if p.min_page <= self.number:
rule = p
elif p.min_page <= self.number:
rule = p
if not rule:
return ''
return ""
prop_value = getattr(rule, key)
if not isinstance(prop_value, str):
logger.warning('%s is set to %s', key, prop_value)
logger.warning("%s is set to %s", key, prop_value)
return prop_value
# URL or SAVE_AS is a string, format it with a controlled context
context = {
'save_as': self.full_name,
'url': self.base_url,
'name': self.name,
'base_name': self.base_name,
'extension': self.extension,
'number': self.number,
"save_as": self.full_name,
"url": self.base_url,
"name": self.name,
"base_name": self.base_name,
"extension": self.extension,
"number": self.number,
}
ret = prop_value.format(**context)
@ -155,9 +163,9 @@ class Page:
# changed to lstrip() because that would remove all leading slashes and
# thus make the workaround impossible. See
# test_custom_pagination_pattern() for a verification of this.
if ret[0] == '/':
if ret.startswith("/"):
ret = ret[1:]
return ret
url = property(functools.partial(_from_settings, key='URL'))
save_as = property(functools.partial(_from_settings, key='SAVE_AS'))
url = property(functools.partial(_from_settings, key="URL"))
save_as = property(functools.partial(_from_settings, key="SAVE_AS"))

View file

@ -6,7 +6,6 @@ import logging
import pkgutil
import sys
logger = logging.getLogger(__name__)
@ -20,30 +19,46 @@ def iter_namespace(ns_pkg):
def get_namespace_plugins(ns_pkg=None):
if ns_pkg is None:
import pelican.plugins as ns_pkg
import pelican.plugins as ns_pkg # noqa: PLC0415
return {
name: importlib.import_module(name)
for finder, name, ispkg
in iter_namespace(ns_pkg)
for finder, name, ispkg in iter_namespace(ns_pkg)
if ispkg
}
def list_plugins(ns_pkg=None):
from pelican.log import init as init_logging
from pelican.log import init as init_logging # noqa: PLC0415
init_logging(logging.INFO)
ns_plugins = get_namespace_plugins(ns_pkg)
if ns_plugins:
logger.info('Plugins found:\n' + '\n'.join(ns_plugins))
logger.info("Plugins found:\n" + "\n".join(ns_plugins))
else:
logger.info('No plugins are installed')
logger.info("No plugins are installed")
def plugin_enabled(name, plugin_list=None):
if plugin_list is None or not plugin_list:
# no plugins are loaded
return False
if name in plugin_list:
# search name as is
return True
if f"pelican.plugins.{name}" in plugin_list:
# check if short name is a namespace plugin
return True
return False
def load_legacy_plugin(plugin, plugin_paths):
if '.' in plugin:
if "." in plugin:
# it is in a package, try to resolve package first
package, _, _ = plugin.rpartition('.')
package, _, _ = plugin.rpartition(".")
load_legacy_plugin(package, plugin_paths)
# Try to find plugin in PLUGIN_PATHS
@ -52,7 +67,7 @@ def load_legacy_plugin(plugin, plugin_paths):
# If failed, try to find it in normal importable locations
spec = importlib.util.find_spec(plugin)
if spec is None:
raise ImportError('Cannot import plugin `{}`'.format(plugin))
raise ImportError(f"Cannot import plugin `{plugin}`")
else:
# Avoid loading the same plugin twice
if spec.name in sys.modules:
@ -78,30 +93,28 @@ def load_legacy_plugin(plugin, plugin_paths):
def load_plugins(settings):
logger.debug('Finding namespace plugins')
logger.debug("Finding namespace plugins")
namespace_plugins = get_namespace_plugins()
if namespace_plugins:
logger.debug('Namespace plugins found:\n' +
'\n'.join(namespace_plugins))
logger.debug("Namespace plugins found:\n" + "\n".join(namespace_plugins))
plugins = []
if settings.get('PLUGINS') is not None:
for plugin in settings['PLUGINS']:
if settings.get("PLUGINS") is not None:
for plugin in settings["PLUGINS"]:
if isinstance(plugin, str):
logger.debug('Loading plugin `%s`', plugin)
logger.debug("Loading plugin `%s`", plugin)
# try to find in namespace plugins
if plugin in namespace_plugins:
plugin = namespace_plugins[plugin]
elif 'pelican.plugins.{}'.format(plugin) in namespace_plugins:
plugin = namespace_plugins['pelican.plugins.{}'.format(
plugin)]
elif f"pelican.plugins.{plugin}" in namespace_plugins:
plugin = namespace_plugins[f"pelican.plugins.{plugin}"]
# try to import it
else:
try:
plugin = load_legacy_plugin(
plugin,
settings.get('PLUGIN_PATHS', []))
plugin, settings.get("PLUGIN_PATHS", [])
)
except ImportError as e:
logger.error('Cannot load plugin `%s`\n%s', plugin, e)
logger.error("Cannot load plugin `%s`\n%s", plugin, e)
continue
plugins.append(plugin)
else:

View file

@ -1,49 +1,53 @@
from blinker import signal
from blinker import Signal, signal
from ordered_set import OrderedSet
# Signals will call functions in the order of connection, i.e. plugin order
Signal.set_class = OrderedSet
# Run-level signals:
initialized = signal('pelican_initialized')
get_generators = signal('get_generators')
all_generators_finalized = signal('all_generators_finalized')
get_writer = signal('get_writer')
finalized = signal('pelican_finalized')
initialized = signal("pelican_initialized")
get_generators = signal("get_generators")
all_generators_finalized = signal("all_generators_finalized")
get_writer = signal("get_writer")
finalized = signal("pelican_finalized")
# Reader-level signals
readers_init = signal('readers_init')
readers_init = signal("readers_init")
# Generator-level signals
generator_init = signal('generator_init')
generator_init = signal("generator_init")
article_generator_init = signal('article_generator_init')
article_generator_pretaxonomy = signal('article_generator_pretaxonomy')
article_generator_finalized = signal('article_generator_finalized')
article_generator_write_article = signal('article_generator_write_article')
article_writer_finalized = signal('article_writer_finalized')
article_generator_init = signal("article_generator_init")
article_generator_pretaxonomy = signal("article_generator_pretaxonomy")
article_generator_finalized = signal("article_generator_finalized")
article_generator_write_article = signal("article_generator_write_article")
article_writer_finalized = signal("article_writer_finalized")
page_generator_init = signal('page_generator_init')
page_generator_finalized = signal('page_generator_finalized')
page_generator_write_page = signal('page_generator_write_page')
page_writer_finalized = signal('page_writer_finalized')
page_generator_init = signal("page_generator_init")
page_generator_finalized = signal("page_generator_finalized")
page_generator_write_page = signal("page_generator_write_page")
page_writer_finalized = signal("page_writer_finalized")
static_generator_init = signal('static_generator_init')
static_generator_finalized = signal('static_generator_finalized')
static_generator_init = signal("static_generator_init")
static_generator_finalized = signal("static_generator_finalized")
# Page-level signals
article_generator_preread = signal('article_generator_preread')
article_generator_context = signal('article_generator_context')
article_generator_preread = signal("article_generator_preread")
article_generator_context = signal("article_generator_context")
page_generator_preread = signal('page_generator_preread')
page_generator_context = signal('page_generator_context')
page_generator_preread = signal("page_generator_preread")
page_generator_context = signal("page_generator_context")
static_generator_preread = signal('static_generator_preread')
static_generator_context = signal('static_generator_context')
static_generator_preread = signal("static_generator_preread")
static_generator_context = signal("static_generator_context")
content_object_init = signal('content_object_init')
content_object_init = signal("content_object_init")
# Writers signals
content_written = signal('content_written')
feed_generated = signal('feed_generated')
feed_written = signal('feed_written')
content_written = signal("content_written")
feed_generated = signal("feed_generated")
feed_written = signal("feed_written")

View file

@ -15,14 +15,14 @@ from docutils.writers.html4css1 import HTMLTranslator, Writer
from pelican import rstdirectives # NOQA
from pelican.cache import FileStampDataCacher
from pelican.contents import Author, Category, Page, Tag
from pelican.contents import Author, Category, Page, SkipStub, Tag
from pelican.plugins import signals
from pelican.utils import get_date, pelican_open, posixize_path
from pelican.utils import file_suffix, get_date, pelican_open, posixize_path
try:
from markdown import Markdown
except ImportError:
Markdown = False # NOQA
Markdown = False
# Metadata processors have no way to discard an unwanted value, so we have
# them return this value instead to signal that it should be discarded later.
@ -31,33 +31,29 @@ except ImportError:
_DISCARD = object()
DUPLICATES_DEFINITIONS_ALLOWED = {
'tags': False,
'date': False,
'modified': False,
'status': False,
'category': False,
'author': False,
'save_as': False,
'url': False,
'authors': False,
'slug': False
"tags": False,
"date": False,
"modified": False,
"status": False,
"category": False,
"author": False,
"save_as": False,
"url": False,
"authors": False,
"slug": False,
}
METADATA_PROCESSORS = {
'tags': lambda x, y: ([
Tag(tag, y)
for tag in ensure_metadata_list(x)
] or _DISCARD),
'date': lambda x, y: get_date(x.replace('_', ' ')),
'modified': lambda x, y: get_date(x),
'status': lambda x, y: x.strip() or _DISCARD,
'category': lambda x, y: _process_if_nonempty(Category, x, y),
'author': lambda x, y: _process_if_nonempty(Author, x, y),
'authors': lambda x, y: ([
Author(author, y)
for author in ensure_metadata_list(x)
] or _DISCARD),
'slug': lambda x, y: x.strip() or _DISCARD,
"tags": lambda x, y: ([Tag(tag, y) for tag in ensure_metadata_list(x)] or _DISCARD),
"date": lambda x, _y: get_date(x.replace("_", " ")),
"modified": lambda x, _y: get_date(x),
"status": lambda x, _y: x.strip() or _DISCARD,
"category": lambda x, y: _process_if_nonempty(Category, x, y),
"author": lambda x, y: _process_if_nonempty(Author, x, y),
"authors": lambda x, y: (
[Author(author, y) for author in ensure_metadata_list(x)] or _DISCARD
),
"slug": lambda x, _y: x.strip() or _DISCARD,
}
logger = logging.getLogger(__name__)
@ -65,25 +61,23 @@ logger = logging.getLogger(__name__)
def ensure_metadata_list(text):
"""Canonicalize the format of a list of authors or tags. This works
the same way as Docutils' "authors" field: if it's already a list,
those boundaries are preserved; otherwise, it must be a string;
if the string contains semicolons, it is split on semicolons;
otherwise, it is split on commas. This allows you to write
author lists in either "Jane Doe, John Doe" or "Doe, Jane; Doe, John"
format.
the same way as Docutils' "authors" field: if it's already a list,
those boundaries are preserved; otherwise, it must be a string;
if the string contains semicolons, it is split on semicolons;
otherwise, it is split on commas. This allows you to write
author lists in either "Jane Doe, John Doe" or "Doe, Jane; Doe, John"
format.
Regardless, all list items undergo .strip() before returning, and
empty items are discarded.
Regardless, all list items undergo .strip() before returning, and
empty items are discarded.
"""
if isinstance(text, str):
if ';' in text:
text = text.split(';')
if ";" in text:
text = text.split(";")
else:
text = text.split(',')
text = text.split(",")
return list(OrderedDict.fromkeys(
[v for v in (w.strip() for w in text) if v]
))
return list(OrderedDict.fromkeys([v for v in (w.strip() for w in text) if v]))
def _process_if_nonempty(processor, name, settings):
@ -112,8 +106,9 @@ class BaseReader:
Markdown).
"""
enabled = True
file_extensions = ['static']
file_extensions = ["static"]
extensions = None
def __init__(self, settings):
@ -126,19 +121,23 @@ class BaseReader:
def read(self, source_path):
"No-op parser"
del source_path # Unused argument
content = None
metadata = {}
return content, metadata
def disabled_message(self) -> str:
"""Message about why this plugin was disabled."""
return ""
class _FieldBodyTranslator(HTMLTranslator):
def __init__(self, document):
super().__init__(document)
self.compact_p = None
def astext(self):
return ''.join(self.body)
return "".join(self.body)
def visit_field_body(self, node):
pass
@ -154,27 +153,26 @@ def render_node_to_html(document, node, field_body_translator_class):
class PelicanHTMLWriter(Writer):
def __init__(self):
super().__init__()
self.translator_class = PelicanHTMLTranslator
class PelicanHTMLTranslator(HTMLTranslator):
def visit_abbreviation(self, node):
attrs = {}
if node.hasattr('explanation'):
attrs['title'] = node['explanation']
self.body.append(self.starttag(node, 'abbr', '', **attrs))
if node.hasattr("explanation"):
attrs["title"] = node["explanation"]
self.body.append(self.starttag(node, "abbr", "", **attrs))
def depart_abbreviation(self, node):
self.body.append('</abbr>')
del node # Unused argument
self.body.append("</abbr>")
def visit_image(self, node):
# set an empty alt if alt is not specified
# avoids that alt is taken from src
node['alt'] = node.get('alt', '')
node["alt"] = node.get("alt", "")
return HTMLTranslator.visit_image(self, node)
@ -194,7 +192,7 @@ class RstReader(BaseReader):
"""
enabled = bool(docutils)
file_extensions = ['rst']
file_extensions = ["rst"]
writer_class = PelicanHTMLWriter
field_body_translator_class = _FieldBodyTranslator
@ -202,38 +200,48 @@ class RstReader(BaseReader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
lang_code = self.settings.get('DEFAULT_LANG', 'en')
lang_code = self.settings.get("DEFAULT_LANG", "en")
if get_docutils_lang(lang_code):
self._language_code = lang_code
else:
logger.warning("Docutils has no localization for '%s'."
" Using 'en' instead.", lang_code)
self._language_code = 'en'
logger.warning(
"Docutils has no localization for '%s'. Using 'en' instead.",
lang_code,
)
self._language_code = "en"
def _parse_metadata(self, document, source_path):
"""Return the dict containing document metadata"""
formatted_fields = self.settings['FORMATTED_FIELDS']
formatted_fields = self.settings["FORMATTED_FIELDS"]
output = {}
if document.first_child_matching_class(docutils.nodes.title) is None:
logger.warning(
'Document title missing in file %s: '
'Ensure exactly one top level section',
source_path)
"Document title missing in file %s: "
"Ensure exactly one top level section",
source_path,
)
for docinfo in document.traverse(docutils.nodes.docinfo):
try:
# docutils 0.18.1+
nodes = document.findall(docutils.nodes.docinfo)
except AttributeError:
# docutils 0.18.0 or before
nodes = document.traverse(docutils.nodes.docinfo)
for docinfo in nodes:
for element in docinfo.children:
if element.tagname == 'field': # custom fields (e.g. summary)
if element.tagname == "field": # custom fields (e.g. summary)
name_elem, body_elem = element.children
name = name_elem.astext()
if name.lower() in formatted_fields:
value = render_node_to_html(
document, body_elem,
self.field_body_translator_class)
document, body_elem, self.field_body_translator_class
)
else:
value = body_elem.astext()
elif element.tagname == 'authors': # author list
elif element.tagname == "authors": # author list
name = element.tagname
value = [element.astext() for element in element.children]
else: # standard fields (e.g. address)
@ -245,22 +253,24 @@ class RstReader(BaseReader):
return output
def _get_publisher(self, source_path):
extra_params = {'initial_header_level': '2',
'syntax_highlight': 'short',
'input_encoding': 'utf-8',
'language_code': self._language_code,
'halt_level': 2,
'traceback': True,
'warning_stream': StringIO(),
'embed_stylesheet': False}
user_params = self.settings.get('DOCUTILS_SETTINGS')
extra_params = {
"initial_header_level": "2",
"syntax_highlight": "short",
"input_encoding": "utf-8",
"language_code": self._language_code,
"halt_level": 2,
"traceback": True,
"warning_stream": StringIO(),
"embed_stylesheet": False,
}
user_params = self.settings.get("DOCUTILS_SETTINGS")
if user_params:
extra_params.update(user_params)
pub = docutils.core.Publisher(
writer=self.writer_class(),
destination_class=docutils.io.StringOutput)
pub.set_components('standalone', 'restructuredtext', 'html')
writer=self.writer_class(), destination_class=docutils.io.StringOutput
)
pub.set_components("standalone", "restructuredtext", "html")
pub.process_programmatic_settings(None, extra_params, None)
pub.set_source(source_path=source_path)
pub.publish()
@ -270,10 +280,10 @@ class RstReader(BaseReader):
"""Parses restructured text"""
pub = self._get_publisher(source_path)
parts = pub.writer.parts
content = parts.get('body')
content = parts.get("body")
metadata = self._parse_metadata(pub.document, source_path)
metadata.setdefault('title', parts.get('title'))
metadata.setdefault("title", parts.get("title"))
return content, metadata
@ -282,26 +292,26 @@ class MarkdownReader(BaseReader):
"""Reader for Markdown files"""
enabled = bool(Markdown)
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
file_extensions = ["md", "markdown", "mkd", "mdown"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
settings = self.settings['MARKDOWN']
settings.setdefault('extension_configs', {})
settings.setdefault('extensions', [])
for extension in settings['extension_configs'].keys():
if extension not in settings['extensions']:
settings['extensions'].append(extension)
if 'markdown.extensions.meta' not in settings['extensions']:
settings['extensions'].append('markdown.extensions.meta')
settings = self.settings["MARKDOWN"]
settings.setdefault("extension_configs", {})
settings.setdefault("extensions", [])
for extension in settings["extension_configs"].keys():
if extension not in settings["extensions"]:
settings["extensions"].append(extension)
if "markdown.extensions.meta" not in settings["extensions"]:
settings["extensions"].append("markdown.extensions.meta")
self._source_path = None
def _parse_metadata(self, meta):
"""Return the dict containing document metadata"""
formatted_fields = self.settings['FORMATTED_FIELDS']
formatted_fields = self.settings["FORMATTED_FIELDS"]
# prevent metadata extraction in fields
self._md.preprocessors.deregister('meta')
self._md.preprocessors.deregister("meta")
output = {}
for name, value in meta.items():
@ -316,9 +326,10 @@ class MarkdownReader(BaseReader):
elif not DUPLICATES_DEFINITIONS_ALLOWED.get(name, True):
if len(value) > 1:
logger.warning(
'Duplicate definition of `%s` '
'for %s. Using first one.',
name, self._source_path)
"Duplicate definition of `%s` for %s. Using first one.",
name,
self._source_path,
)
output[name] = self.process_metadata(name, value[0])
elif len(value) > 1:
# handle list metadata as list of string
@ -332,31 +343,37 @@ class MarkdownReader(BaseReader):
"""Parse content and metadata of markdown files"""
self._source_path = source_path
self._md = Markdown(**self.settings['MARKDOWN'])
self._md = Markdown(**self.settings["MARKDOWN"])
with pelican_open(source_path) as text:
content = self._md.convert(text)
if hasattr(self._md, 'Meta'):
if hasattr(self._md, "Meta"):
metadata = self._parse_metadata(self._md.Meta)
else:
metadata = {}
return content, metadata
def disabled_message(self) -> str:
return (
"Could not import 'markdown.Markdown'. "
"Have you installed the 'markdown' package?"
)
class HTMLReader(BaseReader):
"""Parses HTML files as input, looking for meta, title, and body tags"""
file_extensions = ['htm', 'html']
file_extensions = ["htm", "html"]
enabled = True
class _HTMLParser(HTMLParser):
def __init__(self, settings, filename):
super().__init__(convert_charrefs=False)
self.body = ''
self.body = ""
self.metadata = {}
self.settings = settings
self._data_buffer = ''
self._data_buffer = ""
self._filename = filename
@ -367,94 +384,100 @@ class HTMLReader(BaseReader):
self._in_tags = False
def handle_starttag(self, tag, attrs):
if tag == 'head' and self._in_top_level:
if tag == "head" and self._in_top_level:
self._in_top_level = False
self._in_head = True
elif tag == 'title' and self._in_head:
elif tag == "title" and self._in_head:
self._in_title = True
self._data_buffer = ''
elif tag == 'body' and self._in_top_level:
self._data_buffer = ""
elif tag == "body" and self._in_top_level:
self._in_top_level = False
self._in_body = True
self._data_buffer = ''
elif tag == 'meta' and self._in_head:
self._data_buffer = ""
elif tag == "meta" and self._in_head:
self._handle_meta_tag(attrs)
elif self._in_body:
self._data_buffer += self.build_tag(tag, attrs, False)
def handle_endtag(self, tag):
if tag == 'head':
if tag == "head":
if self._in_head:
self._in_head = False
self._in_top_level = True
elif self._in_head and tag == 'title':
elif self._in_head and tag == "title":
self._in_title = False
self.metadata['title'] = self._data_buffer
elif tag == 'body':
self.metadata["title"] = self._data_buffer
elif tag == "body":
self.body = self._data_buffer
self._in_body = False
self._in_top_level = True
elif self._in_body:
self._data_buffer += '</{}>'.format(escape(tag))
self._data_buffer += f"</{escape(tag)}>"
def handle_startendtag(self, tag, attrs):
if tag == 'meta' and self._in_head:
if tag == "meta" and self._in_head:
self._handle_meta_tag(attrs)
if self._in_body:
self._data_buffer += self.build_tag(tag, attrs, True)
def handle_comment(self, data):
self._data_buffer += '<!--{}-->'.format(data)
self._data_buffer += f"<!--{data}-->"
def handle_data(self, data):
self._data_buffer += data
def handle_entityref(self, data):
self._data_buffer += '&{};'.format(data)
self._data_buffer += f"&{data};"
def handle_charref(self, data):
self._data_buffer += '&#{};'.format(data)
self._data_buffer += f"&#{data};"
def build_tag(self, tag, attrs, close_tag):
result = '<{}'.format(escape(tag))
result = f"<{escape(tag)}"
for k, v in attrs:
result += ' ' + escape(k)
result += " " + escape(k)
if v is not None:
# If the attribute value contains a double quote, surround
# with single quotes, otherwise use double quotes.
if '"' in v:
result += "='{}'".format(escape(v, quote=False))
result += f"='{escape(v, quote=False)}'"
else:
result += '="{}"'.format(escape(v, quote=False))
result += f'="{escape(v, quote=False)}"'
if close_tag:
return result + ' />'
return result + '>'
return result + " />"
return result + ">"
def _handle_meta_tag(self, attrs):
name = self._attr_value(attrs, 'name')
name = self._attr_value(attrs, "name")
if name is None:
attr_list = ['{}="{}"'.format(k, v) for k, v in attrs]
attr_serialized = ', '.join(attr_list)
logger.warning("Meta tag in file %s does not have a 'name' "
"attribute, skipping. Attributes: %s",
self._filename, attr_serialized)
attr_list = [f'{k}="{v}"' for k, v in attrs]
attr_serialized = ", ".join(attr_list)
logger.warning(
"Meta tag in file %s does not have a 'name' "
"attribute, skipping. Attributes: %s",
self._filename,
attr_serialized,
)
return
name = name.lower()
contents = self._attr_value(attrs, 'content', '')
contents = self._attr_value(attrs, "content", "")
if not contents:
contents = self._attr_value(attrs, 'contents', '')
contents = self._attr_value(attrs, "contents", "")
if contents:
logger.warning(
"Meta tag attribute 'contents' used in file %s, should"
" be changed to 'content'",
self._filename,
extra={'limit_msg': "Other files have meta tag "
"attribute 'contents' that should "
"be changed to 'content'"})
extra={
"limit_msg": "Other files have meta tag "
"attribute 'contents' that should "
"be changed to 'content'"
},
)
if name == 'keywords':
name = 'tags'
if name == "keywords":
name = "tags"
if name in self.metadata:
# if this metadata already exists (i.e. a previous tag with the
@ -494,22 +517,29 @@ class Readers(FileStampDataCacher):
"""
def __init__(self, settings=None, cache_name=''):
def __init__(self, settings=None, cache_name=""):
self.settings = settings or {}
self.readers = {}
self.disabled_readers = {}
# extension => reader for readers that are enabled
self.reader_classes = {}
# extension => reader for readers that are not enabled
disabled_reader_classes = {}
for cls in [BaseReader] + BaseReader.__subclasses__():
if not cls.enabled:
logger.debug('Missing dependencies for %s',
', '.join(cls.file_extensions))
continue
logger.debug(
"Missing dependencies for %s", ", ".join(cls.file_extensions)
)
for ext in cls.file_extensions:
self.reader_classes[ext] = cls
if cls.enabled:
self.reader_classes[ext] = cls
else:
disabled_reader_classes[ext] = cls
if self.settings['READERS']:
self.reader_classes.update(self.settings['READERS'])
if self.settings["READERS"]:
self.reader_classes.update(self.settings["READERS"])
signals.readers_init.send(self)
@ -519,74 +549,97 @@ class Readers(FileStampDataCacher):
self.readers[fmt] = reader_class(self.settings)
for fmt, reader_class in disabled_reader_classes.items():
self.disabled_readers[fmt] = reader_class(self.settings)
# set up caching
cache_this_level = (cache_name != '' and
self.settings['CONTENT_CACHING_LAYER'] == 'reader')
caching_policy = cache_this_level and self.settings['CACHE_CONTENT']
load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE']
cache_this_level = (
cache_name != "" and self.settings["CONTENT_CACHING_LAYER"] == "reader"
)
caching_policy = cache_this_level and self.settings["CACHE_CONTENT"]
load_policy = cache_this_level and self.settings["LOAD_CONTENT_CACHE"]
super().__init__(settings, cache_name, caching_policy, load_policy)
@property
def extensions(self):
"""File extensions that will be processed by a reader."""
return self.readers.keys()
def read_file(self, base_path, path, content_class=Page, fmt=None,
context=None, preread_signal=None, preread_sender=None,
context_signal=None, context_sender=None):
@property
def disabled_extensions(self):
return self.disabled_readers.keys()
def read_file(
self,
base_path,
path,
content_class=Page,
fmt=None,
context=None,
preread_signal=None,
preread_sender=None,
context_signal=None,
context_sender=None,
):
"""Return a content object parsed with the given format."""
path = os.path.abspath(os.path.join(base_path, path))
source_path = posixize_path(os.path.relpath(path, base_path))
logger.debug(
'Read file %s -> %s',
source_path, content_class.__name__)
logger.debug("Read file %s -> %s", source_path, content_class.__name__)
if not fmt:
_, ext = os.path.splitext(os.path.basename(path))
fmt = ext[1:]
fmt = file_suffix(path)
if fmt not in self.readers:
raise TypeError(
'Pelican does not know how to parse %s', path)
raise TypeError("Pelican does not know how to parse %s", path)
if preread_signal:
logger.debug(
'Signal %s.send(%s)',
preread_signal.name, preread_sender)
logger.debug("Signal %s.send(%s)", preread_signal.name, preread_sender)
preread_signal.send(preread_sender)
reader = self.readers[fmt]
metadata = _filter_discardable_metadata(default_metadata(
settings=self.settings, process=reader.process_metadata))
metadata.update(path_metadata(
full_path=path, source_path=source_path,
settings=self.settings))
metadata.update(_filter_discardable_metadata(parse_path_metadata(
source_path=source_path, settings=self.settings,
process=reader.process_metadata)))
metadata = _filter_discardable_metadata(
default_metadata(settings=self.settings, process=reader.process_metadata)
)
metadata.update(
path_metadata(
full_path=path, source_path=source_path, settings=self.settings
)
)
metadata.update(
_filter_discardable_metadata(
parse_path_metadata(
source_path=source_path,
settings=self.settings,
process=reader.process_metadata,
)
)
)
reader_name = reader.__class__.__name__
metadata['reader'] = reader_name.replace('Reader', '').lower()
metadata["reader"] = reader_name.replace("Reader", "").lower()
content, reader_metadata = self.get_cached_data(path, (None, None))
if content is None:
content, reader_metadata = reader.read(path)
reader_metadata = _filter_discardable_metadata(reader_metadata)
self.cache_data(path, (content, reader_metadata))
metadata.update(_filter_discardable_metadata(reader_metadata))
metadata.update(reader_metadata)
if content:
# find images with empty alt
find_empty_alt(content, path)
# eventually filter the content with typogrify if asked so
if self.settings['TYPOGRIFY']:
from typogrify.filters import typogrify
import smartypants
if self.settings["TYPOGRIFY"]:
# typogrify is an optional feature, user may not have it installed
import smartypants # noqa: PLC0415
from typogrify.filters import typogrify # noqa: PLC0415
typogrify_dashes = self.settings['TYPOGRIFY_DASHES']
if typogrify_dashes == 'oldschool':
typogrify_dashes = self.settings["TYPOGRIFY_DASHES"]
if typogrify_dashes == "oldschool":
smartypants.Attr.default = smartypants.Attr.set2
elif typogrify_dashes == 'oldschool_inverted':
elif typogrify_dashes == "oldschool_inverted":
smartypants.Attr.default = smartypants.Attr.set3
else:
smartypants.Attr.default = smartypants.Attr.set1
@ -598,33 +651,54 @@ class Readers(FileStampDataCacher):
smartypants.Attr.default |= smartypants.Attr.w
def typogrify_wrapper(text):
"""Ensures ignore_tags feature is backward compatible"""
"""Ensure compatibility with older versions of Typogrify.
The 'TYPOGRIFY_IGNORE_TAGS' and/or 'TYPOGRIFY_OMIT_FILTERS'
settings will be ignored if the installed version of Typogrify
doesn't have the corresponding features."""
try:
return typogrify(
text,
self.settings['TYPOGRIFY_IGNORE_TAGS'])
self.settings["TYPOGRIFY_IGNORE_TAGS"],
**dict.fromkeys(self.settings["TYPOGRIFY_OMIT_FILTERS"], False),
)
except TypeError:
return typogrify(text)
try:
typogrify(text, self.settings["TYPOGRIFY_IGNORE_TAGS"])
except TypeError:
return typogrify(text)
if content:
content = typogrify_wrapper(content)
if 'title' in metadata:
metadata['title'] = typogrify_wrapper(metadata['title'])
if "title" in metadata:
metadata["title"] = typogrify_wrapper(metadata["title"])
if 'summary' in metadata:
metadata['summary'] = typogrify_wrapper(metadata['summary'])
if "summary" in metadata:
metadata["summary"] = typogrify_wrapper(metadata["summary"])
if context_signal:
logger.debug(
'Signal %s.send(%s, <metadata>)',
context_signal.name,
context_sender)
"Signal %s.send(%s, <metadata>)", context_signal.name, context_sender
)
context_signal.send(context_sender, metadata=metadata)
return content_class(content=content, metadata=metadata,
settings=self.settings, source_path=path,
context=context)
if metadata.get("status") == "skip":
content_class = SkipStub
return content_class(
content=content,
metadata=metadata,
settings=self.settings,
source_path=path,
context=context,
)
def check_file(self, source_path: str) -> None:
"""Log a warning if a file is processed by a disabled reader."""
reader = self.disabled_readers.get(file_suffix(source_path), None)
if reader:
logger.warning(f"{source_path}: {reader.disabled_message()}")
def find_empty_alt(content, path):
@ -634,7 +708,8 @@ def find_empty_alt(content, path):
as they are really likely to be accessibility flaws.
"""
imgs = re.compile(r"""
imgs = re.compile(
r"""
(?:
# src before alt
<img
@ -650,53 +725,57 @@ def find_empty_alt(content, path):
[^\>]*
src=(['"])(.*?)\5
)
""", re.X)
""",
re.X,
)
for match in re.findall(imgs, content):
logger.warning(
'Empty alt attribute for image %s in %s',
os.path.basename(match[1] + match[5]), path,
extra={'limit_msg': 'Other images have empty alt attributes'})
"Empty alt attribute for image %s in %s",
os.path.basename(match[1] + match[5]),
path,
extra={"limit_msg": "Other images have empty alt attributes"},
)
def default_metadata(settings=None, process=None):
metadata = {}
if settings:
for name, value in dict(settings.get('DEFAULT_METADATA', {})).items():
for name, value in dict(settings.get("DEFAULT_METADATA", {})).items():
if process:
value = process(name, value)
metadata[name] = value
if 'DEFAULT_CATEGORY' in settings:
value = settings['DEFAULT_CATEGORY']
if "DEFAULT_CATEGORY" in settings:
value = settings["DEFAULT_CATEGORY"]
if process:
value = process('category', value)
metadata['category'] = value
if settings.get('DEFAULT_DATE', None) and \
settings['DEFAULT_DATE'] != 'fs':
if isinstance(settings['DEFAULT_DATE'], str):
metadata['date'] = get_date(settings['DEFAULT_DATE'])
value = process("category", value)
metadata["category"] = value
if settings.get("DEFAULT_DATE", None) and settings["DEFAULT_DATE"] != "fs":
if isinstance(settings["DEFAULT_DATE"], str):
metadata["date"] = get_date(settings["DEFAULT_DATE"])
else:
metadata['date'] = datetime.datetime(*settings['DEFAULT_DATE'])
metadata["date"] = datetime.datetime(*settings["DEFAULT_DATE"])
return metadata
def path_metadata(full_path, source_path, settings=None):
metadata = {}
if settings:
if settings.get('DEFAULT_DATE', None) == 'fs':
metadata['date'] = datetime.datetime.fromtimestamp(
os.stat(full_path).st_mtime)
metadata['modified'] = metadata['date']
if settings.get("DEFAULT_DATE", None) == "fs":
metadata["date"] = datetime.datetime.fromtimestamp(
os.stat(full_path).st_mtime
)
metadata["modified"] = metadata["date"]
# Apply EXTRA_PATH_METADATA for the source path and the paths of any
# parent directories. Sorting EPM first ensures that the most specific
# path wins conflicts.
epm = settings.get('EXTRA_PATH_METADATA', {})
epm = settings.get("EXTRA_PATH_METADATA", {})
for path, meta in sorted(epm.items()):
# Enforce a trailing slash when checking for parent directories.
# This prevents false positives when one file or directory's name
# is a prefix of another's.
dirpath = posixize_path(os.path.join(path, ''))
dirpath = posixize_path(os.path.join(path, ""))
if source_path == path or source_path.startswith(dirpath):
metadata.update(meta)
@ -728,11 +807,10 @@ def parse_path_metadata(source_path, settings=None, process=None):
subdir = os.path.basename(dirname)
if settings:
checks = []
for key, data in [('FILENAME_METADATA', base),
('PATH_METADATA', source_path)]:
for key, data in [("FILENAME_METADATA", base), ("PATH_METADATA", source_path)]:
checks.append((settings.get(key, None), data))
if settings.get('USE_FOLDER_AS_CATEGORY', None):
checks.append(('(?P<category>.*)', subdir))
if settings.get("USE_FOLDER_AS_CATEGORY", None):
checks.append(("(?P<category>.*)", subdir))
for regexp, data in checks:
if regexp and data:
match = re.match(regexp, data)

View file

@ -2,7 +2,6 @@ import re
from docutils import nodes, utils
from docutils.parsers.rst import Directive, directives, roles
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import TextLexer, get_lexer_by_name
@ -11,26 +10,26 @@ import pelican.settings as pys
class Pygments(Directive):
""" Source code syntax highlighting.
"""
"""Source code syntax highlighting."""
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
'anchorlinenos': directives.flag,
'classprefix': directives.unchanged,
'hl_lines': directives.unchanged,
'lineanchors': directives.unchanged,
'linenos': directives.unchanged,
'linenospecial': directives.nonnegative_int,
'linenostart': directives.nonnegative_int,
'linenostep': directives.nonnegative_int,
'lineseparator': directives.unchanged,
'linespans': directives.unchanged,
'nobackground': directives.flag,
'nowrap': directives.flag,
'tagsfile': directives.unchanged,
'tagurlformat': directives.unchanged,
"anchorlinenos": directives.flag,
"classprefix": directives.unchanged,
"hl_lines": directives.unchanged,
"lineanchors": directives.unchanged,
"linenos": directives.unchanged,
"linenospecial": directives.nonnegative_int,
"linenostart": directives.nonnegative_int,
"linenostep": directives.nonnegative_int,
"lineseparator": directives.unchanged,
"linespans": directives.unchanged,
"nobackground": directives.flag,
"nowrap": directives.flag,
"tagsfile": directives.unchanged,
"tagurlformat": directives.unchanged,
}
has_content = True
@ -49,42 +48,45 @@ class Pygments(Directive):
if k not in self.options:
self.options[k] = v
if ('linenos' in self.options and
self.options['linenos'] not in ('table', 'inline')):
if self.options['linenos'] == 'none':
self.options.pop('linenos')
if "linenos" in self.options and self.options["linenos"] not in (
"table",
"inline",
):
if self.options["linenos"] == "none":
self.options.pop("linenos")
else:
self.options['linenos'] = 'table'
self.options["linenos"] = "table"
for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
for flag in ("nowrap", "nobackground", "anchorlinenos"):
if flag in self.options:
self.options[flag] = True
# noclasses should already default to False, but just in case...
formatter = HtmlFormatter(noclasses=False, **self.options)
parsed = highlight('\n'.join(self.content), lexer, formatter)
return [nodes.raw('', parsed, format='html')]
parsed = highlight("\n".join(self.content), lexer, formatter)
return [nodes.raw("", parsed, format="html")]
directives.register_directive('code-block', Pygments)
directives.register_directive('sourcecode', Pygments)
directives.register_directive("code-block", Pygments)
directives.register_directive("sourcecode", Pygments)
_abbr_re = re.compile(r'\((.*)\)$', re.DOTALL)
_abbr_re = re.compile(r"\((.*)\)$", re.DOTALL)
class abbreviation(nodes.Inline, nodes.TextElement):
pass
def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
def abbr_role(typ, rawtext, text, lineno, inliner, options=None, content=None):
del typ, rawtext, lineno, inliner, options, content # Unused arguments
text = utils.unescape(text)
m = _abbr_re.search(text)
if m is None:
return [abbreviation(text, text)], []
abbr = text[:m.start()].strip()
abbr = text[: m.start()].strip()
expl = m.group(1)
return [abbreviation(abbr, abbr, explanation=expl)], []
roles.register_local_role('abbr', abbr_role)
roles.register_local_role("abbr", abbr_role)

View file

@ -12,45 +12,64 @@ try:
except ImportError:
magic_from_file = None
from pelican.log import console # noqa: F401
from pelican.log import init as init_logging
logger = logging.getLogger(__name__)
def parse_arguments():
parser = argparse.ArgumentParser(
description='Pelican Development Server',
formatter_class=argparse.ArgumentDefaultsHelpFormatter
description="Pelican Development Server",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"port", default=8000, type=int, nargs="?", help="Port to Listen On"
)
parser.add_argument("server", default="", nargs="?", help="Interface to Listen On")
parser.add_argument("--ssl", action="store_true", help="Activate SSL listener")
parser.add_argument(
"--cert",
default="./cert.pem",
nargs="?",
help="Path to certificate file. Relative to current directory",
)
parser.add_argument(
"--key",
default="./key.pem",
nargs="?",
help="Path to certificate key file. Relative to current directory",
)
parser.add_argument(
"--path",
default=".",
help="Path to pelican source directory to serve. Relative to current directory",
)
parser.add_argument("port", default=8000, type=int, nargs="?",
help="Port to Listen On")
parser.add_argument("server", default="", nargs="?",
help="Interface to Listen On")
parser.add_argument('--ssl', action="store_true",
help='Activate SSL listener')
parser.add_argument('--cert', default="./cert.pem", nargs="?",
help='Path to certificate file. ' +
'Relative to current directory')
parser.add_argument('--key', default="./key.pem", nargs="?",
help='Path to certificate key file. ' +
'Relative to current directory')
parser.add_argument('--path', default=".",
help='Path to pelican source directory to serve. ' +
'Relative to current directory')
return parser.parse_args()
class ComplexHTTPRequestHandler(server.SimpleHTTPRequestHandler):
SUFFIXES = ['.html', '/index.html', '/', '']
SUFFIXES = [".html", "/index.html", "/", ""]
extensions_map = {
**server.SimpleHTTPRequestHandler.extensions_map,
# web fonts
".oft": "font/oft",
".sfnt": "font/sfnt",
".ttf": "font/ttf",
".woff": "font/woff",
".woff2": "font/woff2",
}
def translate_path(self, path):
# abandon query parameters
path = path.split('?', 1)[0]
path = path.split('#', 1)[0]
path = path.split("?", 1)[0]
path = path.split("#", 1)[0]
# Don't forget explicit trailing slash when normalizing. Issue17324
trailing_slash = path.rstrip().endswith('/')
trailing_slash = path.rstrip().endswith("/")
path = urllib.parse.unquote(path)
path = posixpath.normpath(path)
words = path.split('/')
words = path.split("/")
words = filter(None, words)
path = self.base_path
for word in words:
@ -59,12 +78,12 @@ class ComplexHTTPRequestHandler(server.SimpleHTTPRequestHandler):
continue
path = os.path.join(path, word)
if trailing_slash:
path += '/'
path += "/"
return path
def do_GET(self):
# cut off a query string
original_path = self.path.split('?', 1)[0]
original_path = self.path.split("?", 1)[0]
# try to find file
self.path = self.get_path_that_exists(original_path)
@ -75,30 +94,37 @@ class ComplexHTTPRequestHandler(server.SimpleHTTPRequestHandler):
def get_path_that_exists(self, original_path):
# Try to strip trailing slash
original_path = original_path.rstrip('/')
trailing_slash = original_path.endswith("/")
original_path = original_path.rstrip("/")
# Try to detect file by applying various suffixes
tries = []
for suffix in self.SUFFIXES:
if not trailing_slash and suffix == "/":
# if original request does not have trailing slash, skip the '/' suffix
# so that base class can redirect if needed
continue
path = original_path + suffix
if os.path.exists(self.translate_path(path)):
return path
tries.append(path)
logger.warning("Unable to find `%s` or variations:\n%s",
original_path,
'\n'.join(tries))
logger.warning(
"Unable to find `%s` or variations:\n%s", original_path, "\n".join(tries)
)
return None
def guess_type(self, path):
"""Guess at the mime type for the specified file.
"""
"""Guess at the mime type for the specified file."""
mimetype = server.SimpleHTTPRequestHandler.guess_type(self, path)
# If the default guess is too generic, try the python-magic library
if mimetype == 'application/octet-stream' and magic_from_file:
if mimetype == "application/octet-stream" and magic_from_file:
mimetype = magic_from_file(path, mime=True)
return mimetype
def log_message(self, msg_format, *args):
logger.info(msg_format, *args)
class RootedHTTPServer(server.HTTPServer):
def __init__(self, base_path, *args, **kwargs):
@ -106,31 +132,33 @@ class RootedHTTPServer(server.HTTPServer):
self.RequestHandlerClass.base_path = base_path
if __name__ == '__main__':
if __name__ == "__main__":
init_logging(level=logging.INFO)
logger.warning("'python -m pelican.server' is deprecated.\nThe "
"Pelican development server should be run via "
"'pelican --listen' or 'pelican -l'.\nThis can be combined "
"with regeneration as 'pelican -lr'.\nRerun 'pelican-"
"quickstart' to get new Makefile and tasks.py files.")
logger.warning(
"'python -m pelican.server' is deprecated.\nThe "
"Pelican development server should be run via "
"'pelican --listen' or 'pelican -l'.\nThis can be combined "
"with regeneration as 'pelican -lr'.\nRerun 'pelican-"
"quickstart' to get new Makefile and tasks.py files."
)
args = parse_arguments()
RootedHTTPServer.allow_reuse_address = True
try:
httpd = RootedHTTPServer(
args.path, (args.server, args.port), ComplexHTTPRequestHandler)
args.path, (args.server, args.port), ComplexHTTPRequestHandler
)
if args.ssl:
httpd.socket = ssl.wrap_socket(
httpd.socket, keyfile=args.key,
certfile=args.cert, server_side=True)
httpd.socket, keyfile=args.key, certfile=args.cert, server_side=True
)
except ssl.SSLError as e:
logger.error("Couldn't open certificate file %s or key file %s",
args.cert, args.key)
logger.error("Could not listen on port %s, server %s.",
args.port, args.server)
sys.exit(getattr(e, 'exitcode', 1))
logger.error(
"Couldn't open certificate file %s or key file %s", args.cert, args.key
)
logger.error("Could not listen on port %s, server %s.", args.port, args.server)
sys.exit(getattr(e, "exitcode", 1))
logger.info("Serving at port %s, server %s.",
args.port, args.server)
logger.info("Serving at port %s, server %s.", args.port, args.server)
try:
httpd.serve_forever()
except KeyboardInterrupt:

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
raise ImportError(
'Importing from `pelican.signals` is deprecated. '
'Use `from pelican import signals` or `import pelican.plugins.signals` instead.'
"Importing from `pelican.signals` is deprecated. "
"Use `from pelican import signals` or `import pelican.plugins.signals` instead."
)

View file

@ -9,4 +9,4 @@ Used for pelican test
The quick brown fox .
This page is a draft
This page is a draft

View file

@ -3,7 +3,7 @@ import warnings
from pelican.log import log_warnings
# redirect warnings modulole to use logging instead
# redirect warnings module to use logging instead
log_warnings()
# setup warnings to log DeprecationWarning's and error on

View file

@ -0,0 +1,7 @@
def pytest_addoption(parser):
parser.addoption(
"--check-build",
action="store",
default=False,
help="Check wheel contents.",
)

View file

@ -0,0 +1,69 @@
import importlib.metadata
import tarfile
from pathlib import Path
from re import match
from zipfile import ZipFile
import pytest
version = importlib.metadata.version("pelican")
@pytest.mark.skipif(
"not config.getoption('--check-build')",
reason="Only run when --check-build is given",
)
def test_wheel_contents(pytestconfig):
"""
This test should test the contents of the wheel to make sure
that everything that is needed is included in the final build
"""
dist_folder = pytestconfig.getoption("--check-build")
wheels = Path(dist_folder).rglob(f"pelican-{version}-py3-none-any.whl")
for wheel_file in wheels:
files_list = ZipFile(wheel_file).namelist()
# Check if theme files are copied to wheel
simple_theme = Path("./pelican/themes/simple/templates")
for x in simple_theme.iterdir():
assert str(x) in files_list
# Check if tool templates are copied to wheel
tools = Path("./pelican/tools/templates")
for x in tools.iterdir():
assert str(x) in files_list
assert "pelican/tools/templates/tasks.py.jinja2" in files_list
@pytest.mark.skipif(
"not config.getoption('--check-build')",
reason="Only run when --check-build is given",
)
@pytest.mark.parametrize(
"expected_file",
[
("THANKS"),
("README.rst"),
("CONTRIBUTING.rst"),
("docs/changelog.rst"),
("samples/"),
],
)
def test_sdist_contents(pytestconfig, expected_file):
"""
This test should test the contents of the source distribution to make sure
that everything that is needed is included in the final build.
"""
dist_folder = pytestconfig.getoption("--check-build")
sdist_files = Path(dist_folder).rglob(f"pelican-{version}.tar.gz")
for dist in sdist_files:
files_list = tarfile.open(dist, "r:gz").getnames()
dir_matcher = ""
if expected_file.endswith("/"):
dir_matcher = ".*"
filtered_values = [
path
for path in files_list
if match(rf"^pelican-{version}/{expected_file}{dir_matcher}$", path)
]
assert len(filtered_values) > 0

View file

@ -3,4 +3,3 @@ author: Alexis Métaireau
Markdown with filename metadata
===============================

View file

@ -0,0 +1,5 @@
Title: Draft article
Date: 2012-10-31
Status: draft
This is some content.

View file

@ -0,0 +1,5 @@
Title: Hidden article
Date: 2012-10-31
Status: hidden
This is some unlisted content.

5
pelican/tests/content/article_skip.md vendored Normal file
View file

@ -0,0 +1,5 @@
Title: Skipped article
Date: 2024-06-30
Status: skip
This content will not be rendered.

View file

@ -5,13 +5,13 @@
<body>
Ensure that the title attribute in an inline svg is not handled as an HTML title.
<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" viewBox="0 0 210 297">
<path fill="#b2b2ff" stroke="#000" stroke-width="2.646" d="M88.698 89.869l-8.899 15.63a38.894 38.894 0 00-16.474 31.722 38.894 38.894 0 0038.894 38.894 38.894 38.894 0 0038.894-38.894 38.894 38.894 0 00-9-24.83l-2.38-16.886-14.828 4.994a38.894 38.894 0 00-12.13-2.144z">
<title>A different title inside the inline SVG</title>
</path>
<ellipse cx="100.806" cy="125.285" rx="3.704" ry="10.583"/>
<ellipse cx="82.021" cy="125.285" rx="3.704" ry="10.583"/>
<ellipse cx="-111.432" cy="146.563" rx="3.704" ry="10.583" transform="rotate(-64.822)"/>
<ellipse cx="-118.245" cy="91.308" rx="6.18" ry="8.62" transform="matrix(.063 -.99801 .96163 .27436 0 0)"/>
<path fill="#b2b2ff" stroke="#000" stroke-width="2.646" d="M88.698 89.869l-8.899 15.63a38.894 38.894 0 00-16.474 31.722 38.894 38.894 0 0038.894 38.894 38.894 38.894 0 0038.894-38.894 38.894 38.894 0 00-9-24.83l-2.38-16.886-14.828 4.994a38.894 38.894 0 00-12.13-2.144z">
<title>A different title inside the inline SVG</title>
</path>
<ellipse cx="100.806" cy="125.285" rx="3.704" ry="10.583"/>
<ellipse cx="82.021" cy="125.285" rx="3.704" ry="10.583"/>
<ellipse cx="-111.432" cy="146.563" rx="3.704" ry="10.583" transform="rotate(-64.822)"/>
<ellipse cx="-118.245" cy="91.308" rx="6.18" ry="8.62" transform="matrix(.063 -.99801 .96163 .27436 0 0)"/>
</svg>
</body>
</html>

View file

@ -0,0 +1,4 @@
Title: Article with markdown and empty tags
Tags:
This is some content.

View file

@ -5,4 +5,3 @@ Title: Test Markdown extensions
## Level1
### Level2

View file

@ -1,6 +1,7 @@
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Article with Nonconformant HTML meta tags</title>
<meta name="summary" content="Summary and stuff" />

View file

@ -3,4 +3,3 @@ This is a super article !
#########################
:Category: Yeah

View file

@ -3,4 +3,3 @@ This is an article without category !
#####################################
This article should be in the DEFAULT_CATEGORY.

View file

@ -1064,4 +1064,4 @@
<gd:extendedProperty name="blogger.itemClass" value="pid-944253050"/>
<gd:extendedProperty name="blogger.displayTime" value="29 november 2010 om 12:35"/>
</entry>
</feed>
</feed>

View file

@ -1 +1 @@



View file

@ -0,0 +1,4 @@
<hr/><h3>Title header</h3><p>A paragraph of content.</p><p>Paragraph number two.</p><p>A list:</p><ol><li>One.</li><li>Two.</li><li>Three.</li></ol><p>A link: <a data-href="https://example.com/example" href="https://example.com/example" target="_blank">link text</a>.</p><h3>Header 2</h3><p>A block quote:</p><blockquote>quote words <strong>strong words</strong></blockquote><p>after blockquote</p><figure><img data-height="282" data-image-id="image1.png" data-width="739" src="https://cdn-images-1.medium.com/max/800/image1.png"/><figcaption>A figure caption.</figcaption></figure><p>A final note: <a data-href="http://stats.stackexchange.com/" href="http://stats.stackexchange.com/" rel="noopener" target="_blank">Cross-Validated</a> has sometimes been helpful.</p><hr/><p><em>Next: </em><a data-href="https://medium.com/@username/post-url" href="https://medium.com/@username/post-url" target="_blank"><em>Next post</em>
</a></p>
<p>By <a href="https://medium.com/@username">User Name</a> on <a href="https://medium.com/p/medium-short-url"><time datetime="2017-04-21T17:11:55.799Z">April 21, 2017</time></a>.</p><p><a href="https://medium.com/@username/this-post-url">Canonical link</a></p><p>Exported from <a href="https://medium.com">Medium</a> on December 1, 2023.</p>

View file

@ -0,0 +1,72 @@
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A title</title><style>
* {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}
html, body {
margin: 0;
padding: 0;
}
h1 {
font-size: 50px;
margin-bottom: 17px;
color: #333;
}
h2 {
font-size: 24px;
line-height: 1.6;
margin: 30px 0 0 0;
margin-bottom: 18px;
margin-top: 33px;
color: #333;
}
h3 {
font-size: 30px;
margin: 10px 0 20px 0;
color: #333;
}
header {
width: 640px;
margin: auto;
}
section {
width: 640px;
margin: auto;
}
section p {
margin-bottom: 27px;
font-size: 20px;
line-height: 1.6;
color: #333;
}
section img {
max-width: 640px;
}
footer {
padding: 0 20px;
margin: 50px 0;
text-align: center;
font-size: 12px;
}
.aspectRatioPlaceholder {
max-width: auto !important;
max-height: auto !important;
}
.aspectRatioPlaceholder-fill {
padding-bottom: 0 !important;
}
header,
section[data-field=subtitle],
section[data-field=description] {
display: none;
}
</style></head><body><article class="h-entry">
<header>
<h1 class="p-name">A name (like title)</h1>
</header>
<section data-field="subtitle" class="p-summary">
Summary (first several words of content)
</section>
<section data-field="body" class="e-content">
<section name="ad15" class="section section--body section--first"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="20a3" id="20a3" class="graf graf--h3 graf--leading graf--title">Title header</h3><p name="e3d6" id="e3d6" class="graf graf--p graf-after--h3">A paragraph of content.</p><p name="c7a8" id="c7a8" class="graf graf--p graf-after--p">Paragraph number two.</p><p name="42aa" id="42aa" class="graf graf--p graf-after--p">A list:</p><ol class="postList"><li name="d65f" id="d65f" class="graf graf--li graf-after--p">One.</li><li name="232b" id="232b" class="graf graf--li graf-after--li">Two.</li><li name="ef87" id="ef87" class="graf graf--li graf-after--li">Three.</li></ol><p name="e743" id="e743" class="graf graf--p graf-after--p">A link: <a href="https://example.com/example" data-href="https://example.com/example" class="markup--anchor markup--p-anchor" target="_blank">link text</a>.</p><h3 name="4cfd" id="4cfd" class="graf graf--h3 graf-after--p">Header 2</h3><p name="433c" id="433c" class="graf graf--p graf-after--p">A block quote:</p><blockquote name="3537" id="3537" class="graf graf--blockquote graf-after--p">quote words <strong class="markup--strong markup--blockquote-strong">strong words</strong></blockquote><p name="00cc" id="00cc" class="graf graf--p graf-after--blockquote">after blockquote</p><figure name="edb0" id="edb0" class="graf graf--figure graf-after--p"><img class="graf-image" data-image-id="image1.png" data-width="739" data-height="282" src="https://cdn-images-1.medium.com/max/800/image1.png"><figcaption class="imageCaption">A figure caption.</figcaption></figure><p name="f401" id="f401" class="graf graf--p graf-after--p graf--trailing">A final note: <a href="http://stats.stackexchange.com/" data-href="http://stats.stackexchange.com/" class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">Cross-Validated</a> has sometimes been helpful.</p></div></div></section><section name="09a3" class="section section--body section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><p name="81e8" id="81e8" class="graf graf--p graf--leading"><em class="markup--em markup--p-em">Next: </em><a href="https://medium.com/@username/post-url" data-href="https://medium.com/@username/post-url" class="markup--anchor markup--p-anchor" target="_blank"><em class="markup--em markup--p-em">Next post</em>
</section>
<footer><p>By <a href="https://medium.com/@username" class="p-author h-card">User Name</a> on <a href="https://medium.com/p/medium-short-url"><time class="dt-published" datetime="2017-04-21T17:11:55.799Z">April 21, 2017</time></a>.</p><p><a href="https://medium.com/@username/this-post-url" class="p-canonical">Canonical link</a></p><p>Exported from <a href="https://medium.com">Medium</a> on December 1, 2023.</p></footer></article></body></html>

View file

@ -52,4 +52,3 @@ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View file

@ -685,7 +685,52 @@ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></con
<wp:meta_key>_edit_last</wp:meta_key>
<wp:meta_value><![CDATA[3]]></wp:meta_value>
</wp:postmeta>
</item>
</item>
<item>
<title>Caption on image</title>
<link>http://thisisa.test/?p=176</link>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
<dc:creator>bob</dc:creator>
<guid isPermaLink="false">http://thisisa.test/?p=176</guid>
<description></description>
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
[caption attachment_id="42" align="aligncenter" width="300" caption="This is a pelican"]<img src="/theme/img/xpelican.png.pagespeed.ic.Rjep0025-y.png"/>[/caption]
[caption attachment_id="43" align="aligncenter" width="300"]<img src="/theme/img/xpelican-3.png.pagespeed.ic.m-NAIdRCOM.png" width="300" height="216" class="size-medium wp-image-1055" /> This also a pelican[/caption]
[caption attachment_id="44" align="aligncenter" width="300"]<a href="https://getpelican.com/"><img src="/theme/img/xpelican.png.pagespeed.ic.Rjep0025-y.png" alt=""/> Yet another pelican[/caption]
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
<wp:post_id>176</wp:post_id>
<wp:post_date>2012-02-16 15:52:55</wp:post_date>
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
<wp:comment_status>open</wp:comment_status>
<wp:ping_status>open</wp:ping_status>
<wp:post_name>caption-on-image</wp:post_name>
<wp:status>publish</wp:status>
<wp:post_parent>0</wp:post_parent>
<wp:menu_order>0</wp:menu_order>
<wp:post_type>post</wp:post_type>
<wp:post_password></wp:post_password>
<wp:is_sticky>0</wp:is_sticky>
<category domain="category" nicename="category-2"><![CDATA[Category 2]]></category>
<wp:postmeta>
<wp:meta_key>_edit_last</wp:meta_key>
<wp:meta_value><![CDATA[3]]></wp:meta_value>
</wp:postmeta>
</item>
<item>
<title>A custom post in category 4</title>
<link>http://thisisa.test/?p=175</link>
@ -793,7 +838,7 @@ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></con
<wp:meta_key>_edit_last</wp:meta_key>
<wp:meta_value><![CDATA[3]]></wp:meta_value>
</wp:postmeta>
</item>
</item>
<item>
<title>A 2nd custom post type also in category 5</title>
<link>http://thisisa.test/?p=177</link>

View file

@ -1,43 +1,47 @@
AUTHOR = 'Alexis Métaireau'
AUTHOR = "Alexis Métaireau"
SITENAME = "Alexis' log"
SITEURL = 'http://blog.notmyidea.org'
TIMEZONE = 'UTC'
SITEURL = "http://blog.notmyidea.org"
TIMEZONE = "UTC"
GITHUB_URL = 'http://github.com/ametaireau/'
GITHUB_URL = "http://github.com/ametaireau/"
DISQUS_SITENAME = "blog-notmyidea"
PDF_GENERATOR = False
REVERSE_CATEGORY_ORDER = True
DEFAULT_PAGINATION = 2
FEED_RSS = 'feeds/all.rss.xml'
CATEGORY_FEED_RSS = 'feeds/{slug}.rss.xml'
FEED_RSS = "feeds/all.rss.xml"
CATEGORY_FEED_RSS = "feeds/{slug}.rss.xml"
LINKS = (('Biologeek', 'http://biologeek.org'),
('Filyb', "http://filyb.info/"),
('Libert-fr', "http://www.libert-fr.com"),
('N1k0', "http://prendreuncafe.com/blog/"),
('Tarek Ziadé', "http://ziade.org/blog"),
('Zubin Mithra', "http://zubin71.wordpress.com/"),)
LINKS = [
("Biologeek", "http://biologeek.org"),
("Filyb", "http://filyb.info/"),
("Libert-fr", "http://www.libert-fr.com"),
("N1k0", "http://prendreuncafe.com/blog/"),
("Tarek Ziadé", "http://ziade.org/blog"),
("Zubin Mithra", "http://zubin71.wordpress.com/"),
]
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
('lastfm', 'http://lastfm.com/user/akounet'),
('github', 'http://github.com/ametaireau'),)
SOCIAL = [
("twitter", "http://twitter.com/ametaireau"),
("lastfm", "http://lastfm.com/user/akounet"),
("github", "http://github.com/ametaireau"),
]
# global metadata to all the contents
DEFAULT_METADATA = {'yeah': 'it is'}
DEFAULT_METADATA = {"yeah": "it is"}
# path-specific metadata
EXTRA_PATH_METADATA = {
'extra/robots.txt': {'path': 'robots.txt'},
"extra/robots.txt": {"path": "robots.txt"},
}
# static paths will be copied without parsing their contents
STATIC_PATHS = [
'pictures',
'extra/robots.txt',
"pictures",
"extra/robots.txt",
]
FORMATTED_FIELDS = ['summary', 'custom_formatted_field']
FORMATTED_FIELDS = ["summary", "custom_formatted_field"]
# foobar will not be used, because it's not in caps. All configuration keys
# have to be in caps

View file

@ -1,4 +1,4 @@
NAME = 'namespace plugin'
NAME = "namespace plugin"
def register():

View file

@ -1,67 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A markdown powered article</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="You're mutually oblivious. a root-relative link to unbelievable a file-relative link to unbelievable" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A markdown powered article</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="You're mutually oblivious. a root-relative link to unbelievable a file-relative link to unbelievable" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/a-markdown-powered-article.html" rel="bookmark"
title="Permalink to A markdown powered article">A markdown powered article</a></h1>
</header>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/a-markdown-powered-article.html" rel="bookmark"
title="Permalink to A markdown powered article">A markdown powered article</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-04-20T00:00:00+00:00">
Published: Wed 20 April 2011
</abbr>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-04-20T00:00:00+00:00">
Published: Wed 20 April 2011
</abbr>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
</footer><!-- /.post-info --> <p>You're mutually oblivious.</p>
<p><a href="/unbelievable.html">a root-relative link to unbelievable</a>
<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>
</div><!-- /.entry-content -->
</footer><!-- /.post-info --> <p>You're mutually oblivious.</p>
<p><a href="/unbelievable.html">a root-relative link to unbelievable</a>
<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>
</div><!-- /.entry-content -->
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,69 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<h1>Archives for A Pelican Blog</h1>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<h1>Archives for A Pelican Blog</h1>
<dl>
<dt>Fri 30 November 2012</dt>
<dd><a href="/filename_metadata-example.html">FILENAME_METADATA example</a></dd>
<dt>Wed 29 February 2012</dt>
<dd><a href="/second-article.html">Second article</a></dd>
<dt>Wed 20 April 2011</dt>
<dd><a href="/a-markdown-powered-article.html">A markdown powered article</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-1.html">Article 1</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-2.html">Article 2</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-3.html">Article 3</a></dd>
<dt>Thu 02 December 2010</dt>
<dd><a href="/this-is-a-super-article.html">This is a super article !</a></dd>
<dt>Wed 20 October 2010</dt>
<dd><a href="/oh-yeah.html">Oh yeah !</a></dd>
<dt>Fri 15 October 2010</dt>
<dd><a href="/unbelievable.html">Unbelievable !</a></dd>
<dt>Sun 14 March 2010</dt>
<dd><a href="/tag/baz.html">The baz tag</a></dd>
</dl>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<dl>
<dt>Fri 30 November 2012</dt>
<dd><a href="/filename_metadata-example.html">FILENAME_METADATA example</a></dd>
<dt>Wed 29 February 2012</dt>
<dd><a href="/second-article.html">Second article</a></dd>
<dt>Wed 20 April 2011</dt>
<dd><a href="/a-markdown-powered-article.html">A markdown powered article</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-1.html">Article 1</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-2.html">Article 2</a></dd>
<dt>Thu 17 February 2011</dt>
<dd><a href="/article-3.html">Article 3</a></dd>
<dt>Thu 02 December 2010</dt>
<dd><a href="/this-is-a-super-article.html">This is a super article !</a></dd>
<dt>Wed 20 October 2010</dt>
<dd><a href="/oh-yeah.html">Oh yeah !</a></dd>
<dt>Fri 15 October 2010</dt>
<dd><a href="/unbelievable.html">Unbelievable !</a></dd>
<dt>Sun 14 March 2010</dt>
<dd><a href="/tag/baz.html">The baz tag</a></dd>
</dl>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,66 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>Article 1</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 1" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>Article 1</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 1" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-1.html" rel="bookmark"
title="Permalink to Article 1">Article 1</a></h1>
</header>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-1.html" rel="bookmark"
title="Permalink to Article 1">Article 1</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
</footer><!-- /.post-info --> <p>Article 1</p>
</footer><!-- /.post-info --> <p>Article 1</p>
</div><!-- /.entry-content -->
</div><!-- /.entry-content -->
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,66 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>Article 2</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 2" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>Article 2</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 2" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-2.html" rel="bookmark"
title="Permalink to Article 2">Article 2</a></h1>
</header>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-2.html" rel="bookmark"
title="Permalink to Article 2">Article 2</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
</footer><!-- /.post-info --> <p>Article 2</p>
</footer><!-- /.post-info --> <p>Article 2</p>
</div><!-- /.entry-content -->
</div><!-- /.entry-content -->
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,66 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>Article 3</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 3" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>Article 3</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
<meta name="description" content="Article 3" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-3.html" rel="bookmark"
title="Permalink to Article 3">Article 3</a></h1>
</header>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li class="active"><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="/article-3.html" rel="bookmark"
title="Permalink to Article 3">Article 3</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2011-02-17T00:00:00+00:00">
Published: Thu 17 February 2011
</abbr>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
<p>In <a href="/category/cat1.html">cat1</a>.</p>
</footer><!-- /.post-info --> <p>Article 3</p>
</footer><!-- /.post-info --> <p>Article 3</p>
</div><!-- /.entry-content -->
</div><!-- /.entry-content -->
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</article>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,111 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Alexis Métaireau</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Alexis Métaireau</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<aside id="featured" class="body">
<article>
<h1 class="entry-title"><a href="/this-is-a-super-article.html">This is a super article !</a></h1>
<footer class="post-info">
<abbr class="published" title="2010-12-02T10:14:00+00:00">
Published: Thu 02 December 2010
</abbr>
<br />
<abbr class="modified" title="2013-11-17T23:29:00+00:00">
Updated: Sun 17 November 2013
</abbr>
<aside id="featured" class="body">
<article>
<h1 class="entry-title"><a href="/this-is-a-super-article.html">This is a super article !</a></h1>
<footer class="post-info">
<abbr class="published" title="2010-12-02T10:14:00+00:00">
Published: Thu 02 December 2010
</abbr>
<br />
<abbr class="modified" title="2013-11-17T23:29:00+00:00">
Updated: Sun 17 November 2013
</abbr>
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/yeah.html">yeah</a>.</p>
<p>tags: <a href="/tag/foo.html">foo</a> <a href="/tag/bar.html">bar</a> <a href="/tag/foobar.html">foobar</a> </p>
</footer><!-- /.post-info --><p>Some content here !</p>
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/yeah.html">yeah</a>.</p>
<p>tags: <a href="/tag/foo.html">foo</a> <a href="/tag/bar.html">bar</a> <a href="/tag/foobar.html">foobar</a> </p>
</footer><!-- /.post-info --><p>Some content here !</p>
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<pre class="literal-block">
&gt;&gt;&gt; from ipdb import set_trace
&gt;&gt;&gt; set_trace()
</pre>
<p>→ And now try with some utf8 hell: ééé</p>
</div>
</article>
</aside><!-- /#featured -->
<p>→ And now try with some utf8 hell: ééé</p>
</div>
</article>
</aside><!-- /#featured -->
<section id="content" class="body">
<h1>Other articles</h1>
<hr />
<ol id="posts-list" class="hfeed">
<h1>Other articles</h1>
<hr />
<ol id="posts-list" class="hfeed">
<li><article class="hentry">
<header>
<h1><a href="/oh-yeah.html" rel="bookmark"
title="Permalink to Oh yeah !">Oh yeah !</a></h1>
</header>
<li><article class="hentry">
<header>
<h1><a href="/oh-yeah.html" rel="bookmark"
title="Permalink to Oh yeah !">Oh yeah !</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2010-10-20T10:14:00+00:00">
Published: Wed 20 October 2010
</abbr>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2010-10-20T10:14:00+00:00">
Published: Wed 20 October 2010
</abbr>
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/bar.html">bar</a>.</p>
<p>tags: <a href="/tag/oh.html">oh</a> <a href="/tag/bar.html">bar</a> <a href="/tag/yeah.html">yeah</a> </p>Translations:
<a href="/oh-yeah-fr.html" hreflang="fr">fr</a>
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/bar.html">bar</a>.</p>
<p>tags: <a href="/tag/oh.html">oh</a> <a href="/tag/bar.html">bar</a> <a href="/tag/yeah.html">yeah</a> </p>Translations:
<a href="/oh-yeah-fr.html" hreflang="fr">fr</a>
</footer><!-- /.post-info --> <div class="section" id="why-not">
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</footer><!-- /.post-info --> <div class="section" id="why-not">
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
<a class="readmore" href="/oh-yeah.html">read more</a>
</div><!-- /.entry-content -->
</article></li>
</ol><!-- /#posts-list -->
<a class="readmore" href="/oh-yeah.html">read more</a>
</div><!-- /.entry-content -->
</article></li>
</ol><!-- /#posts-list -->
</section><!-- /#content -->
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

View file

@ -1,51 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Authors</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Authors</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<h1>Authors on A Pelican Blog</h1>
<ul>
<li><a href="/author/alexis-metaireau.html">Alexis Métaireau</a> (2)</li>
</ul>
</section>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<section id="content" class="body">
<h1>Authors on A Pelican Blog</h1>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<li><a href="/author/alexis-metaireau.html">Alexis Métaireau</a> (2)</li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</section>
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</body>
</html>
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>

View file

@ -1,50 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Categories</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - Categories</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<h1>Categories on A Pelican Blog</h1>
<ul>
<li><a href="/category/bar.html">bar</a> (1)</li>
<li><a href="/category/cat1.html">cat1</a> (4)</li>
<li><a href="/category/misc.html">misc</a> (4)</li>
<li><a href="/category/yeah.html">yeah</a> (1)</li>
</ul>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<h1>Categories for A Pelican Blog</h1>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<li><a href="/category/bar.html">bar</a> (1)</li>
<li><a href="/category/cat1.html">cat1</a> (4)</li>
<li><a href="/category/misc.html">misc</a> (4)</li>
<li><a href="/category/yeah.html">yeah</a> (1)</li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</section>
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</body>
</html>
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>

View file

@ -1,67 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - bar</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Pelican" />
<title>A Pelican Blog - bar</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li class="active"><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="/">A Pelican Blog</a></h1>
<nav><ul>
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
<li><a href="/override/">Override url/save_as</a></li>
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
<li class="active"><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<aside id="featured" class="body">
<article>
<h1 class="entry-title"><a href="/oh-yeah.html">Oh yeah !</a></h1>
<footer class="post-info">
<abbr class="published" title="2010-10-20T10:14:00+00:00">
Published: Wed 20 October 2010
</abbr>
<aside id="featured" class="body">
<article>
<h1 class="entry-title"><a href="/oh-yeah.html">Oh yeah !</a></h1>
<footer class="post-info">
<abbr class="published" title="2010-10-20T10:14:00+00:00">
Published: Wed 20 October 2010
</abbr>
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/bar.html">bar</a>.</p>
<p>tags: <a href="/tag/oh.html">oh</a> <a href="/tag/bar.html">bar</a> <a href="/tag/yeah.html">yeah</a> </p>Translations:
<a href="/oh-yeah-fr.html" hreflang="fr">fr</a>
<address class="vcard author">
By <a class="url fn" href="/author/alexis-metaireau.html">Alexis Métaireau</a>
</address>
<p>In <a href="/category/bar.html">bar</a>.</p>
<p>tags: <a href="/tag/oh.html">oh</a> <a href="/tag/bar.html">bar</a> <a href="/tag/yeah.html">yeah</a> </p>Translations:
<a href="/oh-yeah-fr.html" hreflang="fr">fr</a>
</footer><!-- /.post-info --><div class="section" id="why-not">
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</article>
</aside><!-- /#featured -->
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</footer><!-- /.post-info --><div class="section" id="why-not">
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</article>
</aside><!-- /#featured -->
<section id="extras" class="body">
<div class="social">
<h2>social</h2>
<ul>
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a rel="nofollow" href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a rel="nofollow" href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<p>The theme is by <a rel="nofollow" href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
</body>
</html>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show more