mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Compare commits
3,754 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7408cbfe9 |
||
|
|
87e3b60da7 | ||
|
|
f95466c8fe | ||
|
|
4cac1ab5f1 | ||
|
|
6df3cfc6e3 | ||
|
|
162d2b8318 |
||
|
|
595713b91a | ||
|
|
7ef5eae639 | ||
|
|
eb0d4deb01 |
||
|
|
f92b2a27ab | ||
|
|
95965459f2 | ||
|
|
3efb0817e3 | ||
|
|
f4ee3b7946 |
||
|
|
939434b4ab |
||
|
|
4dedf17958 | ||
|
|
a29857ac19 |
||
|
|
bfd1068b82 |
||
|
|
0e358c611c |
||
|
|
fca2fde2ed | ||
|
|
ff4460c3d7 | ||
|
|
b2ac0e93aa | ||
|
|
9e3e1325c0 |
||
|
|
f44ec52427 | ||
|
|
9f6cc9f0d7 |
||
|
|
ffe22e3c59 | ||
|
|
487486138f |
||
|
|
07f32c1a09 |
||
|
|
ca32b1b77c | ||
|
|
f9711fa10a |
||
|
|
7fd66d8a95 |
||
|
|
9c7749a298 |
||
|
|
88a6f57940 | ||
|
|
5338f4fac2 |
||
|
|
b71159a11e | ||
|
|
69e24fa82f | ||
|
|
ec95a2c855 | ||
|
|
543424aa41 |
||
|
|
5be013d9d2 |
||
|
|
64be147463 |
||
|
|
4fcc24ddfe | ||
|
|
af3c2ed0cf | ||
|
|
d813c5148e | ||
|
|
4878fc82a7 |
||
|
|
8a1c55ed07 | ||
|
|
9207e1ff62 |
||
|
|
fa0af6d221 |
||
|
|
b3ef32bcf1 | ||
|
|
b4fcb7f4e3 | ||
|
|
7a4c89f64a | ||
|
|
74d76ca0da | ||
|
|
a17521b6f7 |
||
|
|
5bb39c4f6f | ||
|
|
714a3d53a1 | ||
|
|
7d4adfce3f | ||
|
|
07c7eacab9 | ||
|
|
d9652ef109 |
||
|
|
7096b0a168 |
||
|
|
ac28ddb9bf |
||
|
|
31538d1578 | ||
|
|
1edca55253 | ||
|
|
882cd16e11 |
||
|
|
60261b8c99 | ||
|
|
4ca1454293 |
||
|
|
075542721c | ||
|
|
0da2530d9b |
||
|
|
31264498e1 |
||
|
|
92050d90bc | ||
|
|
b02abf0220 | ||
|
|
f5dc4d4b96 | ||
|
|
478012e0d0 | ||
|
|
b86383fb28 | ||
|
|
fe45094545 | ||
|
|
08283b4915 |
||
|
|
0cb445c813 |
||
|
|
6c6b940ffc | ||
|
|
84db21c724 |
||
|
|
2f9d382c56 |
||
|
|
86bf9230b4 | ||
|
|
a5db130e1d | ||
|
|
9e8af627b5 | ||
|
|
44db258f59 | ||
|
|
e609b4d78a |
||
|
|
5687883d4b |
||
|
|
84f2995b38 |
||
|
|
4201256a5b |
||
|
|
2d375bc135 | ||
|
|
bb0ed26fdd | ||
|
|
d85f493ee3 | ||
|
|
513abbfdc6 |
||
|
|
ef501a3d89 |
||
|
|
36ebe91af7 | ||
|
|
28e54106f2 | ||
|
|
bdd4e45628 | ||
|
|
6a50191728 | ||
|
|
f89f8894cc |
||
|
|
6fec5786d0 |
||
|
|
5171631dec |
||
|
|
8d63d1ced8 |
||
|
|
49723e6daf | ||
|
|
993c75103b | ||
|
|
7a2c72e604 |
||
|
|
05535c7d6c | ||
|
|
853e9e6b8a |
||
|
|
617aba077f | ||
|
|
487877f206 | ||
|
|
750a1f8bfa | ||
|
|
d03ae2a41f | ||
|
|
b17182ece1 |
||
|
|
50f77b42b2 | ||
|
|
135c61f769 |
||
|
|
f19de98b9e | ||
|
|
e46595cdac |
||
|
|
79d37ba491 |
||
|
|
dc40474e29 |
||
|
|
5c7e4bbac4 |
||
|
|
b80a592d30 | ||
|
|
d83c5029b8 |
||
|
|
e262990c68 | ||
|
|
fd955ba054 | ||
|
|
8c7c29e4f2 |
||
|
|
657ad64f49 |
||
|
|
af9865d317 | ||
|
|
b77bb690e2 | ||
|
|
30bde3823f | ||
|
|
3e81af966a | ||
|
|
8fd94ea025 |
||
|
|
82b48fcfa1 | ||
|
|
fc45791da4 | ||
|
|
2687475fba |
||
|
|
9b77a9027b | ||
|
|
cbe6c08f44 | ||
|
|
ccb4e58882 |
||
|
|
37ba4fc21a | ||
|
|
4af40e8077 | ||
|
|
7f07c220de | ||
|
|
270fd4edcc |
||
|
|
98bdd87dae | ||
|
|
308af1912e | ||
|
|
59756f8faf |
||
|
|
3569dede01 | ||
|
|
7577dd7603 | ||
|
|
3624bcdbf4 | ||
|
|
880e9769e8 |
||
|
|
144b2edf88 | ||
|
|
9d30c5608a | ||
|
|
b6d3b65899 | ||
|
|
425f302880 |
||
|
|
9d46a94d6d | ||
|
|
54ac03fca6 | ||
|
|
0bd02c00c0 | ||
|
|
800f22b3ba | ||
|
|
39c964450c |
||
|
|
c46063cfc3 | ||
|
|
8d8feb6341 |
||
|
|
6d8597addb | ||
|
|
4f46fedd73 | ||
|
|
f0b6e8732f |
||
|
|
1001dcb609 | ||
|
|
e4d7f0a9d9 | ||
|
|
0b5934a1fa |
||
|
|
0f5179b816 |
||
|
|
666b962eb6 |
||
|
|
94bcd41f27 | ||
|
|
b87308cfaa | ||
|
|
fabc409277 | ||
|
|
7454138184 | ||
|
|
7c7c9355b6 | ||
|
|
960aee5907 |
||
|
|
8a01cb11e1 |
||
|
|
1f14606f83 | ||
|
|
f1f2ceccc7 | ||
|
|
c36ab07526 | ||
|
|
ff35d26cbc |
||
|
|
dbf90a4821 |
||
|
|
e4807316ae |
||
|
|
3a662ace03 |
||
|
|
2fa5c515b0 |
||
|
|
d39dd9b85f | ||
|
|
f2ab4a1dc1 |
||
|
|
fbe81a971a |
||
|
|
def0899f10 |
||
|
|
d6a33f1d21 | ||
|
|
b1cb6c7326 |
||
|
|
5e6dba73ac |
||
|
|
bf4fd679a5 |
||
|
|
f69e2cca6b |
||
|
|
f0beb81a97 | ||
|
|
5d3e87b50b |
||
|
|
af37f0656f |
||
|
|
8626d5bd85 |
||
|
|
2d75ca8391 |
||
|
|
61eacffa90 |
||
|
|
4ed5c0d5b8 | ||
|
|
7466b13e0a | ||
|
|
d9b2bc3a4e |
||
|
|
7194cf5795 | ||
|
|
a1d475fb22 |
||
|
|
6fd2c0d8e6 |
||
|
|
76f7343b61 | ||
|
|
f510b4b21f | ||
|
|
a2525f7db4 | ||
|
|
1d0fd456e8 | ||
|
|
6cd707a668 | ||
|
|
7ca66ee9d0 | ||
|
|
9525583ccd |
||
|
|
86d6898517 |
||
|
|
0c5d63c69e | ||
|
|
eca501ac1e |
||
|
|
e92ccb8a46 |
||
|
|
2238dcab07 | ||
|
|
db241feaa4 |
||
|
|
ecd598f293 | ||
|
|
903ce3ce33 | ||
|
|
39ff56a082 | ||
|
|
be5afa3175 |
||
|
|
6059675d55 |
||
|
|
d7015db9e4 |
||
|
|
e014e5b55b |
||
|
|
451b094a94 |
||
|
|
dc1b6ab14d |
||
|
|
8a8b952ecb |
||
|
|
14f19474df |
||
|
|
32b72123f0 |
||
|
|
ee10d6995a |
||
|
|
49aef30dab |
||
|
|
feae8ef41c |
||
|
|
76650898a6 | ||
|
|
e6a5e2a665 | ||
|
|
abae21494d | ||
|
|
a20cd8dda5 |
||
|
|
3c57996945 | ||
|
|
08785f714f | ||
|
|
4e438ffe60 |
||
|
|
6f467fefdc |
||
|
|
f0aab11a2d |
||
|
|
805ca9b4a9 | ||
|
|
271f4dd68f | ||
|
|
cabdb26cee | ||
|
|
8ea27b82f6 | ||
|
|
bfb2587697 |
||
|
|
dbe0b1125f | ||
|
|
a23a4e14cf |
||
|
|
6f1605edf9 |
||
|
|
842c6537f1 |
||
|
|
9437de6341 | ||
|
|
cce1570135 | ||
|
|
73599f44f2 |
||
|
|
8a0f335e2b | ||
|
|
165d57eff5 |
||
|
|
eb052cae09 | ||
|
|
00d26fc068 | ||
|
|
8b6d215934 | ||
|
|
c18f1a7308 | ||
|
|
a76a419585 | ||
|
|
fad2ff7ae3 |
||
|
|
fec78ebf33 |
||
|
|
3a6ae72333 | ||
|
|
84795c701c |
||
|
|
3dce25ab23 |
||
|
|
269751b033 |
||
|
|
85bf98232d |
||
|
|
8a7e01646b |
||
|
|
b812f2ad1c |
||
|
|
e14f20bb99 |
||
|
|
b8d5919cd2 |
||
|
|
33d6712e8b |
||
|
|
29b10ef6e6 |
||
|
|
6cf6a1ffe9 |
||
|
|
58fd855385 |
||
|
|
19c797af5e |
||
|
|
7dfc799f25 |
||
|
|
f342dc3097 |
||
|
|
43e513f218 |
||
|
|
b289dcea82 |
||
|
|
631ac1bdb3 |
||
|
|
b388057d66 |
||
|
|
5519efef2e |
||
|
|
7643e0e92b |
||
|
|
61ca47c519 |
||
|
|
6ed7395812 |
||
|
|
11c13ceae1 |
||
|
|
83a8059d02 |
||
|
|
a20bbb55d6 |
||
|
|
dc427ad9d6 |
||
|
|
b6a9a8333b |
||
|
|
9c87d8f3a3 |
||
|
|
6a623ba10a |
||
|
|
865f7b10dd | ||
|
|
91d9ef7a70 | ||
|
|
58e70082e0 | ||
|
|
8fd5d6f51b | ||
|
|
1404a2dbc3 |
||
|
|
fab6e1a2c5 | ||
|
|
777a708ef7 |
||
|
|
620139cdaf |
||
|
|
0282c1d6eb |
||
|
|
4caf9a88a2 |
||
|
|
36b4c6dc08 |
||
|
|
a8fefad331 | ||
|
|
ab9e55b398 |
||
|
|
5d8c03108b | ||
|
|
5c36cfbb9b | ||
|
|
82e2571754 |
||
|
|
de0fae8182 | ||
|
|
48166bd687 | ||
|
|
29185e4ad7 |
||
|
|
3be0703b14 | ||
|
|
e724de9ffe | ||
|
|
30adfba1ca |
||
|
|
8a5f02ac60 |
||
|
|
2eeff62fd7 |
||
|
|
0d1bcd4b11 |
||
|
|
63b60da919 | ||
|
|
48a0484d15 | ||
|
|
9384e7cb0b | ||
|
|
639173da6b | ||
|
|
5435dd0d81 | ||
|
|
dcd3045f32 | ||
|
|
0989ed29be |
||
|
|
5d1dcd8ed3 |
||
|
|
bf0860ee86 |
||
|
|
7acc9ac554 |
||
|
|
413c6a1c71 |
||
|
|
44d9754466 | ||
|
|
e8076bfe03 |
||
|
|
1d2bf8e96e |
||
|
|
715c056cd4 | ||
|
|
7f1ecdec8b | ||
|
|
b8bf5950b6 |
||
|
|
ef7e26329c | ||
|
|
0533e2da9f |
||
|
|
69d2b5b9af |
||
|
|
b260b3838e | ||
|
|
410f60d6b3 | ||
|
|
d3daa4d794 | ||
|
|
33220695d1 |
||
|
|
7d6accac4d | ||
|
|
7877376153 | ||
|
|
168093a750 | ||
|
|
6ba7a0926d |
||
|
|
5214248344 |
||
|
|
1f6b344f7d | ||
|
|
418a9191b0 | ||
|
|
23c50ea885 |
||
|
|
1b360acafa |
||
|
|
bbbc96cf83 |
||
|
|
043ab617b8 |
||
|
|
8b6b7dac2d |
||
|
|
0a42b5f250 |
||
|
|
6f93202e60 | ||
|
|
ef844dbe0a | ||
|
|
bb682973fb | ||
|
|
7adcfc7938 | ||
|
|
86f62d0a92 |
||
|
|
8bb9e0da48 | ||
|
|
208332c0e6 |
||
|
|
4db5c7ca4b | ||
|
|
6ac497922f | ||
|
|
219c01afb0 | ||
|
|
a2852942ea | ||
|
|
06c9e0fb80 | ||
|
|
385d5bf75e | ||
|
|
b473280eac |
||
|
|
95ff3b8e62 |
||
|
|
f50bf26466 |
||
|
|
7850153c54 |
||
|
|
504bfcf703 |
||
|
|
b777bedce3 |
||
|
|
4d82a42229 | ||
|
|
ff665de3ca | ||
|
|
5e986580e8 | ||
|
|
b10c7c699b | ||
|
|
f015ab89d9 |
||
|
|
3937028c00 |
||
|
|
6ddbc83f43 |
||
|
|
a51d75c8ed |
||
|
|
1f6f4a3626 |
||
|
|
cbddac44e4 | ||
|
|
66408d611f |
||
|
|
cdc90d5d07 |
||
|
|
6d11c6f2e5 |
||
|
|
9d509253c3 |
||
|
|
27f2c678cb | ||
|
|
2a7e691000 | ||
|
|
5d4cb5619b |
||
|
|
6af939e096 |
||
|
|
5103aa9a38 | ||
|
|
09d434d87b | ||
|
|
062144a875 |
||
|
|
e265deb094 |
||
|
|
73c0320f62 |
||
|
|
083fb357bd |
||
|
|
23f3804c96 |
||
|
|
1bcd6c5f56 |
||
|
|
21e855a29f | ||
|
|
9c0c5b4929 | ||
|
|
6487735efb | ||
|
|
09c420f40c | ||
|
|
fcfb39b8f2 | ||
|
|
81b5fbe174 | ||
|
|
33aca76d78 | ||
|
|
961909a149 | ||
|
|
ac416d7df2 | ||
|
|
494b418dda | ||
|
|
6cac8237cc |
||
|
|
84dfbcf3dc |
||
|
|
9685e4b594 | ||
|
|
d5d792060c |
||
|
|
5c222ef41b |
||
|
|
c46554ae70 |
||
|
|
7006016121 | ||
|
|
39e5edde9c | ||
|
|
392bf98118 | ||
|
|
595f3be988 | ||
|
|
d89c6f6ed2 | ||
|
|
e8d6318e93 |
||
|
|
f94ba0ef3d |
||
|
|
eca0ee04b7 |
||
|
|
433453924b |
||
|
|
16b8a03ad9 | ||
|
|
34ca2e1de2 |
||
|
|
77e5381be7 |
||
|
|
5823412085 | ||
|
|
f3613af155 |
||
|
|
21c331e789 |
||
|
|
5c178a1ccb | ||
|
|
ab81f183c6 | ||
|
|
fe19f1abb6 | ||
|
|
2f5fc10614 |
||
|
|
4794752dd9 | ||
|
|
7b9a859e5e | ||
|
|
fe4f1ec4ea | ||
|
|
0384c9bc07 |
||
|
|
11633992a0 |
||
|
|
4c8572e85d |
||
|
|
1a321102a1 |
||
|
|
8f6a61439d | ||
|
|
59f7f4beb8 | ||
|
|
2e35bc90a6 | ||
|
|
fa31a7e279 | ||
|
|
57c5296a44 |
||
|
|
8eb4be521f |
||
|
|
1b87ef6a7b | ||
|
|
9ec1750709 | ||
|
|
bb10d286a6 | ||
|
|
de2e9b7e41 | ||
|
|
17089aefc9 | ||
|
|
99c935df8f | ||
|
|
aeec09b397 | ||
|
|
9bd54b7b60 | ||
|
|
eab67f7634 | ||
|
|
d1a874e580 |
||
|
|
793b93bd34 |
||
|
|
33ef2c5356 |
||
|
|
98372c9869 | ||
|
|
8849721913 |
||
|
|
0da8659d0e | ||
|
|
30597b70f0 | ||
|
|
735d93c7b6 |
||
|
|
5803052bb7 | ||
|
|
31b282f3e2 | ||
|
|
76cf879414 | ||
|
|
b5426fb0bb |
||
|
|
2b631ab4d3 | ||
|
|
0b9a488c26 | ||
|
|
e2c73a0a16 |
||
|
|
324fcefae7 |
||
|
|
c5c7483268 |
||
|
|
2d97a45902 |
||
|
|
f862d64b7a | ||
|
|
7dec2660fb | ||
|
|
f9238269d7 | ||
|
|
492ed61c9f | ||
|
|
eacd6435ef | ||
|
|
24aefd3b1b |
||
|
|
7ccaa9a6b6 |
||
|
|
22192c148a | ||
|
|
a088f8bb9e | ||
|
|
62a878ded3 | ||
|
|
991cebf95d | ||
|
|
438938819e | ||
|
|
332be6e5c8 |
||
|
|
0919507ae7 |
||
|
|
a168470f29 | ||
|
|
1cd7dd6a28 | ||
|
|
bc21922cf2 | ||
|
|
58e3770b80 | ||
|
|
7eb730af78 | ||
|
|
a52922bfb5 | ||
|
|
82098a634f |
||
|
|
7d492bad67 | ||
|
|
4bfcedb8a5 | ||
|
|
80f44c494a | ||
|
|
ee8fb6998c |
||
|
|
7dfac1c0c0 |
||
|
|
2cafe926fa | ||
|
|
e800b23b4d |
||
|
|
c10792c679 |
||
|
|
845acfe1ac | ||
|
|
c041bf2192 | ||
|
|
c41b8abb13 | ||
|
|
add3628a64 | ||
|
|
487da3550b | ||
|
|
7893455b43 |
||
|
|
fb9df68477 |
||
|
|
40f3d2df91 | ||
|
|
14afc6c54a | ||
|
|
fd3ad0c16e | ||
|
|
c461def10a | ||
|
|
dac01831f2 |
||
|
|
a00284f744 |
||
|
|
88953d45d5 | ||
|
|
cf4e8d527d |
||
|
|
1219bcd029 | ||
|
|
9a9dbcf523 | ||
|
|
1449840199 | ||
|
|
2b08497c32 | ||
|
|
ce4994bec8 | ||
|
|
4b6b5f0461 | ||
|
|
31398d4247 | ||
|
|
d44821b733 |
||
|
|
eaa801f14a |
||
|
|
0db5afb920 | ||
|
|
872c4dbd30 | ||
|
|
cdec530572 | ||
|
|
68817845b0 | ||
|
|
27762d2cf7 | ||
|
|
aa7c821c70 |
||
|
|
7a26f509df |
||
|
|
f846191edd | ||
|
|
8bb5f1b786 | ||
|
|
ce5d063513 | ||
|
|
e01cde7fcb | ||
|
|
34fc7f2a84 | ||
|
|
ab3001391e | ||
|
|
f9abcb30e3 |
||
|
|
5971c5ad90 |
||
|
|
89a31141ff | ||
|
|
507d68e5c6 | ||
|
|
659c4cbf0f |
||
|
|
b17e4a5ffa | ||
|
|
b12443f48a |
||
|
|
9e72b29fc1 | ||
|
|
dc60105926 |
||
|
|
783a70da46 |
||
|
|
049bb2e1b3 |
||
|
|
8033162ba4 | ||
|
|
9435a6c045 |
||
|
|
246da3b4d8 | ||
|
|
afdf0fb3cf |
||
|
|
a9d9ccb583 | ||
|
|
f21969a016 | ||
|
|
4b79d6dae6 | ||
|
|
67e27ca7cd | ||
|
|
e3c7a915e5 | ||
|
|
06d4eff4a5 | ||
|
|
98b1a46362 | ||
|
|
09822c16a7 |
||
|
|
b454f76f72 | ||
|
|
c345268de6 |
||
|
|
587e1a4ad8 |
||
|
|
e4d9c41a77 |
||
|
|
f4bb0d8933 |
||
|
|
197cd1e12e |
||
|
|
20a1ac0e6f |
||
|
|
fd0923d2f2 |
||
|
|
8b8a0147e8 |
||
|
|
6da975fc73 |
||
|
|
991c00af95 |
||
|
|
8fffcbef7a |
||
|
|
30c9f6bb52 |
||
|
|
aed71c30f8 |
||
|
|
7a6686f467 | ||
|
|
3565094b10 |
||
|
|
0ab6ac9798 | ||
|
|
4bda2745ac | ||
|
|
e11a7de051 | ||
|
|
94bdcb7f18 | ||
|
|
fafe0207ca | ||
|
|
64fcdb5172 |
||
|
|
ade70cb2e2 | ||
|
|
145cd4be92 | ||
|
|
a0335711af | ||
|
|
16975bc3a2 | ||
|
|
863421b1b8 | ||
|
|
26a8909580 |
||
|
|
64bb392fef | ||
|
|
adbefe8363 | ||
|
|
b769144a63 | ||
|
|
45c5cb9029 | ||
|
|
74692a37a6 |
||
|
|
449a8e6ac4 |
||
|
|
b0cdae78d2 |
||
|
|
04c0ea53e6 | ||
|
|
d728cd2696 | ||
|
|
1c50a18d0a | ||
|
|
40d09875e6 | ||
|
|
f80bf187a9 | ||
|
|
18a2720ea7 | ||
|
|
d2bbfd967e | ||
|
|
18b626aa8b | ||
|
|
dc6fb57c41 | ||
|
|
6289452e95 | ||
|
|
2372e8e574 |
||
|
|
f05a806164 |
||
|
|
b7cfe0c4f9 |
||
|
|
d200c4363c |
||
|
|
ee80399be1 |
||
|
|
d3c4bcc254 |
||
|
|
4d70447a5a |
||
|
|
d3aa4f7c7c |
||
|
|
d6623c642f |
||
|
|
20067da9f5 |
||
|
|
cd3048d4cf |
||
|
|
78edd878a3 | ||
|
|
9db937e581 | ||
|
|
a133716709 | ||
|
|
cfba3d72be | ||
|
|
d817231836 | ||
|
|
d0457dcfb8 | ||
|
|
0ed7d6641e | ||
|
|
7c9c1c63cc | ||
|
|
f0841dc454 | ||
|
|
f6ee00f877 |
||
|
|
873df9094a |
||
|
|
21242e3a47 | ||
|
|
ca1c58e201 |
||
|
|
2eb9c26cdb |
||
|
|
177bc2262c |
||
|
|
50281c42e5 |
||
|
|
c19075816b |
||
|
|
48d842faa7 |
||
|
|
2e482b207b |
||
|
|
839629b102 |
||
|
|
125dec493e |
||
|
|
ffc960df5c |
||
|
|
e6df353302 |
||
|
|
c8639fe547 | ||
|
|
51b873b42e | ||
|
|
e83a8032e8 | ||
|
|
a15f2aba76 | ||
|
|
82ff563f6f |
||
|
|
2a6b7d9e7c |
||
|
|
d9809c34fc | ||
|
|
df2ec7ea14 |
||
|
|
b8f7c584c5 |
||
|
|
e87717d27c |
||
|
|
d43b786b30 | ||
|
|
2cd1d44576 | ||
|
|
1ac4abcb67 | ||
|
|
13e138aacd | ||
|
|
19e0f28c64 |
||
|
|
82fcfbcbfc | ||
|
|
021ef45f75 | ||
|
|
7e24886190 |
||
|
|
bd699d34e8 | ||
|
|
3031ca64c8 | ||
|
|
4a7cff7688 | ||
|
|
3b5cdef7f9 | ||
|
|
97fe235e60 | ||
|
|
03d9c38871 | ||
|
|
075ca53bd2 |
||
|
|
59462ad415 |
||
|
|
46e1ec4f99 | ||
|
|
f610801ee8 |
||
|
|
cb3bb4ad69 |
||
|
|
d13108b03a | ||
|
|
e18c9d2c60 | ||
|
|
fc031174bb | ||
|
|
86ff02541f | ||
|
|
5365a1cdb3 | ||
|
|
adf12505ab |
||
|
|
592517dea9 |
||
|
|
8ba00dd9f1 | ||
|
|
79095f7bd3 |
||
|
|
540c06b2b8 | ||
|
|
d536cd2239 | ||
|
|
9d10abaed4 | ||
|
|
7e52b61934 |
||
|
|
9eb259af82 |
||
|
|
cefe984c7e |
||
|
|
eb05aa8ce5 | ||
|
|
aa176b7939 | ||
|
|
e10dcfc5e7 |
||
|
|
7eae9b1abc | ||
|
|
2d590bb8c1 | ||
|
|
c8bf3ec5a4 | ||
|
|
3f4166e7b6 | ||
|
|
863176040f | ||
|
|
cff6a829c2 | ||
|
|
bf85991ee6 |
||
|
|
1a6d66f395 | ||
|
|
fc8a3c719f |
||
|
|
276a14ae05 |
||
|
|
07c2526c08 |
||
|
|
97dbafcb89 | ||
|
|
e7ef546661 | ||
|
|
0bc6869879 |
||
|
|
7d19bcf5d4 |
||
|
|
9a0a08f460 | ||
|
|
6cef4ead88 | ||
|
|
e2bbfcb088 | ||
|
|
212742a56f | ||
|
|
7bbd3dc6fb |
||
|
|
18c7a9c3a1 | ||
|
|
b6dc55f96c | ||
|
|
88100484e0 | ||
|
|
2a5bb109ba | ||
|
|
0f97f6d488 |
||
|
|
e618becfc0 | ||
|
|
5d6513c36c | ||
|
|
4db9b944a2 | ||
|
|
50808f644f | ||
|
|
e8760646f7 |
||
|
|
5b238d189c |
||
|
|
9d8a143ce8 |
||
|
|
0fabbb6a60 |
||
|
|
e06934a003 | ||
|
|
7f8726929b | ||
|
|
56c2abe613 | ||
|
|
4833a27243 | ||
|
|
e412657581 | ||
|
|
a9a651ce4d |
||
|
|
6b6ef5f18f |
||
|
|
ab5e78db2a | ||
|
|
bae37a7ae4 | ||
|
|
f2dbfbfcec |
||
|
|
652ec971d4 | ||
|
|
bd1ab74031 | ||
|
|
cf96c113e1 |
||
|
|
fa71931503 | ||
|
|
569f8a080e | ||
|
|
70c8d2a474 | ||
|
|
b8f2326fa6 | ||
|
|
d7795b8afd | ||
|
|
d2c857883f | ||
|
|
6a9aa1dca8 | ||
|
|
b149a23507 | ||
|
|
3f1d4edea3 | ||
|
|
48f6275134 |
||
|
|
8a56e1f1fa | ||
|
|
87a5c82197 | ||
|
|
ed1eca160e | ||
|
|
58edad6897 | ||
|
|
a2053c34c3 | ||
|
|
772005f431 |
||
|
|
16968834ce | ||
|
|
3cc430b418 | ||
|
|
49bc6ed47f | ||
|
|
1e0e541b57 | ||
|
|
bae6de5d26 | ||
|
|
993c214d94 |
||
|
|
4821ad3ce7 | ||
|
|
74815af6e2 | ||
|
|
4dc30dabab | ||
|
|
2e9833986d |
||
|
|
535df9cd9c | ||
|
|
f18429f23a | ||
|
|
b7368f919f | ||
|
|
703c281089 | ||
|
|
c0df11ecb8 | ||
|
|
dad376e0db | ||
|
|
2d232d15aa | ||
|
|
e713407f89 | ||
|
|
68c9ef76b2 | ||
|
|
04a602e381 | ||
|
|
272778bc67 | ||
|
|
d859f93c7b | ||
|
|
e46b623254 | ||
|
|
ae73d06301 | ||
|
|
0806df6068 | ||
|
|
1c1640634f |
||
|
|
01eb08c42b | ||
|
|
67781f63af |
||
|
|
3be0006016 |
||
|
|
7bfc70c153 | ||
|
|
f72d06a4a5 | ||
|
|
b6514dcb47 |
||
|
|
c81e68e895 |
||
|
|
e5b94d7248 |
||
|
|
e092f7ca75 |
||
|
|
f0617a53dc | ||
|
|
bcac6e80b9 | ||
|
|
eaccca52dd | ||
|
|
643bccc497 | ||
|
|
619c9015cb |
||
|
|
f9975ed47e |
||
|
|
f52f276f2e | ||
|
|
761f2e34e7 |
||
|
|
7aa30c7335 |
||
|
|
bc450b3339 | ||
|
|
7aa2f6c142 |
||
|
|
7b7d54c7bd |
||
|
|
b88b5f7b36 | ||
|
|
2c8e7b3e6b | ||
|
|
047d884323 | ||
|
|
db04f01297 | ||
|
|
8734bd1a6f |
||
|
|
3f96cb8a4a | ||
|
|
ce87857104 |
||
|
|
367245cc47 |
||
|
|
ac1e07a3cd |
||
|
|
589a31ddd0 |
||
|
|
7f4e614bb8 | ||
|
|
60e80ad634 |
||
|
|
41fbf3adb2 | ||
|
|
e44aa294b0 | ||
|
|
f6ef027014 | ||
|
|
9db42658e5 | ||
|
|
2ee423017b | ||
|
|
8353cea6b6 | ||
|
|
f1430472b8 | ||
|
|
00159b7999 |
||
|
|
99ea502102 |
||
|
|
b2da535fec | ||
|
|
7c2a7478d7 | ||
|
|
360ff420d3 |
||
|
|
67b5ca5e1c |
||
|
|
06dee4de58 | ||
|
|
a7e58ac3a3 | ||
|
|
daee3c2336 | ||
|
|
021f15256a | ||
|
|
f61bd2ceba | ||
|
|
d9e58f3096 | ||
|
|
5bb4bab718 | ||
|
|
3aacc114fd | ||
|
|
a52c67d42c | ||
|
|
126f72e1cd | ||
|
|
f7e0f7bbe0 |
||
|
|
54911fff39 | ||
|
|
7c63cb5231 |
||
|
|
c988d6aaa2 | ||
|
|
7b123d8e6c |
||
|
|
b5c7e6fbe8 | ||
|
|
216eec50fc | ||
|
|
80540281bc | ||
|
|
9154d8f42e |
||
|
|
a4cecd2d0c | ||
|
|
cf2275c3be | ||
|
|
c8b0b52d4e | ||
|
|
ae7af1d696 | ||
|
|
8b4c46d74b | ||
|
|
4b5610175f | ||
|
|
5525a9021e | ||
|
|
c61665b85d |
||
|
|
86777b9ce8 |
||
|
|
ca012bd288 | ||
|
|
28383a6355 | ||
|
|
9e07234bae | ||
|
|
2e82a53cdf | ||
|
|
98071fab94 | ||
|
|
bbee493961 |
||
|
|
c25906d7c7 |
||
|
|
b40282d566 |
||
|
|
a343b166e0 | ||
|
|
577d18a778 |
||
|
|
9fdcb901f3 | ||
|
|
2ab91bbaaa | ||
|
|
4bae94834e |
||
|
|
d8d230b554 | ||
|
|
7f77106c1b | ||
|
|
7e859c277f | ||
|
|
8ed686136a | ||
|
|
e6ecefb594 | ||
|
|
90fc604d2d |
||
|
|
4700fc89bd |
||
|
|
21a4169169 | ||
|
|
24515c2cf0 |
||
|
|
8a76981137 |
||
|
|
8520840be6 | ||
|
|
4f49428961 | ||
|
|
86c1db1c63 | ||
|
|
3d5cdad473 | ||
|
|
de237e365a | ||
|
|
de71f39232 |
||
|
|
583c0d4e17 | ||
|
|
396b679976 |
||
|
|
dde374651a |
||
|
|
d9e98a5a39 |
||
|
|
6fa80ce37d |
||
|
|
ce9f3d55a3 | ||
|
|
c9dc3223eb | ||
|
|
e967988eff |
||
|
|
63a72fc619 | ||
|
|
3395e71570 | ||
|
|
95a6486a8b |
||
|
|
5517e0dece |
||
|
|
d5947b53a8 |
||
|
|
f490618b9f |
||
|
|
e8c7756875 |
||
|
|
42c27594ab |
||
|
|
071f4756c9 |
||
|
|
f6724cb960 |
||
|
|
15f5e81552 | ||
|
|
9ffaaa16f8 |
||
|
|
0153f55016 |
||
|
|
2aebfd1cdc | ||
|
|
3cdf4fd410 | ||
|
|
ac90104103 |
||
|
|
cc9598299d | ||
|
|
ec2a1bd42a | ||
|
|
94db14e801 | ||
|
|
58be4f0e04 | ||
|
|
b6d423d2b8 |
||
|
|
1b8a7826c4 | ||
|
|
6f0743b340 |
||
|
|
4a3a06af8a |
||
|
|
2f077037ba | ||
|
|
24d6efa9fd | ||
|
|
49c77d7412 | ||
|
|
f7e005cd0f | ||
|
|
0e3c8cede7 |
||
|
|
6aa2ad1808 |
||
|
|
227c33a57d |
||
|
|
59cca7adb5 |
||
|
|
8aeed9b7bd | ||
|
|
a597a31dad | ||
|
|
942e462241 | ||
|
|
ded234467d | ||
|
|
3596e04639 |
||
|
|
2bef2e83cf |
||
|
|
c4eda992d5 |
||
|
|
64d1a78373 |
||
|
|
2afef16008 | ||
|
|
497271ea7e |
||
|
|
a3b256db1e | ||
|
|
6923a7bca0 | ||
|
|
9ae32b8ff9 | ||
|
|
45c884cba5 |
||
|
|
a0c0816191 |
||
|
|
4d1869002e | ||
|
|
70b8ededa6 | ||
|
|
033d6ac4d6 | ||
|
|
940d4534a1 | ||
|
|
36293da1e0 | ||
|
|
a00bd6ec8b |
||
|
|
71650b408c |
||
|
|
b1d44c1c87 | ||
|
|
9768c6ead3 |
||
|
|
bc84075ded | ||
|
|
db586a4c59 |
||
|
|
7f7448ef76 |
||
|
|
74a2481bf3 | ||
|
|
4c3b6ac383 | ||
|
|
d01614495f | ||
|
|
dc7579582a | ||
|
|
c2e19df4c1 |
||
|
|
af9859d7cc | ||
|
|
4d0de58409 | ||
|
|
686206161b | ||
|
|
d974ba898c |
||
|
|
2c2706b715 |
||
|
|
4df3b5156f | ||
|
|
673e33840d | ||
|
|
c793e5c394 | ||
|
|
dd76c7158f | ||
|
|
015eefe7de | ||
|
|
5ff553f6f3 | ||
|
|
cbf4c3cae2 | ||
|
|
b6b3724ed2 |
||
|
|
a06fd61ffc | ||
|
|
e9b6174157 |
||
|
|
e35120faa8 |
||
|
|
3a0add4b6e | ||
|
|
682b0b6711 |
||
|
|
f9c3ac73e0 | ||
|
|
f595741b8e | ||
|
|
dbdbd43511 | ||
|
|
0da7ac677a |
||
|
|
048ea4dc0c | ||
|
|
1873200a4f |
||
|
|
11de7b2e47 |
||
|
|
5c08af8f80 |
||
|
|
77c967f1db | ||
|
|
c97c128d16 |
||
|
|
a78950bce7 | ||
|
|
461f535d04 |
||
|
|
5199fa51ea | ||
|
|
96a689eaef |
||
|
|
6af825eae6 |
||
|
|
cdc999dd28 |
||
|
|
d965575f4a | ||
|
|
a247354db8 |
||
|
|
f2b429b7b7 |
||
|
|
ab9b21c03d | ||
|
|
b27153fe9b | ||
|
|
08ae2ef361 | ||
|
|
f130695bbf | ||
|
|
ddb5f4ed71 |
||
|
|
6224f95ea3 |
||
|
|
e81a284c39 | ||
|
|
00a14a02a6 |
||
|
|
9e526a825e |
||
|
|
8f68551454 |
||
|
|
8c433616bf | ||
|
|
5cc40ee3ba | ||
|
|
e9b654bbaa |
||
|
|
6a717469d9 |
||
|
|
f3e95cf473 | ||
|
|
c388f14d3e | ||
|
|
f2c3136921 |
||
|
|
150d1f05d0 | ||
|
|
d2eb32c910 | ||
|
|
998de87fba |
||
|
|
36d61438c1 | ||
|
|
4f861245a6 |
||
|
|
31fd6c6da6 | ||
|
|
500c556974 | ||
|
|
6d4fcedacc | ||
|
|
62128fb948 | ||
|
|
76eebfe539 |
||
|
|
a5571ba1d5 | ||
|
|
a6600e2fca |
||
|
|
c04a4701b8 | ||
|
|
dc465d5c5f | ||
|
|
6e0ed07446 | ||
|
|
7d18a4f3b8 | ||
|
|
9ac35ed47a |
||
|
|
d84757fae5 |
||
|
|
a3d76a0fd8 | ||
|
|
bf16faf1e2 | ||
|
|
10f70db9a6 | ||
|
|
6ec5a984ad | ||
|
|
d1d1cccdad | ||
|
|
b30270190a |
||
|
|
b4d5e4285e |
||
|
|
ec1914d3bd |
||
|
|
2577555737 |
||
|
|
0b8d5bdaaa |
||
|
|
63dfe70850 | ||
|
|
ec15105c2f | ||
|
|
576229ad19 | ||
|
|
71af410285 | ||
|
|
668663684c |
||
|
|
29b93366cf |
||
|
|
bdeb84adb9 | ||
|
|
e44c4aba36 | ||
|
|
a5edbf8546 | ||
|
|
ee24ad1821 | ||
|
|
20b39dc761 | ||
|
|
8ef9d11bc4 | ||
|
|
80f212cc60 |
||
|
|
80027bc714 | ||
|
|
3656df50a5 |
||
|
|
544b35fba5 | ||
|
|
583c840579 |
||
|
|
12db9ba0e1 | ||
|
|
5ca1cabe78 |
||
|
|
25045e8fb8 |
||
|
|
5fed5d9118 |
||
|
|
5330453579 |
||
|
|
5be4dab713 |
||
|
|
c16fdd997c |
||
|
|
16d5236e62 | ||
|
|
859e7af8c7 |
||
|
|
3f8af1ab76 |
||
|
|
04b0cfe50c |
||
|
|
557e614083 |
||
|
|
9e035ed727 | ||
|
|
e9c2409eab | ||
|
|
fb6d44712b | ||
|
|
81b7e7481f |
||
|
|
36f00b3afd |
||
|
|
f761f95288 |
||
|
|
d973a7d097 |
||
|
|
c160cb73cc | ||
|
|
0a49609f82 |
||
|
|
8cb88e91ee |
||
|
|
a51a487533 |
||
|
|
9cf05fb2ae |
||
|
|
97d79f1b56 |
||
|
|
a521bb6e87 |
||
|
|
aaac64618a |
||
|
|
15c069d411 | ||
|
|
beef062bb8 | ||
|
|
4c0c2a5893 | ||
|
|
72756a5c0d |
||
|
|
b6b9f2af40 |
||
|
|
30a472a8a3 |
||
|
|
f7681f7259 |
||
|
|
59fc1d02a7 |
||
|
|
037d9aa11b | ||
|
|
182fb11c80 | ||
|
|
4995a5c641 | ||
|
|
e609641336 |
||
|
|
2d24d6b997 |
||
|
|
3de422b1ab | ||
|
|
31dc9366f0 | ||
|
|
06fd9be1c2 | ||
|
|
65daa9e537 | ||
|
|
98852a63c1 |
||
|
|
ba1c7f6095 | ||
|
|
01480a539f | ||
|
|
fc7af9e1c3 | ||
|
|
b573576b00 | ||
|
|
598f9fbc83 |
||
|
|
f776e56b34 |
||
|
|
948b48bb8c |
||
|
|
14aac3a0f4 |
||
|
|
3492dfe3c8 |
||
|
|
e7ac0a9272 |
||
|
|
b888a4589e |
||
|
|
d496e81f2b |
||
|
|
0dc175434f | ||
|
|
4f96966020 | ||
|
|
f5cc21df0e |
||
|
|
69bd9e01b6 | ||
|
|
6d46bf4257 | ||
|
|
f62217f38e | ||
|
|
abb91fc3be | ||
|
|
34103cd5dd |
||
|
|
a091a4b8b9 | ||
|
|
8ebc120f36 | ||
|
|
430868e859 | ||
|
|
19a9eeb975 | ||
|
|
a8b594f9d9 | ||
|
|
e5110edcca | ||
|
|
343e24a26f | ||
|
|
d04b777159 | ||
|
|
fc4b3e44d8 | ||
|
|
0b13aa9b46 | ||
|
|
1f30306e23 | ||
|
|
56a483475b | ||
|
|
88da1b89cb | ||
|
|
71625af8a4 | ||
|
|
aac005cd0f | ||
|
|
fa70988421 | ||
|
|
e83c3d9796 | ||
|
|
17b37358e9 | ||
|
|
359ffcabb8 | ||
|
|
50af2ed45d | ||
|
|
db027929b5 | ||
|
|
da05657e13 | ||
|
|
012d034cba | ||
|
|
ebf31e85c4 | ||
|
|
ce0787f0d3 | ||
|
|
f8da7077d8 | ||
|
|
0b8e243738 | ||
|
|
5efdd1a778 | ||
|
|
2013fc0ab2 | ||
|
|
d6dca3403d | ||
|
|
b1bc9a6f5f | ||
|
|
9d8d555708 | ||
|
|
a2d0705987 | ||
|
|
9ce09c0715 | ||
|
|
9495a6c3df | ||
|
|
68724e9682 | ||
|
|
089b46b7eb | ||
|
|
706c6f6f2f | ||
|
|
1c96d8c933 | ||
|
|
42b205d75c | ||
|
|
fbb1f32a06 | ||
|
|
f9a778fcae | ||
|
|
43ec3c4f7d | ||
|
|
7336de45cb | ||
|
|
d4435ea874 | ||
|
|
fdf355c377 | ||
|
|
fa1d4d937c | ||
|
|
1d556c78b6 | ||
|
|
c68958e6b8 | ||
|
|
32c154be95 | ||
|
|
24c41195a6 | ||
|
|
651ccbcddf | ||
|
|
c2b2def1c8 | ||
|
|
5f1d5c4b88 | ||
|
|
77faffa6f7 | ||
|
|
ad38d602c7 | ||
|
|
f49037e0ca | ||
|
|
623eb0a4c0 | ||
|
|
cfcf40f1f8 | ||
|
|
89b28fd36b | ||
|
|
fb07f4d513 | ||
|
|
30df8e3558 | ||
|
|
4917b8618a | ||
|
|
753da77e08 | ||
|
|
b65a790b50 | ||
|
|
ee643d47d7 | ||
|
|
f4bce91837 | ||
|
|
5569338fbd | ||
|
|
490e3646ba | ||
|
|
018f4468cc | ||
|
|
4006554a49 | ||
|
|
22208a9471 | ||
|
|
dcb6882fbc | ||
|
|
5a19887a22 | ||
|
|
a982e0c4f4 | ||
|
|
9cca567bed | ||
|
|
927d9c7ea5 | ||
|
|
d61e2ccd6b | ||
|
|
25732f7be6 | ||
|
|
ce38e318bd | ||
|
|
f4baa43040 | ||
|
|
6fe2fecb13 | ||
|
|
01d536d7c9 | ||
|
|
213976ca11 | ||
|
|
b46fbb7879 | ||
|
|
84920e8fdf | ||
|
|
98d1d4e338 | ||
|
|
fc9227215b | ||
|
|
c96edef571 | ||
|
|
82ada44aa8 | ||
|
|
5c6ae32f99 | ||
|
|
0936d5f6ee | ||
|
|
d13d57eaa6 | ||
|
|
f4460a4449 | ||
|
|
e3ab685a26 | ||
|
|
97c058e94f | ||
|
|
3518713ac6 | ||
|
|
44bc69b320 | ||
|
|
8850beb828 | ||
|
|
90025818ed | ||
|
|
976a9efcc2 | ||
|
|
1c09741280 | ||
|
|
fc52234986 | ||
|
|
550ffe4599 | ||
|
|
4aa60a0905 | ||
|
|
f17f3068e3 | ||
|
|
9fc5890886 | ||
|
|
335c40d23e | ||
|
|
7039668669 | ||
|
|
44704c8396 | ||
|
|
76709c672a | ||
|
|
6cc053b920 | ||
|
|
4645def789 | ||
|
|
d3b22c6e21 | ||
|
|
c413bcdb94 | ||
|
|
ca10933082 | ||
|
|
6f9f0def0f | ||
|
|
f30f4fe66b | ||
|
|
6008f7e2ed | ||
|
|
a445e81ae6 | ||
|
|
4fc2c6c633 | ||
|
|
a07c0e6e04 | ||
|
|
27d67f04cb | ||
|
|
a80a707321 | ||
|
|
114e64dcf7 | ||
|
|
9e399e7a05 | ||
|
|
35dba138e0 | ||
|
|
594b9c9633 | ||
|
|
bdb0265378 | ||
|
|
a8be1b562e | ||
|
|
c361246eaa | ||
|
|
e07c53a09d | ||
|
|
eac8fa2abd | ||
|
|
de0b6dc6aa | ||
|
|
270817c022 | ||
|
|
ecc5d0b953 | ||
|
|
aa2c84a59c | ||
|
|
6cadbdf354 | ||
|
|
e8a87e5d3c | ||
|
|
13ac28b6d4 | ||
|
|
b2231c40f7 | ||
|
|
f8031203d2 | ||
|
|
0942fcb9ec | ||
|
|
22861aa1c1 | ||
|
|
5a332ed726 | ||
|
|
c1a5279da9 | ||
|
|
9e574e9d8c | ||
|
|
24a1254f03 | ||
|
|
83afc5e214 | ||
|
|
937f366b80 | ||
|
|
eb435dc065 | ||
|
|
1eee6f0211 | ||
|
|
577b748f5f | ||
|
|
98398e0420 | ||
|
|
30b8955134 | ||
|
|
1b1d1fd9f7 | ||
|
|
5cc4c9f4ab | ||
|
|
9d4c140c49 | ||
|
|
ed9e15e3c0 | ||
|
|
e8a964fd57 |
||
|
|
0f6b98506e | ||
|
|
9185e0b7a8 | ||
|
|
f0c05686e5 | ||
|
|
994758aa07 | ||
|
|
d5fbd3be93 | ||
|
|
77d8160dab | ||
|
|
9d1a1d428b | ||
|
|
09fb6a1393 | ||
|
|
6aa05ace19 | ||
|
|
5cdd2645fd | ||
|
|
ac08cd5eb1 | ||
|
|
d6ac93a470 | ||
|
|
d83a261290 | ||
|
|
85a860d5dd | ||
|
|
129b144852 | ||
|
|
36f93af275 | ||
|
|
904f57d9c3 | ||
|
|
5d860471ac | ||
|
|
6232241ef1 | ||
|
|
c11b8ceb09 | ||
|
|
76dcd64a82 | ||
|
|
12c72d3e19 | ||
|
|
090694dba7 | ||
|
|
d9605d005d | ||
|
|
3f2d89c9d6 | ||
|
|
ed92d959b2 | ||
|
|
2ceeb88c63 | ||
|
|
3d2eb1d45e | ||
|
|
515f2fb5b2 | ||
|
|
e48365c329 | ||
|
|
3b6d059eac | ||
|
|
9cff2efb62 | ||
|
|
de2a5286eb | ||
|
|
28e79b7a38 | ||
|
|
d81c53a748 | ||
|
|
afd46e1618 | ||
|
|
f91ea06cc5 | ||
|
|
66410b9396 | ||
|
|
e0769fe2a3 | ||
|
|
132fe9a4fa | ||
|
|
fcd4f9aa0d | ||
|
|
648165b839 | ||
|
|
70665ea0fa | ||
|
|
a3a0b6c1b2 | ||
|
|
23c3a7c7f6 | ||
|
|
58904af92c | ||
|
|
23ab0f1ae1 | ||
|
|
3857145754 | ||
|
|
945b8384ed | ||
|
|
f864dd832c | ||
|
|
c360aebec3 | ||
|
|
14694c8357 | ||
|
|
123fd0b65a | ||
|
|
cff4db6e7c | ||
|
|
e4532eb8e0 | ||
|
|
2dcc4ccf80 | ||
|
|
985840178a | ||
|
|
034e2e19f3 | ||
|
|
f62198aeab | ||
|
|
6c5183486f | ||
|
|
d7407eabab | ||
|
|
3437592c48 | ||
|
|
ac48dc22c6 | ||
|
|
9a04ce660c | ||
|
|
24b7bca37d | ||
|
|
23a84e9b82 | ||
|
|
4750137642 | ||
|
|
eee2aa339d | ||
|
|
749f85e468 | ||
|
|
959f96ff53 | ||
|
|
510961bbb9 | ||
|
|
a2852da3e7 | ||
|
|
1fe40db3cb | ||
|
|
2b51c0e499 | ||
|
|
365d12cbea | ||
|
|
2170ca4cd5 | ||
|
|
d3f306505e | ||
|
|
e067e019f9 | ||
|
|
9255ab22f9 | ||
|
|
880ba20a98 | ||
|
|
6bb743cb22 | ||
|
|
1bbffad7b9 | ||
|
|
5e7eb91808 | ||
|
|
ef2c62ab82 | ||
|
|
437bcdbd66 | ||
|
|
ab2eec854d | ||
|
|
22ec94ee56 | ||
|
|
c3f2e888a5 | ||
|
|
bfafb3a492 | ||
|
|
2d84c04add | ||
|
|
8b299098c9 | ||
|
|
e50abb20b3 | ||
|
|
2cb2bf05df | ||
|
|
a69f4294bc | ||
|
|
e16ca36fe0 | ||
|
|
65f0f31b7b | ||
|
|
43a872c98a | ||
|
|
d333ed12c6 | ||
|
|
554cde1a22 | ||
|
|
661ee49eda | ||
|
|
a670a3e040 | ||
|
|
44ae54fc42 | ||
|
|
72ee73f886 | ||
|
|
b152aba6c6 | ||
|
|
c255a35800 | ||
|
|
d583efb861 | ||
|
|
178902a692 | ||
|
|
a6c258eb7f | ||
|
|
6465a91b65 | ||
|
|
6afa7704b1 | ||
|
|
8519ccf18c | ||
|
|
b0d41f081b | ||
|
|
f16ae07d78 | ||
|
|
ac151ef867 | ||
|
|
9d0804de7a | ||
|
|
d30ffcf52f | ||
|
|
7f795ed558 | ||
|
|
ad72287b4c | ||
|
|
170a429c52 | ||
|
|
ca389e70e1 | ||
|
|
39f74280b3 | ||
|
|
9d57dcf020 | ||
|
|
8993c55e6e | ||
|
|
44f9cfaaf1 | ||
|
|
de6bd537b5 | ||
|
|
bd3bec493e | ||
|
|
5dc6d2914e | ||
|
|
3580478dc9 | ||
|
|
e06d0046b1 | ||
|
|
f0a6725a74 | ||
|
|
ed83ad75a9 | ||
|
|
06190f1518 | ||
|
|
ed34ee1808 | ||
|
|
45ff578f69 | ||
|
|
a55217ef36 | ||
|
|
657ffdd75f | ||
|
|
2ca7aa8c80 | ||
|
|
ed71ad0d3a | ||
|
|
7181cc36d5 | ||
|
|
96b23e03bd | ||
|
|
5e36a87916 | ||
|
|
379f8666c1 | ||
|
|
10315944d3 | ||
|
|
d88f846599 | ||
|
|
bd5dfa0b3e | ||
|
|
aa318a1366 | ||
|
|
2332563bda | ||
|
|
ba9b4a1d9b | ||
|
|
2a183281fa | ||
|
|
5389543a39 | ||
|
|
ec5c77b251 | ||
|
|
3f69a1fb62 | ||
|
|
ff88c4bb34 | ||
|
|
8eebf19627 | ||
|
|
4b74896a4d | ||
|
|
21544a404c | ||
|
|
22bc56ddf1 | ||
|
|
108b67282a | ||
|
|
f588c565e2 | ||
|
|
780ccfe137 | ||
|
|
fba2826b70 | ||
|
|
68354eb94e | ||
|
|
c7ec93466d | ||
|
|
d19854f4dc | ||
|
|
1461197826 | ||
|
|
0c9e4764ea | ||
|
|
3c8a7c9fd7 | ||
|
|
da8b469ab8 | ||
|
|
33d9157929 | ||
|
|
e3f5e39e17 | ||
|
|
e17c4377da | ||
|
|
1da84349c4 | ||
|
|
b7e8af5977 | ||
|
|
1352d2638a | ||
|
|
db59c16f42 | ||
|
|
b7e6390f04 | ||
|
|
f7e2d5b817 | ||
|
|
d082d94f25 | ||
|
|
a8d41e0c57 | ||
|
|
69b8a2d8cc | ||
|
|
1aac19caaf | ||
|
|
c7b9a339eb | ||
|
|
0a48371985 | ||
|
|
c918380802 | ||
|
|
735a4452df | ||
|
|
b6f391d8e9 | ||
|
|
551909893e | ||
|
|
39fd4936b5 | ||
|
|
940eb76b7f | ||
|
|
389d0cec52 | ||
|
|
3a03aef3e2 | ||
|
|
1f3c6c5dca | ||
|
|
77ebd05fce | ||
|
|
641b3ffa71 | ||
|
|
f8f89a8476 | ||
|
|
72a0e626dd | ||
|
|
8786732044 | ||
|
|
42d2c4d26a | ||
|
|
e10ae8a187 | ||
|
|
47e468cebe | ||
|
|
5946313b2e | ||
|
|
ab2dc71d34 | ||
|
|
aae0f6c484 | ||
|
|
2f048d3652 | ||
|
|
8292d35ea8 | ||
|
|
264d75b9e0 | ||
|
|
807b3bced3 | ||
|
|
ac844eacf4 | ||
|
|
3f6315fe26 | ||
|
|
9a38f61e4d | ||
|
|
a571ec4cd9 | ||
|
|
222c6e4c03 | ||
|
|
df54953032 | ||
|
|
5cf3481483 | ||
|
|
d6ebf772e3 | ||
|
|
3effe464c6 | ||
|
|
9dd4080fe6 | ||
|
|
d0c15d5a0c | ||
|
|
44bd308dd2 | ||
|
|
dceea3aabe | ||
|
|
90a283bc44 | ||
|
|
f19ea17d0a | ||
|
|
2e84e30ad3 | ||
|
|
a45a917766 | ||
|
|
f864418b9e | ||
|
|
bf7d113caa | ||
|
|
249a919c59 | ||
|
|
adc5c4b572 | ||
|
|
d0e2e3e63f | ||
|
|
0f7938ccb7 | ||
|
|
2e590d0e86 | ||
|
|
5ca808ed59 | ||
|
|
b295163142 | ||
|
|
946e95172f | ||
|
|
7b4ceb2974 | ||
|
|
cc8f835f07 | ||
|
|
8a479733f0 | ||
|
|
9acaa25164 | ||
|
|
7ad649e3b7 | ||
|
|
db2e517450 | ||
|
|
ebf5fca520 | ||
|
|
5bf21abc66 | ||
|
|
875c4a5e05 | ||
|
|
aa9ff632ca | ||
|
|
df70fa8596 | ||
|
|
ef737c2239 | ||
|
|
e0d40c17a0 | ||
|
|
0f7f328206 | ||
|
|
3d5f01ba3f | ||
|
|
ffe71d324d | ||
|
|
822fb134e0 | ||
|
|
ddd637b870 | ||
|
|
4e896c427d | ||
|
|
3ea4542015 | ||
|
|
e35ca1d6ff | ||
|
|
87d86d724c | ||
|
|
63602c4a9e | ||
|
|
62e7a41797 | ||
|
|
555c553992 | ||
|
|
d53c166f95 | ||
|
|
2bcabb5497 | ||
|
|
d0afaa5fbe | ||
|
|
39f5762ae4 | ||
|
|
79aaedc681 | ||
|
|
bc3a0e8c59 | ||
|
|
784d07e940 | ||
|
|
d4ba7b7291 | ||
|
|
88ec7026ea | ||
|
|
053d198f22 | ||
|
|
6549f51591 | ||
|
|
95860c6b1b | ||
|
|
838478d65d | ||
|
|
fa269d7c6f | ||
|
|
bfbb7d4bb5 | ||
|
|
6a69a2c943 | ||
|
|
1301343d1d | ||
|
|
5912608b04 | ||
|
|
ca0477c62f | ||
|
|
6c4f0d7894 | ||
|
|
c139221dbc | ||
|
|
0949fa62ec | ||
|
|
9152e021e2 | ||
|
|
efc5e6f2ca | ||
|
|
7fc6aab99a | ||
|
|
954c85a593 | ||
|
|
8218923625 | ||
|
|
08f73d7d91 | ||
|
|
265f68a879 | ||
|
|
82c629b9c0 | ||
|
|
f56b699d5b | ||
|
|
77231e97c0 | ||
|
|
4e2e00b450 | ||
|
|
2fc442fe2d | ||
|
|
ca2a426a83 | ||
|
|
f7a5d06c6d | ||
|
|
e3139db712 | ||
|
|
173beecd17 | ||
|
|
5332ea4142 | ||
|
|
4c25610cd8 | ||
|
|
8d7d379a61 | ||
|
|
737db1d641 | ||
|
|
88ad46fd4d | ||
|
|
8aa9a9329e | ||
|
|
a62f9ab23c | ||
|
|
3c514266dd | ||
|
|
79548c3bf9 | ||
|
|
6616ed8816 | ||
|
|
bf7966183a | ||
|
|
38c307eefd | ||
|
|
cff5f3e774 | ||
|
|
3b22dd4f2d | ||
|
|
3d8ceb1c67 | ||
|
|
b72961f12d | ||
|
|
49481f60a5 | ||
|
|
30c4d0eaf3 | ||
|
|
5432dc04a6 | ||
|
|
3763f96011 | ||
|
|
0360ce1865 | ||
|
|
a740f8aa88 | ||
|
|
49668f711a | ||
|
|
5a8efcd526 | ||
|
|
bbbb3247ea | ||
|
|
7e961061e1 | ||
|
|
7b852ffe9d | ||
|
|
2c8300e76f | ||
|
|
3e058dd69c | ||
|
|
f46d86d632 | ||
|
|
8cc2f99ec4 | ||
|
|
4add2d344b | ||
|
|
5006dc95d2 | ||
|
|
b3b2e84533 | ||
|
|
33994f0024 | ||
|
|
88d19d47b5 | ||
|
|
90edf14beb | ||
|
|
4654a4efe4 | ||
|
|
30b8a2069e | ||
|
|
febd28a74e | ||
|
|
3068075963 | ||
|
|
e302642d06 | ||
|
|
7b84e50584 | ||
|
|
d503ea436c | ||
|
|
369b8b8474 | ||
|
|
d356b44631 | ||
|
|
f706f98ce7 | ||
|
|
b3abeb723e | ||
|
|
f87e4faa22 | ||
|
|
08044f2436 | ||
|
|
85f9608ccb | ||
|
|
d5d821fd87 | ||
|
|
618d94c897 | ||
|
|
da41f7681b | ||
|
|
e65d33b89c | ||
|
|
afe009e6c9 | ||
|
|
7d3c765927 | ||
|
|
45417832e1 | ||
|
|
636f83ab67 | ||
|
|
de8b437549 | ||
|
|
b4ae60b3d0 | ||
|
|
72f3b4a116 | ||
|
|
0fe290c321 | ||
|
|
a81fcd3fef | ||
|
|
48f4f0850d | ||
|
|
f9bd4acb10 | ||
|
|
5b389d6f36 | ||
|
|
10c0002af1 | ||
|
|
99e734cb71 | ||
|
|
17fd176461 | ||
|
|
17c551c793 | ||
|
|
7feb638b5c | ||
|
|
96eaf9cea0 | ||
|
|
693ad3296c | ||
|
|
9b4b123a0e | ||
|
|
5e2e88ca92 | ||
|
|
055fdfa9c6 | ||
|
|
4310296648 | ||
|
|
c7b52bc730 | ||
|
|
e4a2bb5b52 | ||
|
|
08d5221114 | ||
|
|
683d10a480 | ||
|
|
c92e00f17b | ||
|
|
9bf22f20bf | ||
|
|
dec6023fe6 | ||
|
|
426c7428d6 | ||
|
|
fbc65e0d7b | ||
|
|
1d9981b4f9 | ||
|
|
f5775bcba0 | ||
|
|
69d8015ba7 | ||
|
|
5ea3a36a3f | ||
|
|
8cf89bd623 | ||
|
|
304b16a9be | ||
|
|
cb11bea1f2 | ||
|
|
1fae9534d5 | ||
|
|
0093984861 | ||
|
|
2b130fb4dd | ||
|
|
b357592248 | ||
|
|
a2bb80b8bd | ||
|
|
6ac06b28b1 | ||
|
|
b8c9d61f20 | ||
|
|
04978e9b75 | ||
|
|
b80f2357b9 | ||
|
|
2ecd85d7b3 | ||
|
|
5563b9baf4 | ||
|
|
4261b9f5d0 | ||
|
|
b3b65d77e0 | ||
|
|
a0ecab901f | ||
|
|
c995fa87a7 | ||
|
|
3b54f3e418 | ||
|
|
df0731f2e8 | ||
|
|
ed3209888a | ||
|
|
f1a9d50a06 | ||
|
|
7c3cc8fc0d | ||
|
|
00434d4bb6 | ||
|
|
af0899ae2a | ||
|
|
a3c8fca1db | ||
|
|
8553ad6a59 | ||
|
|
d35348830a | ||
|
|
2c50ccb764 | ||
|
|
8d14872700 | ||
|
|
e7eb3b8ec3 | ||
|
|
9b5261512d | ||
|
|
d41331bd69 | ||
|
|
a47c0e26c0 | ||
|
|
7e516cb7b0 | ||
|
|
09c07e2950 | ||
|
|
bea40aab8c | ||
|
|
c7052a6404 | ||
|
|
9af2169027 | ||
|
|
975140d352 | ||
|
|
669bdc92e1 | ||
|
|
b2ccc62582 | ||
|
|
2e1b16826b | ||
|
|
43523dac4d | ||
|
|
5eaf2aa2bf | ||
|
|
95e170a15f | ||
|
|
7fabd712a1 | ||
|
|
40c9406ca4 | ||
|
|
8fe05bb599 | ||
|
|
a44a60ddd4 | ||
|
|
fc505091c2 | ||
|
|
ce8574aff4 | ||
|
|
009543b7e4 | ||
|
|
3f6b130d6e | ||
|
|
2432a22400 | ||
|
|
dbf6d7cf8f | ||
|
|
24106081b5 | ||
|
|
e3d3675493 | ||
|
|
bf9316bb7e | ||
|
|
ca3aa1e75f | ||
|
|
def654434c | ||
|
|
ef96705677 | ||
|
|
8673711d84 | ||
|
|
b572cbeef1 | ||
|
|
e86f4d6250 | ||
|
|
43701cae7c | ||
|
|
b8db970455 | ||
|
|
144cddaf39 | ||
|
|
6aa0e4346d | ||
|
|
21882fd4a0 | ||
|
|
d635a347d1 | ||
|
|
bf6a4ad747 | ||
|
|
ebf0da0f7b | ||
|
|
33e9ce1ddf | ||
|
|
9d2a129832 | ||
|
|
86e11c619d | ||
|
|
7313d327fb | ||
|
|
7cbf750329 | ||
|
|
9a753f4fa9 | ||
|
|
cd40105c40 | ||
|
|
5bad061c19 | ||
|
|
f2549650e6 | ||
|
|
f00fc944fb | ||
|
|
fd231b6ce2 | ||
|
|
81cd781c45 | ||
|
|
3d53b4ca17 | ||
|
|
b0e388747c | ||
|
|
46c865f295 | ||
|
|
00a5a0f0df | ||
|
|
b4f6df2fb6 | ||
|
|
5a3daae72f | ||
|
|
ddc5367231 | ||
|
|
4f3a71d14b | ||
|
|
ad6dc3f8ba | ||
|
|
30e2cac753 | ||
|
|
cd35e713e0 | ||
|
|
ac7e2c6d71 | ||
|
|
c1324b0206 | ||
|
|
5959346e17 | ||
|
|
e6be02264a | ||
|
|
260953da02 | ||
|
|
f0802e8114 | ||
|
|
c386e29d0c | ||
|
|
22484983e9 | ||
|
|
06080dd873 | ||
|
|
8f58c0582c | ||
|
|
676981c621 | ||
|
|
8b2e28a6ef | ||
|
|
6972261261 | ||
|
|
6703950abe | ||
|
|
fd7cb9e213 | ||
|
|
34ef5ab098 | ||
|
|
dd70f1b24e | ||
|
|
7277c95fb5 | ||
|
|
e97e9b5ae5 | ||
|
|
4cae9ea88f | ||
|
|
5b4381c19c | ||
|
|
fd77926700 | ||
|
|
de9ef74479 | ||
|
|
aabb7f9345 | ||
|
|
7e06912bca | ||
|
|
66a16b560f | ||
|
|
b11b8a93cd | ||
|
|
03976b650d | ||
|
|
c6ff88d0fc | ||
|
|
80842cbc0e | ||
|
|
d9b0091357 | ||
|
|
cfd18b20fc | ||
|
|
7eb30596f6 | ||
|
|
3f304a2e92 | ||
|
|
4c581cdcf2 | ||
|
|
8ec958fb35 | ||
|
|
382c09c187 | ||
|
|
16b288222d | ||
|
|
01ad449f29 | ||
|
|
a8ead21e95 | ||
|
|
216d3548af | ||
|
|
91d576eb45 | ||
|
|
990ddb5a5e | ||
|
|
d9bbdf7f07 | ||
|
|
56b0061393 | ||
|
|
011cd50e2e | ||
|
|
e38be6b2ea | ||
|
|
d23c68361a | ||
|
|
652eb3686f | ||
|
|
7f2bc2a23b | ||
|
|
05d357e98e | ||
|
|
a7ca52dee0 | ||
|
|
58e817cb0f | ||
|
|
de3475aa64 | ||
|
|
e500e64ebd | ||
|
|
cff9d0aa58 | ||
|
|
459a13bf79 | ||
|
|
c00d808bf8 | ||
|
|
1b6f081619 | ||
|
|
826ff4df50 | ||
|
|
2c25e488c4 | ||
|
|
57155b561a | ||
|
|
e55e550198 | ||
|
|
00e1b68e74 | ||
|
|
81e44ed2de | ||
|
|
df21315a24 | ||
|
|
4f0431f9e9 | ||
|
|
70a690650d | ||
|
|
6b0a99932f | ||
|
|
c60e0d03fb | ||
|
|
e58cab0250 | ||
|
|
a9d1fdae3d | ||
|
|
9b36437d97 | ||
|
|
05f392c6bc | ||
|
|
45e1aa112f | ||
|
|
22762f2c16 | ||
|
|
dcadf33988 | ||
|
|
89de903925 | ||
|
|
9dd8e3954c | ||
|
|
f6e27617f8 | ||
|
|
24866b77c7 | ||
|
|
ea3e160db1 | ||
|
|
d91750090b | ||
|
|
45bc018672 | ||
|
|
f232958daf | ||
|
|
752e862b80 | ||
|
|
23e7ac3659 | ||
|
|
cda21c5481 | ||
|
|
e60b5602ec | ||
|
|
960291c2f2 | ||
|
|
7a15045fbc | ||
|
|
5eb9fa6d16 | ||
|
|
dc552bb869 | ||
|
|
8dfa7c23f3 | ||
|
|
d8e50d56da | ||
|
|
dbcbc2c119 | ||
|
|
f6d012adf8 | ||
|
|
6264cf8916 | ||
|
|
fb4b894b77 | ||
|
|
18e6ec9f02 | ||
|
|
c90a62ea13 | ||
|
|
226672da9f | ||
|
|
fb1cfc35bf | ||
|
|
b25001333d | ||
|
|
f73484a4f4 | ||
|
|
127f60c3e9 | ||
|
|
505852c04c | ||
|
|
f750f38d60 | ||
|
|
d935af3229 | ||
|
|
786a209d2b | ||
|
|
0b3dc9db21 | ||
|
|
71103ef2c1 | ||
|
|
1e203e955a | ||
|
|
6ab890ddb7 | ||
|
|
1976eac1bf | ||
|
|
3715749cc6 | ||
|
|
da690dfc37 | ||
|
|
fd7fc2e202 | ||
|
|
7da0506f2d | ||
|
|
e10fe42928 | ||
|
|
c495502c8f | ||
|
|
257f9ce1ed | ||
|
|
2dede23a3d | ||
|
|
c9b84abe46 | ||
|
|
eeae09be5e | ||
|
|
301268f67f | ||
|
|
44ef4d3eaa | ||
|
|
4e6a600b97 | ||
|
|
082ce1dd19 | ||
|
|
f4e78d7254 | ||
|
|
a3cb64c320 | ||
|
|
83e4d35b44 | ||
|
|
8005f675a7 | ||
|
|
add9a0790d | ||
|
|
4e3779ae1d | ||
|
|
f832a63501 | ||
|
|
1592a45db8 | ||
|
|
ba0f07cc1f | ||
|
|
e9a78b8ccb | ||
|
|
97766ba1f4 | ||
|
|
bd9d1b9539 | ||
|
|
69ff7dd634 | ||
|
|
0c69f4ad84 | ||
|
|
3b0823f5e6 | ||
|
|
da66245729 | ||
|
|
ad74464e94 | ||
|
|
350706b2f0 | ||
|
|
4b2fcb09a4 | ||
|
|
c8f5eb54db | ||
|
|
35375b19ff | ||
|
|
455c159b48 | ||
|
|
9fe3d3c937 | ||
|
|
dc0edb2b2b | ||
|
|
6b808b2faa | ||
|
|
3b4dad470c | ||
|
|
7fadbd682a | ||
|
|
0dc20329a4 | ||
|
|
f69c71000a | ||
|
|
efc1d38efd | ||
|
|
fb994b1399 | ||
|
|
5e5510cfcf | ||
|
|
4a940da1a2 | ||
|
|
6c808e426f | ||
|
|
5a6d60001d | ||
|
|
9331e42ee1 | ||
|
|
effac994db | ||
|
|
ae2afa27fc | ||
|
|
cd92ef3696 | ||
|
|
e538aa2cde | ||
|
|
04dba17b80 | ||
|
|
bc94c6b6e3 | ||
|
|
eb6d4bb008 | ||
|
|
2b5db0321b | ||
|
|
caa833877d | ||
|
|
754611180b | ||
|
|
6dafe69ac6 | ||
|
|
00150f3556 | ||
|
|
e2f50750d2 | ||
|
|
f83d0d3b0c | ||
|
|
9ebe06156c | ||
|
|
67d3ab8883 | ||
|
|
9657071301 | ||
|
|
cb82e48636 | ||
|
|
47e19b8d18 | ||
|
|
a49b744e95 | ||
|
|
dbbf95b184 | ||
|
|
6ed23fec7d | ||
|
|
7415d370e6 | ||
|
|
6fb0335269 | ||
|
|
a987b65bd2 | ||
|
|
2c468f091a | ||
|
|
b35ce43b7f | ||
|
|
2f57b86560 | ||
|
|
5f23aab807 | ||
|
|
7d43c4fa00 | ||
|
|
e5c0a54c57 | ||
|
|
f6c9237a01 | ||
|
|
07f87969ea | ||
|
|
3857fd72b5 | ||
|
|
22da74211d | ||
|
|
74069e771f | ||
|
|
76e47e5198 | ||
|
|
3580233b38 | ||
|
|
85213f077b | ||
|
|
e03cf3f517 | ||
|
|
9935286e19 | ||
|
|
bb50bdbc34 | ||
|
|
3d419bf55d | ||
|
|
13199792a7 | ||
|
|
bc26cde436 | ||
|
|
dd66ad6731 | ||
|
|
e2236d50d6 | ||
|
|
48fa70c6a6 | ||
|
|
bddf0faa9c | ||
|
|
6813cd923f | ||
|
|
b7bc570215 | ||
|
|
089059aec6 | ||
|
|
10c62b27dd | ||
|
|
ef16c915d4 | ||
|
|
8d352d9a78 | ||
|
|
2f34307e12 | ||
|
|
8367ae4e98 | ||
|
|
71cca7a444 | ||
|
|
2fb00a980a | ||
|
|
651e59fce1 | ||
|
|
5a322ecc1e | ||
|
|
8d41d6ba24 | ||
|
|
bad8cfb3d9 | ||
|
|
c61f6f402a | ||
|
|
b144c3cfbd | ||
|
|
0f4058a317 | ||
|
|
d22b089241 | ||
|
|
2826c1a558 | ||
|
|
9d583961e7 | ||
|
|
e6e99ffbb9 | ||
|
|
469c531ae4 | ||
|
|
d11b33030f | ||
|
|
1fad70e5b9 | ||
|
|
895945e3cc | ||
|
|
2e845feb02 | ||
|
|
56371aaf0f | ||
|
|
39570053e1 | ||
|
|
e2ca6d7608 | ||
|
|
339955376e | ||
|
|
2a599b8646 | ||
|
|
aae56fee39 | ||
|
|
73b37989f7 | ||
|
|
2be674c909 | ||
|
|
1fdda30c9b | ||
|
|
09c9d48a6a | ||
|
|
9ea3871568 | ||
|
|
6191b2919e | ||
|
|
9645356eeb | ||
|
|
7ddb542ac4 | ||
|
|
853ce866cb | ||
|
|
d9816be5de | ||
|
|
3b315fbc53 | ||
|
|
472abb6fd9 | ||
|
|
71a2c14d1b | ||
|
|
b0a13a851c | ||
|
|
a7152716e2 | ||
|
|
f2aef81c96 | ||
|
|
d824b79a19 | ||
|
|
c875c27e83 | ||
|
|
24e2ad5b3f | ||
|
|
5a469dc2e3 | ||
|
|
0df12e31e2 | ||
|
|
f47f054d0b | ||
|
|
bab8d0b26a | ||
|
|
85ea737a98 | ||
|
|
cfe72c2736 | ||
|
|
4bc4b1500c | ||
|
|
c3aa85831f | ||
|
|
ece437f8fd | ||
|
|
6b68d94079 | ||
|
|
bbea6d1747 | ||
|
|
42f9726ffa | ||
|
|
e228357f58 | ||
|
|
5a8f5cefdd | ||
|
|
ea6d0cf5b5 | ||
|
|
05437a15a9 | ||
|
|
97c2598cdf | ||
|
|
d4ba9dcf21 | ||
|
|
23f7a12b52 | ||
|
|
f9a6d10eec | ||
|
|
8c4b2a0d2e | ||
|
|
dfc3a7ce2f | ||
|
|
a75eac6c0f | ||
|
|
1b904ae767 | ||
|
|
41970cb2c6 | ||
|
|
4ffa34544e | ||
|
|
577a3d116e | ||
|
|
a268d9e952 | ||
|
|
a495527e2b | ||
|
|
0999d4d691 | ||
|
|
e0a2f1906d | ||
|
|
dc58a17e64 | ||
|
|
a14dc4dad2 | ||
|
|
6d32fb2bb7 | ||
|
|
4977de8453 | ||
|
|
72ea20f06a | ||
|
|
122ec39a27 | ||
|
|
a4ce664f17 | ||
|
|
10dc5ef0b7 | ||
|
|
2a53934834 | ||
|
|
2aa0c6e24b | ||
|
|
1abd5ef447 | ||
|
|
76fa457654 | ||
|
|
23e62b0056 | ||
|
|
1443131fde | ||
|
|
bea03bb4bb | ||
|
|
0de44cc844 | ||
|
|
d61ef0c66c | ||
|
|
50ff7ce89f | ||
|
|
4d614c173b | ||
|
|
5ffbf907de | ||
|
|
92f5c06ba6 | ||
|
|
6a0d19ef5c | ||
|
|
03e9d0182d | ||
|
|
4c1b5c3429 | ||
|
|
1cebd345aa | ||
|
|
65a716ec02 | ||
|
|
4fa9184b01 | ||
|
|
74c7c72fb3 | ||
|
|
89034f8b3f | ||
|
|
9abc08ea9f | ||
|
|
51dc02f298 | ||
|
|
80a7c3f293 | ||
|
|
0e0775b74a | ||
|
|
30192b2318 | ||
|
|
95890a2a61 | ||
|
|
71e83635ea | ||
|
|
0caa101ec7 | ||
|
|
e07b39dfcb | ||
|
|
c5eecd23eb | ||
|
|
0ddabb95c3 | ||
|
|
b527fd594d | ||
|
|
2ace30cdb0 | ||
|
|
e32c893aa1 | ||
|
|
d4b64a3c8e | ||
|
|
3445066b11 | ||
|
|
c5008f61e0 | ||
|
|
9b0cfd9884 | ||
|
|
f43742c3f0 | ||
|
|
b282b7c72d | ||
|
|
4ca5d908ff | ||
|
|
9b7ae20aa9 | ||
|
|
6c5444eb68 | ||
|
|
9f0ad2bd95 | ||
|
|
5e73b7b40e | ||
|
|
fe33d3eed5 | ||
|
|
cb650c1c99 | ||
|
|
689632835e | ||
|
|
3a5db543bb | ||
|
|
241ac2400a | ||
|
|
75263fa852 | ||
|
|
00a1cbb6b8 | ||
|
|
3da4c2e13e | ||
|
|
39518e15ef | ||
|
|
7ec4d5faa2 | ||
|
|
ddb6d89be3 | ||
|
|
bed53d1c0b | ||
|
|
298151237e | ||
|
|
1448db9603 | ||
|
|
931d571606 | ||
|
|
5c70e2bcb1 | ||
|
|
5d000ca290 | ||
|
|
0d63b4520a | ||
|
|
12fd53c27e | ||
|
|
7d37cfa748 | ||
|
|
d2ef893b72 | ||
|
|
6f36b0a246 | ||
|
|
bf0a50880d | ||
|
|
e9fec3b1dc | ||
|
|
dd9f55c8bb | ||
|
|
4a204f19c9 | ||
|
|
d8c9fb31d0 | ||
|
|
2188f4de68 | ||
|
|
4f444ee6a8 | ||
|
|
39dd4a0255 | ||
|
|
12dd35ef36 | ||
|
|
6e527e7416 | ||
|
|
0d1866b393 | ||
|
|
8f295f7a03 | ||
|
|
a650dd9d64 | ||
|
|
0dee76f259 | ||
|
|
dfb29b5388 | ||
|
|
5d9b3d7777 | ||
|
|
6fcb6d3766 | ||
|
|
180cf9165f | ||
|
|
9b42b2a130 | ||
|
|
ce0a9b697e | ||
|
|
8797f0ebef | ||
|
|
38c22e83b6 | ||
|
|
4058cfdea4 | ||
|
|
29f0aa39d2 | ||
|
|
fdde17281d | ||
|
|
f63325aa9a | ||
|
|
06121eda76 | ||
|
|
7de7bd0e37 | ||
|
|
d43dc1b9d6 | ||
|
|
1ca0e06a27 | ||
|
|
1bc5b100ec | ||
|
|
7be16dd524 | ||
|
|
a9c530281e | ||
|
|
f2d6f77462 | ||
|
|
386cd1f3f0 | ||
|
|
effe7e5e12 | ||
|
|
e38e170656 | ||
|
|
4e118eff01 | ||
|
|
ecf5682930 | ||
|
|
ed82f62a5a | ||
|
|
5a61600bc9 | ||
|
|
1102143c33 | ||
|
|
228fc82fc9 | ||
|
|
1fcf4a6550 | ||
|
|
e5f1755172 | ||
|
|
edcc027d89 | ||
|
|
cc15629966 | ||
|
|
15606f8dea | ||
|
|
e91b53be87 | ||
|
|
ba3e14dd1d | ||
|
|
07b8c13db3 | ||
|
|
3f91165f09 | ||
|
|
8ff34e6c5d | ||
|
|
c8e7d95b34 | ||
|
|
8511915294 | ||
|
|
1d4d86c876 | ||
|
|
e9dc1dd478 | ||
|
|
c6de4430a0 | ||
|
|
a81c50ff55 | ||
|
|
7057d3742b | ||
|
|
427a5ca3c3 | ||
|
|
fd018d7ceb | ||
|
|
529d0d99c5 | ||
|
|
2bf91e54cd | ||
|
|
f8cf685c30 | ||
|
|
0ecae1f50d | ||
|
|
7a3bc410d0 | ||
|
|
675d6c81cd | ||
|
|
e999918cd1 | ||
|
|
6c9d158609 | ||
|
|
2856f49b3a | ||
|
|
33653f2864 | ||
|
|
7024fe1192 | ||
|
|
ee752d9b66 | ||
|
|
19de7539f4 | ||
|
|
8c47ab21ec | ||
|
|
71150430a9 | ||
|
|
86d4aac918 | ||
|
|
55382dd184 | ||
|
|
dcc17bbfa4 | ||
|
|
ead50cca62 | ||
|
|
bcfd574664 | ||
|
|
75f214103e | ||
|
|
fa1550ceaa | ||
|
|
5fa3504ad0 | ||
|
|
e9ca508e8e | ||
|
|
43f4d0df7a | ||
|
|
2482baf837 | ||
|
|
084818b399 | ||
|
|
50505dfd71 | ||
|
|
91337940d3 | ||
|
|
34f05d4ba6 | ||
|
|
7706530aa8 | ||
|
|
9af62414db | ||
|
|
0397274fed | ||
|
|
ba84658503 | ||
|
|
4fa2c30d3f | ||
|
|
63ddcf22d9 | ||
|
|
6db2ad2130 | ||
|
|
f15f5708bf | ||
|
|
4d2355bc57 | ||
|
|
5ffadd2283 | ||
|
|
30c2490f88 | ||
|
|
be511c9ac2 | ||
|
|
be8837963a | ||
|
|
09a332aff3 | ||
|
|
f3340c1152 | ||
|
|
62a9b05595 | ||
|
|
740bb46e6d | ||
|
|
d59a59dc83 | ||
|
|
2790446906 | ||
|
|
70a72545ce | ||
|
|
bdd702384f | ||
|
|
b5e77a0643 | ||
|
|
e55878fc2e | ||
|
|
e86f4eedcf | ||
|
|
13eeb9043a | ||
|
|
8c7ea8df98 | ||
|
|
870ec0efe8 | ||
|
|
5ccbbcc7d1 | ||
|
|
a07052ff86 | ||
|
|
08f27e0134 | ||
|
|
e03e17bc12 | ||
|
|
d83af30195 | ||
|
|
723db1cd7a | ||
|
|
3aea29fb2b | ||
|
|
598cbeb3be | ||
|
|
e7370945c9 | ||
|
|
cdcfdf4605 | ||
|
|
bef5e4479e | ||
|
|
48f7132ba8 | ||
|
|
8be7c0dbae | ||
|
|
7b0165696e | ||
|
|
de120aefb4 | ||
|
|
1c4a83e1ad | ||
|
|
ec8e257fde | ||
|
|
907bdd4d46 | ||
|
|
a3e8a2d18d | ||
|
|
ff7410ce2a | ||
|
|
73ca6a1316 | ||
|
|
ebee8e9b43 | ||
|
|
a2a3f5a393 | ||
|
|
b2aabdc02b | ||
|
|
a6167f64f1 | ||
|
|
f139a04374 | ||
|
|
40643ce554 | ||
|
|
87735b5215 | ||
|
|
5554668d37 | ||
|
|
68921fe94d | ||
|
|
bc4bd773a0 | ||
|
|
a4c16e1b53 | ||
|
|
091007ddf7 | ||
|
|
8c907a4cc2 | ||
|
|
c4b3ad58e8 | ||
|
|
886c8d649c | ||
|
|
b0ca35279f | ||
|
|
cb509c1b70 | ||
|
|
4687ae7f30 | ||
|
|
ba41611d64 | ||
|
|
8e254e8cd7 | ||
|
|
0d7c3e1b0a | ||
|
|
7364f77c0c | ||
|
|
0a8678a8ae | ||
|
|
679d4aa801 | ||
|
|
45dc17f41f | ||
|
|
0ac8118c46 | ||
|
|
d0489758ad | ||
|
|
eb640b09e6 | ||
|
|
e14a658672 | ||
|
|
c2924402ad | ||
|
|
ea6b240541 | ||
|
|
0548b62441 | ||
|
|
ea6f0d8bef | ||
|
|
9936538d8b | ||
|
|
6726e5f139 | ||
|
|
e042e11c23 | ||
|
|
f35206660b | ||
|
|
58faf9462e | ||
|
|
999980c07c | ||
|
|
433ab37eb8 | ||
|
|
4cdd515f5b | ||
|
|
ba200c30af | ||
|
|
024ecb301e | ||
|
|
8710982d2a | ||
|
|
edbac49f2b | ||
|
|
54ffdf8ae5 | ||
|
|
9d25710300 | ||
|
|
fad824ef5a | ||
|
|
e6f3126ba6 | ||
|
|
58f77012dd | ||
|
|
de69739774 | ||
|
|
0d43017704 | ||
|
|
3dcfe1846c | ||
|
|
608e398386 | ||
|
|
b06fbd78cc | ||
|
|
385a18563c | ||
|
|
cb5f66ffe0 | ||
|
|
bd54cb1b88 | ||
|
|
5e4622b229 | ||
|
|
5dbb8c3041 | ||
|
|
1b2e59756e | ||
|
|
4bdb8a5d34 | ||
|
|
b69046f98d | ||
|
|
932407f153 | ||
|
|
c1272bc69d | ||
|
|
ff571967cf | ||
|
|
5894624e2e | ||
|
|
167128b1f2 | ||
|
|
29cdb37af3 | ||
|
|
f147d9ec4a | ||
|
|
90822de962 | ||
|
|
ae4fc5a25e | ||
|
|
b59da89e80 | ||
|
|
a5c1fdac58 | ||
|
|
e5e455e0e5 | ||
|
|
4e5454912f | ||
|
|
173e17d992 | ||
|
|
5fcb18ea60 | ||
|
|
1ff16f248b | ||
|
|
c7f06b9af6 | ||
|
|
e235cadda4 | ||
|
|
439b783a72 | ||
|
|
043b9a52d6 | ||
|
|
7fb51e94bb | ||
|
|
c36fce8b6a | ||
|
|
c6b943bfe9 | ||
|
|
66aae01493 | ||
|
|
e73f7e9f84 | ||
|
|
9eda0f79bd | ||
|
|
a3206dbe9e | ||
|
|
7fa0d3063d | ||
|
|
d4b41bd11d | ||
|
|
f92c800216 | ||
|
|
62ab60d0b1 | ||
|
|
c3e9d0e96e | ||
|
|
9a62b5ec62 | ||
|
|
bfa8851af0 | ||
|
|
c46ca5d5d1 | ||
|
|
12c43b7d4d | ||
|
|
fc45d8d791 | ||
|
|
14d548fc44 | ||
|
|
e045515b91 | ||
|
|
37f6190c69 | ||
|
|
ab035795bc | ||
|
|
33c60a78cd | ||
|
|
49bf80ec39 | ||
|
|
9cbf5c0cbe | ||
|
|
c6856dec44 | ||
|
|
14cf5f014c | ||
|
|
5aeca4826c | ||
|
|
fa77c3d66a | ||
|
|
b9e2825da6 | ||
|
|
14f11f8561 | ||
|
|
61dc53a7e0 | ||
|
|
bfaa5f9d5c | ||
|
|
71d437df62 | ||
|
|
3c5d819736 | ||
|
|
a76bca9b0d | ||
|
|
372e8c07cf | ||
|
|
964f7d96d6 | ||
|
|
2cb89ce528 | ||
|
|
3f26f9af5b | ||
|
|
547f8d2e83 | ||
|
|
2692586abe | ||
|
|
a2d585084e | ||
|
|
4f6467ce08 | ||
|
|
7cafcf6c24 | ||
|
|
d0e9c52410 | ||
|
|
168d713df8 | ||
|
|
9ed4e77049 | ||
|
|
92e9f3b313 | ||
|
|
6f5d8eae96 | ||
|
|
11bdb437d2 | ||
|
|
ccef2a6f13 | ||
|
|
44351aaf31 | ||
|
|
4a63695ae2 | ||
|
|
205792e9d4 | ||
|
|
60ae7aa667 | ||
|
|
a13e31a76b | ||
|
|
824edb8823 | ||
|
|
a7a71da6df | ||
|
|
1bbfdf96a0 | ||
|
|
e721727476 | ||
|
|
4e4080c523 | ||
|
|
986733e8fb | ||
|
|
8a6d96b289 | ||
|
|
45c42dfe9a | ||
|
|
07f4163300 | ||
|
|
3e364bb8a4 | ||
|
|
519dcdbcb3 | ||
|
|
20662c2a43 | ||
|
|
80edafbe50 | ||
|
|
03f87057c2 | ||
|
|
d68d2debf9 | ||
|
|
ed907b4094 | ||
|
|
c977e0aa25 | ||
|
|
400a11d4c9 | ||
|
|
3f4406dd6b | ||
|
|
557f1cc956 | ||
|
|
fdb5759610 | ||
|
|
21ad904abc | ||
|
|
5737534302 | ||
|
|
de44644700 | ||
|
|
d0b291e509 | ||
|
|
8017fa948d | ||
|
|
5a818e9331 | ||
|
|
08439bdcf1 | ||
|
|
7ec9ea92aa | ||
|
|
f3bc2ece86 | ||
|
|
64ce845bae | ||
|
|
5f5b300ba5 | ||
|
|
8ba6a4d19d | ||
|
|
06899aa826 | ||
|
|
0285bbcec4 | ||
|
|
d5bfec3a8b | ||
|
|
2a3d7d0319 | ||
|
|
7b59b34a73 | ||
|
|
9e51e767d4 | ||
|
|
e6a4fe3fc4 | ||
|
|
bf6f16e383 | ||
|
|
5f639b9a3b | ||
|
|
357f3a3da2 | ||
|
|
bc2bc7a330 | ||
|
|
90672e5491 | ||
|
|
5f3a3e4582 | ||
|
|
c8da208a91 | ||
|
|
b642d2247d | ||
|
|
0288bf1f68 | ||
|
|
a7b18515a1 | ||
|
|
a441596b07 | ||
|
|
56a276d92e | ||
|
|
ffdf8babbf | ||
|
|
efbce9a375 | ||
|
|
688dee2dca | ||
|
|
d9855ae346 | ||
|
|
abc73d9d98 | ||
|
|
0a6294a2a3 | ||
|
|
67a67846aa | ||
|
|
b01ddbb29c | ||
|
|
86f8743b1b | ||
|
|
763244dad5 | ||
|
|
5466ffd614 | ||
|
|
6686f1c9bd | ||
|
|
6233f5a409 | ||
|
|
370640e008 | ||
|
|
13b36a5c34 | ||
|
|
4fcdaa91e9 | ||
|
|
13cd0a4cb3 | ||
|
|
ec50e18a3e | ||
|
|
c3c3037a1d | ||
|
|
54a9132aea | ||
|
|
9b574361c9 | ||
|
|
004adfa5cc | ||
|
|
61f05672e6 | ||
|
|
08a5ea6fdf | ||
|
|
d2a221c899 | ||
|
|
733ab8ae6c | ||
|
|
bebb94c15b | ||
|
|
656b5150ff | ||
|
|
2c434ebac1 | ||
|
|
a7fb6b5eae | ||
|
|
476f2980ce | ||
|
|
2f7479374b | ||
|
|
e11d8aedff | ||
|
|
d7caaded3f | ||
|
|
149ca493e0 | ||
|
|
4ac094966e | ||
|
|
1197e09626 | ||
|
|
e5be4b7e40 | ||
|
|
d1b238638c | ||
|
|
71995d5e1b | ||
|
|
9847394e12 | ||
|
|
696caac9b0 | ||
|
|
88b5a27ddf | ||
|
|
9eb5ad77ef | ||
|
|
a71465217b | ||
|
|
be040715f9 | ||
|
|
8cc0da67e1 | ||
|
|
369bb476e9 | ||
|
|
c73dba7a7a | ||
|
|
fcc74be267 | ||
|
|
a0b29d980f | ||
|
|
30c8825fa2 | ||
|
|
02f984f7ef | ||
|
|
d879218c27 | ||
|
|
92c085c28e | ||
|
|
98c8db568b | ||
|
|
b4c5d7cf62 | ||
|
|
b35947f7a6 | ||
|
|
f66c16bd52 | ||
|
|
733e41a6a7 | ||
|
|
f79c844855 | ||
|
|
e8043594f7 | ||
|
|
b0ff693839 | ||
|
|
802c9d1111 | ||
|
|
00c7451200 | ||
|
|
a5772bf3d6 | ||
|
|
694f318614 | ||
|
|
9f66333d77 | ||
|
|
625afa0621 | ||
|
|
f92c0cb69d | ||
|
|
a07b56c02b | ||
|
|
be2a3f4030 | ||
|
|
822c63cbd7 | ||
|
|
89fd11d582 | ||
|
|
21e8087822 | ||
|
|
e4dd5c1c00 | ||
|
|
f604cc4df8 | ||
|
|
8bb86d3e5d | ||
|
|
6236e8f66b | ||
|
|
bb2cfffe6a | ||
|
|
f86e1128f0 | ||
|
|
070fa1ff9d | ||
|
|
fc13ae8e76 | ||
|
|
92b9ccb08a | ||
|
|
dfab8ed5b9 | ||
|
|
3a25f82c4f | ||
|
|
debd6fb3b4 | ||
|
|
a0049f9fcd | ||
|
|
e14623b46c | ||
|
|
5f47523dd3 | ||
|
|
49f481e399 | ||
|
|
891a66ad8b | ||
|
|
f9e7c86a1a | ||
|
|
81cb774a8e | ||
|
|
523ac9f64c | ||
|
|
a0504aeabe | ||
|
|
a6dd3178b1 | ||
|
|
b5b35c9fc8 | ||
|
|
c74abe579b | ||
|
|
f653118658 | ||
|
|
d913761c46 | ||
|
|
5df258c5f0 | ||
|
|
088c810b00 | ||
|
|
c731edcdeb | ||
|
|
a86fdfc779 | ||
|
|
6380cd428a | ||
|
|
8fe68aa035 | ||
|
|
3342d3b9b9 | ||
|
|
c749671778 | ||
|
|
2bdbbc3faf | ||
|
|
7056622322 | ||
|
|
447e627286 | ||
|
|
03c39076e5 | ||
|
|
ce0723cf48 | ||
|
|
07ccf477d0 | ||
|
|
080c884c1a | ||
|
|
4d6ddd0af3 | ||
|
|
fa82e19c1f | ||
|
|
d9fbb540c5 | ||
|
|
103ae436c9 | ||
|
|
4de668159d | ||
|
|
0fbf96b4be | ||
|
|
a6f328516a | ||
|
|
1c44f49d1b | ||
|
|
5fd6eac477 | ||
|
|
801bc755b5 | ||
|
|
816e8d88e0 | ||
|
|
09ddd92efc | ||
|
|
587184c778 | ||
|
|
c022f4d483 | ||
|
|
6adfec2bd5 | ||
|
|
aee59f42ef | ||
|
|
3e454045e9 | ||
|
|
429991c3f9 | ||
|
|
a9cdf3c5a1 | ||
|
|
6d11f6d063 | ||
|
|
4aeb65512d | ||
|
|
e006cf04bb | ||
|
|
f413a8da79 | ||
|
|
67af48eed4 | ||
|
|
00d1ea6157 | ||
|
|
09c893f3a3 | ||
|
|
7ff0d0e686 | ||
|
|
fb562ec7d3 | ||
|
|
67c576add6 | ||
|
|
5523240553 | ||
|
|
43b1555e5d | ||
|
|
6d745f32c0 | ||
|
|
ec42fa837f | ||
|
|
8336df2b9b | ||
|
|
c787e02dcc | ||
|
|
f49336f087 | ||
|
|
960c35596c | ||
|
|
e56d2b14c8 | ||
|
|
1b81f8b830 | ||
|
|
cf95b02bc0 | ||
|
|
13f444260c | ||
|
|
8a72b11e3d | ||
|
|
578f9ea21e | ||
|
|
b6db45420c | ||
|
|
fd18f2efa9 | ||
|
|
a79904c075 | ||
|
|
93905e828d | ||
|
|
537e9df3ed | ||
|
|
5593670759 | ||
|
|
c7d87feec3 | ||
|
|
593acfc37a | ||
|
|
721a422e5e | ||
|
|
7088135f5e | ||
|
|
4c15ec9f86 | ||
|
|
4cfb0cd24e | ||
|
|
df66579fc2 | ||
|
|
d6ec9b2028 | ||
|
|
dfa69fd383 | ||
|
|
1b20319074 | ||
|
|
b66a37ccb1 | ||
|
|
5f51cffe08 | ||
|
|
d0f5875f66 | ||
|
|
e84d2ba594 | ||
|
|
1b23a4a8e1 | ||
|
|
528747684d | ||
|
|
121bc0ad5e | ||
|
|
9fdd378687 | ||
|
|
41d3a1e8dd | ||
|
|
705ab7b0f8 | ||
|
|
4afc32c425 | ||
|
|
868ef2079c | ||
|
|
e2c3701757 | ||
|
|
bfc963a065 | ||
|
|
ac85e9c819 | ||
|
|
3734c48489 | ||
|
|
54eee3f28a | ||
|
|
e0e1b3eecf | ||
|
|
083a8cc172 | ||
|
|
a91f1cab5d | ||
|
|
7127676f71 | ||
|
|
84c708b74b | ||
|
|
4349a5e815 | ||
|
|
92d8208309 | ||
|
|
4234bfc1c2 | ||
|
|
c0ed9e1cff | ||
|
|
47c972e21a | ||
|
|
318518ee1f | ||
|
|
f7a2f8ea47 | ||
|
|
a282499055 | ||
|
|
ae8cf9defd | ||
|
|
0ebba1c4ab | ||
|
|
dd299d272b | ||
|
|
b349bdd80f | ||
|
|
324c7c3674 | ||
|
|
b6cc6bd2d4 | ||
|
|
93c04cd79f | ||
|
|
d38b32abfd | ||
|
|
0856b72c3c | ||
|
|
a11726783e | ||
|
|
4f1e3293ff | ||
|
|
ba99bc5528 | ||
|
|
25e9cccbdf | ||
|
|
ddcb4ec72f | ||
|
|
bc0f7ae4f6 | ||
|
|
94877e033b | ||
|
|
4029f2ec82 | ||
|
|
136e2e46d8 | ||
|
|
178d63b154 | ||
|
|
22f3c40385 | ||
|
|
41b93f3dcc | ||
|
|
51c08601dc | ||
|
|
299277b140 | ||
|
|
34218ee132 | ||
|
|
17dc36aad6 | ||
|
|
cce962f3f0 | ||
|
|
9add2151c3 | ||
|
|
7892c33ec9 | ||
|
|
ee36f53cb2 | ||
|
|
ffc8ec7a5b | ||
|
|
d718bc2eba | ||
|
|
da1efcd847 | ||
|
|
7d1c362635 | ||
|
|
61fe02f411 | ||
|
|
cd85151f97 | ||
|
|
c08ab18bff | ||
|
|
f7a28dc661 | ||
|
|
c659695c5d | ||
|
|
9dcf4e5438 | ||
|
|
007cd9b8fd | ||
|
|
ac67587b79 | ||
|
|
3a6196ccd1 | ||
|
|
7ffa9e21d8 | ||
|
|
31afafda0f | ||
|
|
914653f140 | ||
|
|
d0e5c3c151 | ||
|
|
0073c64e21 | ||
|
|
966065767a | ||
|
|
5e45aaab78 | ||
|
|
519d664a40 | ||
|
|
b9c0f07f57 | ||
|
|
48625964f1 | ||
|
|
c7fa7b6467 | ||
|
|
848fdedec7 | ||
|
|
cf40006b58 | ||
|
|
1d14b19f15 | ||
|
|
38dac13ee3 | ||
|
|
3606debb15 | ||
|
|
b1f65f6c9f | ||
|
|
5e895317f6 | ||
|
|
e0674aad87 | ||
|
|
ee46becaf9 | ||
|
|
d9d58b0510 | ||
|
|
c53a06a5d5 | ||
|
|
01293dedaa | ||
|
|
1580f7fea7 | ||
|
|
15875b8bd1 | ||
|
|
52ce7983e4 | ||
|
|
0bb323f63c | ||
|
|
1beff31bd8 | ||
|
|
45c836fdf5 | ||
|
|
226aa2d8f3 | ||
|
|
74e9c12695 | ||
|
|
55783fc3a1 | ||
|
|
a7dd21ffaf | ||
|
|
4f5253bcb3 | ||
|
|
6afc9f7902 | ||
|
|
cf3697199a | ||
|
|
7828614459 | ||
|
|
32429d3091 | ||
|
|
ea97e9a9a8 | ||
|
|
8473a72ee5 | ||
|
|
fc8696bf20 | ||
|
|
36e86a5854 | ||
|
|
a9d370f7be | ||
|
|
e096fb66fb | ||
|
|
b1099477f9 | ||
|
|
6466bb4384 | ||
|
|
0a1a868b37 | ||
|
|
56e2c67f7f | ||
|
|
b8279e1c9c | ||
|
|
81d6d85461 | ||
|
|
3af7e2251d | ||
|
|
728d6076e5 | ||
|
|
161f60e569 | ||
|
|
20daa28452 | ||
|
|
3054e71f5b | ||
|
|
389bf3298c | ||
|
|
1da88a647a | ||
|
|
8b44fa6a2d | ||
|
|
0c2625e59d | ||
|
|
ff3c12fd71 | ||
|
|
75312305b9 | ||
|
|
1ca2a77c05 | ||
|
|
2c85fb0d19 | ||
|
|
41fdfa63b1 | ||
|
|
77a538e588 | ||
|
|
566530ca18 | ||
|
|
c462237b9d | ||
|
|
dcb50a20b2 | ||
|
|
6100773c24 | ||
|
|
8dcc503bc0 | ||
|
|
229b0e4dcc | ||
|
|
c02926e2ad | ||
|
|
39db9ddcfd | ||
|
|
fc749755df | ||
|
|
dfd3fca92b | ||
|
|
b911972716 | ||
|
|
c1b0e83a44 | ||
|
|
680e04b4a1 | ||
|
|
88555de28c | ||
|
|
663d1e7347 | ||
|
|
ffe4bf0b71 | ||
|
|
644fd4ed5f | ||
|
|
9c9963b608 | ||
|
|
fb8a069d4a | ||
|
|
0ec0cf9d0e | ||
|
|
bba3caa697 | ||
|
|
000210d875 | ||
|
|
2873a09fd0 | ||
|
|
79745f77c0 | ||
|
|
472063e98c | ||
|
|
d1d737777c | ||
|
|
9435b381ed | ||
|
|
63f37eeeda | ||
|
|
831e1d04b9 | ||
|
|
95af2e46ec | ||
|
|
a37ba369ef | ||
|
|
86da6d1f2e | ||
|
|
62f190d574 | ||
|
|
e9a0717aea | ||
|
|
8ecebc9310 | ||
|
|
be5b5e880d | ||
|
|
b1866c8f92 | ||
|
|
ef3cad5421 | ||
|
|
e4df1da252 | ||
|
|
7b5b99b04b | ||
|
|
3aca0d8061 | ||
|
|
892761f732 | ||
|
|
515847fdd2 | ||
|
|
ec14df9fbb | ||
|
|
10f75524fc | ||
|
|
cadcfa43c3 | ||
|
|
440a68636b | ||
|
|
532001c851 | ||
|
|
3bf377fd5f | ||
|
|
68cf8d5c3d | ||
|
|
237dedfae0 | ||
|
|
e18a63e992 | ||
|
|
1eaaf4d8d8 | ||
|
|
c0e3926b0d | ||
|
|
a3e24949af | ||
|
|
8f7a3044ec | ||
|
|
0c02536605 | ||
|
|
beb4dccc8c | ||
|
|
b72692baaf | ||
|
|
7732482738 | ||
|
|
aeb6a4842f | ||
|
|
7ee6fdd9e6 | ||
|
|
24d5a6053e | ||
|
|
7cb18a088e | ||
|
|
baeec62e07 | ||
|
|
9df639b403 | ||
|
|
f4eea743db | ||
|
|
0e4d493d93 | ||
|
|
f3280071c1 | ||
|
|
cf71ed75a4 | ||
|
|
22c88e4de3 | ||
|
|
d5f1747993 | ||
|
|
0494cd1406 | ||
|
|
5cb009d782 | ||
|
|
1c5f9e6103 | ||
|
|
b0d860b7e0 | ||
|
|
172555bbce | ||
|
|
98f74a9094 | ||
|
|
6075024469 | ||
|
|
20d5c1ab13 | ||
|
|
46c19e3cb0 | ||
|
|
8007c20c79 | ||
|
|
db79abdc13 | ||
|
|
1ba712bea9 | ||
|
|
65948c8137 | ||
|
|
50b02340d0 | ||
|
|
bfd3f37bf4 | ||
|
|
d48dd63755 | ||
|
|
597dba1391 | ||
|
|
625c1d167d | ||
|
|
fe91caf325 | ||
|
|
809ba7f04e | ||
|
|
73351e1eab | ||
|
|
3277a219fd | ||
|
|
d6f358182a | ||
|
|
a84d0bf5c5 | ||
|
|
da5db5aac9 | ||
|
|
636fd6cc38 | ||
|
|
4a9d2e86cf | ||
|
|
e626f771c4 | ||
|
|
5f958ae84d | ||
|
|
be2f04f082 | ||
|
|
18183632dc | ||
|
|
6f40e452e1 | ||
|
|
18019efd38 | ||
|
|
63cff4c9a0 | ||
|
|
1e8b05984a | ||
|
|
6393df3bfe | ||
|
|
79e480a894 | ||
|
|
d9817f9a96 | ||
|
|
f4ab1b2cd0 | ||
|
|
ec23c94645 | ||
|
|
1e7c939953 | ||
|
|
e92937eea0 | ||
|
|
e196fb95e1 | ||
|
|
76a176f647 | ||
|
|
0fdd2654f0 | ||
|
|
3c5f6e1887 | ||
|
|
70ed05625f | ||
|
|
9ef8df9a19 | ||
|
|
2b933faaf2 | ||
|
|
d2a28350ff | ||
|
|
d9b5ee10de | ||
|
|
875734f963 | ||
|
|
53a1c21a98 | ||
|
|
a0812eeb17 | ||
|
|
4ce5adb2a0 | ||
|
|
d726e5e81c | ||
|
|
4d23ffc112 | ||
|
|
ddc0aa0e82 | ||
|
|
4ec6cefe1d | ||
|
|
a86d5fda71 | ||
|
|
c87cf2d2cf | ||
|
|
3c30425276 | ||
|
|
a0d2d34466 | ||
|
|
842817f110 | ||
|
|
4acbbb8d0f | ||
|
|
10e668a87c | ||
|
|
38ffcfd4c4 | ||
|
|
a1f27d9189 | ||
|
|
dff5b3589b | ||
|
|
dc21efbe10 | ||
|
|
4c060030ae | ||
|
|
18b4d65c4e | ||
|
|
764a2cfa51 | ||
|
|
d8b85580dc | ||
|
|
72421d4438 | ||
|
|
6521af5a13 | ||
|
|
886a1d94b9 | ||
|
|
2b47429c4a | ||
|
|
fe9388a7a4 | ||
|
|
236dbb2842 | ||
|
|
4427424db3 | ||
|
|
cb3c40256a | ||
|
|
7abb2a7a7c | ||
|
|
3a2df479da | ||
|
|
775b236c93 | ||
|
|
36be150f20 | ||
|
|
b44ea53741 | ||
|
|
c07821e8a2 | ||
|
|
2b062ce384 | ||
|
|
ea0a964365 | ||
|
|
d589450200 | ||
|
|
cf696939f8 | ||
|
|
76f86fb3ca | ||
|
|
8a53ee1ad3 | ||
|
|
dff20f250b | ||
|
|
9ad93d36a0 | ||
|
|
c2993c4d4e | ||
|
|
de251bc999 | ||
|
|
a0e46c9106 | ||
|
|
b2ff07d58c | ||
|
|
707536725d | ||
|
|
387e5c1ab9 | ||
|
|
847a6fe3ce | ||
|
|
036728a194 | ||
|
|
c0578eb9ab | ||
|
|
56800a1d43 | ||
|
|
caa4442abb | ||
|
|
c608d39aa4 | ||
|
|
7b6a97dee0 | ||
|
|
0f21583625 | ||
|
|
e89b32511d | ||
|
|
083f302b19 | ||
|
|
c461c6435d | ||
|
|
f7fcbe7dc9 | ||
|
|
f822e83489 | ||
|
|
d3ada540bf | ||
|
|
0373c15e43 | ||
|
|
cc1988fbda | ||
|
|
d1dfcdafc2 | ||
|
|
44cadf7c1f | ||
|
|
ddb345897e | ||
|
|
d93530a6ea | ||
|
|
70fd137ced | ||
|
|
8c375f016f | ||
|
|
336d6fd407 | ||
|
|
1d5228388b | ||
|
|
d9dba38644 | ||
|
|
1c708a70ba | ||
|
|
c6f1d0aada | ||
|
|
c6d1de14f3 | ||
|
|
876c7f5093 | ||
|
|
9fb5969c59 | ||
|
|
191b1cdb0f | ||
|
|
98c8041df2 | ||
|
|
7682f657a4 | ||
|
|
4ed8c6a09c | ||
|
|
7c48937ea2 | ||
|
|
68d5ed57e3 | ||
|
|
298c15bdda | ||
|
|
6a0937a9e8 | ||
|
|
ed8b8bc27e | ||
|
|
cbe47d4416 | ||
|
|
4d5b1ae741 | ||
|
|
e3919a1b82 | ||
|
|
74bf31b0e9 | ||
|
|
f94cbc9f98 | ||
|
|
219280d203 | ||
|
|
ae1424a8dd | ||
|
|
3dd63a012e | ||
|
|
46daadc137 | ||
|
|
7192f74554 | ||
|
|
ef77847762 | ||
|
|
5ffdee42e2 | ||
|
|
849244f61e | ||
|
|
40dc019b30 | ||
|
|
a16c19545f | ||
|
|
2c1c05923d | ||
|
|
ba8ed9fb18 | ||
|
|
fed8e8b331 | ||
|
|
0444513e90 | ||
|
|
e82c6512b4 | ||
|
|
a8983b420f | ||
|
|
b7e6d3d98d | ||
|
|
ebfdabf2d7 | ||
|
|
e6448567a0 | ||
|
|
d7f28d4328 | ||
|
|
263ba2b0fa | ||
|
|
d4125ca735 | ||
|
|
ec707930ce | ||
|
|
252d00834f | ||
|
|
1779b66f10 | ||
|
|
a42446268d | ||
|
|
419a2159e6 | ||
|
|
df7b2c968e | ||
|
|
f12a297466 | ||
|
|
a6788f83c2 | ||
|
|
e9996b5cc6 | ||
|
|
4a0d4461e1 | ||
|
|
acf9b0597d | ||
|
|
d97fc8f666 | ||
|
|
7c53cc8955 | ||
|
|
8a842c0de7 | ||
|
|
0fe1453c50 | ||
|
|
4370b51f02 | ||
|
|
3f9c87099d | ||
|
|
718f8989f8 | ||
|
|
8946332913 | ||
|
|
1d6289245a | ||
|
|
a60fa59514 | ||
|
|
29fed3cc85 | ||
|
|
06ba9acdb8 | ||
|
|
0d5a1f9cf3 | ||
|
|
3c987d20b1 | ||
|
|
ec610537be | ||
|
|
faecba6035 | ||
|
|
feb1dcc773 | ||
|
|
5ab1933be7 | ||
|
|
e4f011a697 | ||
|
|
19cfe00397 | ||
|
|
c7de5e6bff | ||
|
|
cc46ac5d4c | ||
|
|
17626b5474 | ||
|
|
0924a9dd73 | ||
|
|
f558389006 | ||
|
|
2b93d6d855 | ||
|
|
1d3e38c5dd | ||
|
|
d4e981f916 | ||
|
|
b73d984ec9 | ||
|
|
58d98e918f | ||
|
|
79e7ccce29 | ||
|
|
1efda9eb74 | ||
|
|
a72567fa36 | ||
|
|
898ac3808f | ||
|
|
004ff4e7b6 | ||
|
|
5710dc771d | ||
|
|
5cad4c46f0 | ||
|
|
36a5344282 | ||
|
|
cc30695b72 | ||
|
|
f3188587ce | ||
|
|
602990b80e | ||
|
|
f53d902265 | ||
|
|
9dcf612f9d | ||
|
|
55d7cf438b | ||
|
|
6116236ed9 | ||
|
|
9491bb40d4 | ||
|
|
6577efc8f4 | ||
|
|
800a5a6d4a | ||
|
|
a0d5596605 | ||
|
|
4793cdfab3 | ||
|
|
e29b54e5e0 | ||
|
|
e694cdc2b3 | ||
|
|
597233c49b | ||
|
|
51d0e83a21 | ||
|
|
4c4c2a9604 | ||
|
|
7b5b99aafa | ||
|
|
ac8f3fc653 | ||
|
|
644af826ee | ||
|
|
ddf57ca295 | ||
|
|
50f2cd295f | ||
|
|
a9f798eae1 | ||
|
|
23c05ad7db | ||
|
|
6888a04636 | ||
|
|
5e6945d380 | ||
|
|
424cfe1b1e | ||
|
|
c8323af63d | ||
|
|
d4e632dfa8 | ||
|
|
75febf4bfd | ||
|
|
1b978bac6d | ||
|
|
28a1e0f432 | ||
|
|
ae97cbfb72 | ||
|
|
405cc66637 | ||
|
|
7b657032ae | ||
|
|
b9973bcf8a | ||
|
|
b509fe70cd | ||
|
|
cfebb37c64 | ||
|
|
03fdefb158 | ||
|
|
912ffe4a91 | ||
|
|
c430ab57ba | ||
|
|
c4c49678f9 | ||
|
|
7fcaca85dd | ||
|
|
f903aaa1a4 | ||
|
|
7f36e0ed20 | ||
|
|
877d454c8f | ||
|
|
e5f58c9594 | ||
|
|
b845db30de | ||
|
|
c234005f1c | ||
|
|
e999e0f6be | ||
|
|
2db2b671f2 | ||
|
|
f492f2d14d | ||
|
|
9f03a407cb | ||
|
|
6880f3d1e9 | ||
|
|
fe9af76e22 | ||
|
|
be01e9f3a1 | ||
|
|
373ccdebf2 | ||
|
|
ebe5c0b2bf | ||
|
|
2d55eacc57 | ||
|
|
68b4b8f2f2 | ||
|
|
af2b588ea6 | ||
|
|
3e288b9a0f | ||
|
|
3cabdb2dbf | ||
|
|
d20ea30add | ||
|
|
d3fc327bc9 | ||
|
|
520d9b73c0 | ||
|
|
0993458a57 | ||
|
|
56b8a88b1f | ||
|
|
34310a61f5 | ||
|
|
abadedffec | ||
|
|
64e12b1809 | ||
|
|
2f1f6b5b43 | ||
|
|
5ac3fdec50 | ||
|
|
ed58799f13 | ||
|
|
c71ad2babc | ||
|
|
4df6179954 | ||
|
|
5aa12b2319 | ||
|
|
9df2e79fb9 | ||
|
|
cffb44891a | ||
|
|
4efca13c33 | ||
|
|
fc584969c9 | ||
|
|
0d9298313f | ||
|
|
bd767a5273 | ||
|
|
65b93dbfd4 | ||
|
|
0ed6cf7743 | ||
|
|
dbc4d4786b | ||
|
|
38b5b94617 | ||
|
|
6e467172e5 | ||
|
|
1623394da8 | ||
|
|
352a67d162 | ||
|
|
bc7c8c14f4 | ||
|
|
97d8d0daa6 | ||
|
|
9009ed7e43 | ||
|
|
a201232843 | ||
|
|
50d4901f86 | ||
|
|
db3d588f64 | ||
|
|
8510a07a9e | ||
|
|
7cd4d28bb2 | ||
|
|
0922efa371 | ||
|
|
67f7fcba26 | ||
|
|
229ebbbcbf | ||
|
|
4fe67b8947 | ||
|
|
ff5921a469 | ||
|
|
7fcfea647f | ||
|
|
9c4b40fd35 | ||
|
|
cf7359a915 | ||
|
|
a9f5fdc47b | ||
|
|
8819d02600 | ||
|
|
cbc609c8f0 | ||
|
|
4819a83003 | ||
|
|
8b846b9fe2 | ||
|
|
3dcedb60d8 | ||
|
|
e38e3e14e6 | ||
|
|
c75ab513da | ||
|
|
8b8b9f59a1 | ||
|
|
ad36beed1f | ||
|
|
d57cd81ca6 | ||
|
|
4e4af9d011 | ||
|
|
173133dbf3 | ||
|
|
26078ecc17 | ||
|
|
df8b71f811 | ||
|
|
74c2449d8f | ||
|
|
4714276e2c | ||
|
|
5890ae7bcd | ||
|
|
a3e6988d87 | ||
|
|
b8377f50c9 | ||
|
|
2ff3db8f51 | ||
|
|
99852ebda8 | ||
|
|
db91c70ce9 | ||
|
|
8cd0939bfe | ||
|
|
d5c251042f | ||
|
|
61d5ba1776 | ||
|
|
020c1400e2 | ||
|
|
7f8f6e8a7e | ||
|
|
10fc8a733d | ||
|
|
d01606e86d | ||
|
|
ec31832c5c | ||
|
|
4bac1ee745 | ||
|
|
39bdbcfd86 | ||
|
|
4f95b9f05c | ||
|
|
c441855522 | ||
|
|
ff2426c4ad | ||
|
|
2f79d5f052 | ||
|
|
d7f0b1637e | ||
|
|
fec605b577 | ||
|
|
c4f96b108f | ||
|
|
e097175a77 | ||
|
|
71a5ba3283 | ||
|
|
0951831c64 | ||
|
|
f08aad6b14 | ||
|
|
acad3e864d | ||
|
|
89a481f8e7 | ||
|
|
a4ce10d88e | ||
|
|
e95b26bf20 | ||
|
|
9cc7efbe12 | ||
|
|
991a49084a | ||
|
|
c05b743fa6 | ||
|
|
08b40c7967 | ||
|
|
3cb18303f6 | ||
|
|
2827a6df47 | ||
|
|
d42b6d9ad7 | ||
|
|
912b1dbc1a | ||
|
|
48b318d29e | ||
|
|
32355f5463 | ||
|
|
c393b011c4 | ||
|
|
3c983d62c9 | ||
|
|
78091bfa80 | ||
|
|
cfd050b0f2 | ||
|
|
6a4f4a55b4 | ||
|
|
189da25c5b | ||
|
|
d43bd1dcb8 | ||
|
|
fbf89687cc | ||
|
|
d6be2fb44c | ||
|
|
f076f64404 | ||
|
|
aef7418bdf | ||
|
|
0ca9997e10 | ||
|
|
1c219d14bb | ||
|
|
1ec2779f5e | ||
|
|
3bdc769134 | ||
|
|
1194764ed1 | ||
|
|
012caed1dc | ||
|
|
1c2f631723 | ||
|
|
38668785e4 | ||
|
|
8499ce3340 | ||
|
|
fd1fbca520 | ||
|
|
a7ea166fd2 | ||
|
|
0cf820f07b | ||
|
|
5e26062fd0 | ||
|
|
174f1b50c8 | ||
|
|
542b8b8705 | ||
|
|
8a442e726a | ||
|
|
6cde7fd27a | ||
|
|
df25dec30a | ||
|
|
0298d412dc | ||
|
|
7240460688 | ||
|
|
a7cea63db6 | ||
|
|
019382220a | ||
|
|
dd07ddb0b0 | ||
|
|
20af8fd378 | ||
|
|
2e0e893a9b | ||
|
|
4eb20c5d82 | ||
|
|
1405667692 | ||
|
|
8f7b08a01c | ||
|
|
7c78f232b4 | ||
|
|
8009324a3b | ||
|
|
1f32624e8b | ||
|
|
352d2047b4 | ||
|
|
8f8933d991 | ||
|
|
c2b8caed3f | ||
|
|
bfd0e63e3d | ||
|
|
8bf0a22eb0 | ||
|
|
c5816c9c5a | ||
|
|
9ba55c28b4 | ||
|
|
44cf2ad400 | ||
|
|
a39787c1a2 | ||
|
|
ff9c786149 | ||
|
|
f9ed01bb64 | ||
|
|
6754099730 | ||
|
|
2de789325f | ||
|
|
4861a15774 | ||
|
|
8997a08cd7 | ||
|
|
bde06c4011 | ||
|
|
ddac40e9cb | ||
|
|
917633628a | ||
|
|
6c5fe3b0cf | ||
|
|
f31d588839 | ||
|
|
e0308e3528 | ||
|
|
097a781e0e | ||
|
|
a4e620680c | ||
|
|
483bed74b8 | ||
|
|
9cced6be83 | ||
|
|
821fa5460b | ||
|
|
c699172fd6 | ||
|
|
90dab85e13 | ||
|
|
02b9b964b8 | ||
|
|
7a7fc781a0 | ||
|
|
3ccbe19c8a | ||
|
|
278d1105cf | ||
|
|
76ee6c2149 | ||
|
|
189d72e989 | ||
|
|
e78372f338 | ||
|
|
ab245726ed | ||
|
|
d1d82db4f7 | ||
|
|
67472298ca | ||
|
|
52fb81a441 | ||
|
|
bf314fde6b | ||
|
|
3e96908786 | ||
|
|
1ceb2745b1 | ||
|
|
6e73edd81f | ||
|
|
1f4bb6a2e4 | ||
|
|
3e8226da15 | ||
|
|
9543ce049f | ||
|
|
501e1b8524 | ||
|
|
6ca3fd423b | ||
|
|
b3b0af5a45 | ||
|
|
2be58aa51a | ||
|
|
522ac12dc9 | ||
|
|
c4fec61d08 | ||
|
|
256b92e5c4 | ||
|
|
651249a6c5 | ||
|
|
4a8b3ddb75 | ||
|
|
889cdd4dbd | ||
|
|
df4e88ff15 | ||
|
|
b0dcce01cb | ||
|
|
4de99619c3 | ||
|
|
b2919e9051 | ||
|
|
fb9a622ca7 | ||
|
|
92b232972e | ||
|
|
53f7811a89 | ||
|
|
dc22d2b131 | ||
|
|
082cc2a401 | ||
|
|
c63eb85070 | ||
|
|
499a67912f | ||
|
|
4144c8d76f | ||
|
|
aee3f661f4 | ||
|
|
c588342cfc | ||
|
|
2911a38f40 | ||
|
|
5b7cd45668 | ||
|
|
c522ce7fbc | ||
|
|
b735f5fa49 | ||
|
|
f248a81107 | ||
|
|
b9157df1a3 | ||
|
|
4da387127e | ||
|
|
3cf3657202 | ||
|
|
0b6896a0ab | ||
|
|
3192cf6e37 | ||
|
|
2d5dd70e85 | ||
|
|
ed954ee839 | ||
|
|
462e637e69 | ||
|
|
83d59d6b93 | ||
|
|
3bdb1eae0b | ||
|
|
1bd2af1064 | ||
|
|
713da771cb | ||
|
|
5bcc56fed8 | ||
|
|
8b36f90db9 | ||
|
|
5a993de400 | ||
|
|
358e92cf04 | ||
|
|
73d9ab4763 | ||
|
|
d877150df1 | ||
|
|
87c22dc7ac | ||
|
|
d33bd1cad1 | ||
|
|
948ef452ca | ||
|
|
48d7df72f1 | ||
|
|
575905ac53 | ||
|
|
3743617d27 | ||
|
|
c6c0ee76c2 | ||
|
|
a50e986f80 | ||
|
|
8f6da4fa7f | ||
|
|
de790b9e72 | ||
|
|
f337f5067b | ||
|
|
da84603558 | ||
|
|
67485be240 | ||
|
|
56749af1da | ||
|
|
fc3ca7ea0e | ||
|
|
28e13be3a4 | ||
|
|
5b4e148a2e | ||
|
|
100d94cd12 | ||
|
|
af93f76836 | ||
|
|
e7168c1d18 | ||
|
|
396db8411c | ||
|
|
eea6c7477d | ||
|
|
96b52a2283 | ||
|
|
720b8d3168 | ||
|
|
bee3140fc6 | ||
|
|
b2092fe0e7 | ||
|
|
f185c45c16 | ||
|
|
36b89b3e4b | ||
|
|
e5d4e90b8f | ||
|
|
26eecf082a | ||
|
|
32a6ecbcc5 | ||
|
|
66ca61dfbb | ||
|
|
acb65b77af | ||
|
|
4a6bf81b2e | ||
|
|
1edbe044a2 | ||
|
|
c73ae02170 | ||
|
|
0adb76d5d2 | ||
|
|
e9f1bb9853 | ||
|
|
7f1cad26ba | ||
|
|
a5f47cfae9 | ||
|
|
d6a2946aef | ||
|
|
4685e41173 | ||
|
|
ae4a3cb6da | ||
|
|
a32dc03616 | ||
|
|
7b7695509d | ||
|
|
e8cac3bfff | ||
|
|
319b553f69 | ||
|
|
a9bb789b14 | ||
|
|
69636a9da0 | ||
|
|
3b37b42633 | ||
|
|
79e675b911 | ||
|
|
cd277672d0 | ||
|
|
73ba522508 | ||
|
|
89a48ecb1d | ||
|
|
a13ae91f0b | ||
|
|
2609004719 | ||
|
|
068a3d2f1d | ||
|
|
b892f758a8 | ||
|
|
6611107e48 | ||
|
|
09d7847c7e | ||
|
|
52df0dc47a | ||
|
|
17e7fb4509 | ||
|
|
53b295b980 | ||
|
|
fc2843306f | ||
|
|
b9aa3d0bfd | ||
|
|
d77f657aa7 | ||
|
|
55bc684380 | ||
|
|
dc8b168fc1 | ||
|
|
3f844ee5d8 | ||
|
|
81722f65b8 | ||
|
|
bafa2154ff | ||
|
|
ffbf5016ac | ||
|
|
d7f85712db | ||
|
|
dd5aeb678a | ||
|
|
90c3b98413 | ||
|
|
34c41b43e5 | ||
|
|
86803b8ae4 | ||
|
|
77aac049fd | ||
|
|
3958cbcce3 | ||
|
|
53c19cc9a0 | ||
|
|
d19b0c975b | ||
|
|
dc6934be43 | ||
|
|
3cd84ab396 | ||
|
|
0e596a29d9 | ||
|
|
10869f7845 | ||
|
|
9d9355c597 | ||
|
|
d8da5ce590 | ||
|
|
0a26fcbd0d | ||
|
|
9dc9fc1d40 | ||
|
|
f05da13f47 | ||
|
|
53e25ce2cf | ||
|
|
a7d5a9a420 | ||
|
|
f2ea886ed2 | ||
|
|
a6dc53fe20 | ||
|
|
0183882cf7 | ||
|
|
3d6bf828fd | ||
|
|
6ac802bcf1 | ||
|
|
eee004cdb5 | ||
|
|
95b44ef8bf | ||
|
|
28c0644eb6 | ||
|
|
c5a63c953a | ||
|
|
7184484488 | ||
|
|
96c42c0aa5 | ||
|
|
971f3b4937 | ||
|
|
e617b08ab6 | ||
|
|
a66fa4c77d | ||
|
|
5398da9d76 | ||
|
|
b474a6f4e5 | ||
|
|
eb7c5674a0 | ||
|
|
d366fd376e | ||
|
|
5ae0d2f20c | ||
|
|
78d10b1feb | ||
|
|
9d194b5a84 | ||
|
|
84ab2059d7 | ||
|
|
014b3b3852 | ||
|
|
94b15b5260 | ||
|
|
1288676302 | ||
|
|
ac0b1a6f82 | ||
|
|
61884c5de4 | ||
|
|
515e02bcc6 | ||
|
|
d698ca3899 | ||
|
|
9698bdebcd | ||
|
|
7fc5fa0661 | ||
|
|
fee2b50cb9 | ||
|
|
83a61da255 | ||
|
|
086df21ce7 | ||
|
|
8862e5db74 | ||
|
|
eb16c6e980 | ||
|
|
6ba15e6a52 | ||
|
|
8b914fcec2 | ||
|
|
c5ffe377df | ||
|
|
a5d4027c80 | ||
|
|
631f0cd2e7 | ||
|
|
1c6ea5aab2 | ||
|
|
3f0ce7ec4e | ||
|
|
a7baab6a97 | ||
|
|
44c1fe4840 | ||
|
|
f759491279 | ||
|
|
19ed8d5ef1 | ||
|
|
5277b9dc16 | ||
|
|
421a8768d4 | ||
|
|
bb0b001184 | ||
|
|
0bbdc6bc00 | ||
|
|
34d29e6192 | ||
|
|
93d0ad25d1 | ||
|
|
1cd7ac0483 | ||
|
|
37474e5ccb | ||
|
|
f6870f4a01 | ||
|
|
278038ee87 | ||
|
|
4aa829d45d | ||
|
|
0a041c2509 | ||
|
|
6cd425e408 | ||
|
|
cacc6db9a4 | ||
|
|
eb988ab763 | ||
|
|
0d1edc6450 | ||
|
|
e7eecb03e0 | ||
|
|
371892ceaa | ||
|
|
aab3ee78dc | ||
|
|
6b44d93780 | ||
|
|
1171d24f3f | ||
|
|
4909877fc0 | ||
|
|
ec5196e5f0 | ||
|
|
bf38517a91 | ||
|
|
ddad637bb3 | ||
|
|
3641703a49 | ||
|
|
04da794b6b | ||
|
|
52f2a8383a | ||
|
|
56effc24cb | ||
|
|
1baca77f3a | ||
|
|
e09444fa89 | ||
|
|
b7daed2ce3 | ||
|
|
252ba7d53a | ||
|
|
ffe8e00046 | ||
|
|
d03a412e5b | ||
|
|
24c3447d6c | ||
|
|
b270c1bac4 | ||
|
|
e7c75147d2 | ||
|
|
3c37704b3b | ||
|
|
e69b55dbcd | ||
|
|
9c99db7119 | ||
|
|
0441127c41 | ||
|
|
70ea12aec3 | ||
|
|
f3a8f45de4 | ||
|
|
3a301b1859 | ||
|
|
06246557c5 | ||
|
|
1264b81bb6 | ||
|
|
18c827653d | ||
|
|
20b0d1d4ae | ||
|
|
1085e0b2f1 | ||
|
|
b4d7628b86 | ||
|
|
4a5f4fe6e4 | ||
|
|
07edd96088 | ||
|
|
f4b2b62874 | ||
|
|
09567fa99e | ||
|
|
91831eb525 | ||
|
|
eef5fc8f99 | ||
|
|
dfe4d4e132 | ||
|
|
4fb5d2b31e | ||
|
|
91cb42d7d8 | ||
|
|
3d2ae33799 | ||
|
|
ca2030f62c | ||
|
|
15de7d45c9 | ||
|
|
d2bb85ab6c | ||
|
|
deb5b8a98f | ||
|
|
f9819e0c71 | ||
|
|
bb24c05b90 | ||
|
|
51f760edc2 | ||
|
|
60807d1958 | ||
|
|
6b62ed8673 | ||
|
|
1ef913cb64 | ||
|
|
c8d20a7064 | ||
|
|
ec9525a3e8 | ||
|
|
b6b7238519 | ||
|
|
764a135bb3 | ||
|
|
8de525fa28 | ||
|
|
bb0d4bcc2f | ||
|
|
98ed7338e6 | ||
|
|
afda2fcbbd | ||
|
|
8febf10651 | ||
|
|
ac391479f2 | ||
|
|
dcc9a5596e | ||
|
|
52ae61fe24 | ||
|
|
befd7098ce | ||
|
|
77457ed800 | ||
|
|
dd62f293d6 | ||
|
|
f9f01320ca | ||
|
|
62c08f66fb | ||
|
|
1013ae5eb3 | ||
|
|
c21d7a1233 | ||
|
|
6b10d86407 | ||
|
|
36cc74b224 | ||
|
|
26b756d7d8 | ||
|
|
a92394eac2 | ||
|
|
8732569a01 | ||
|
|
e9364df4ed | ||
|
|
6f89ffec83 | ||
|
|
9e05b1fd51 | ||
|
|
b602e3799d | ||
|
|
c9f9f4e500 | ||
|
|
fcab48a5e5 | ||
|
|
94ce3bea64 | ||
|
|
34d88bb13c | ||
|
|
a65cfe6237 | ||
|
|
105b5c2863 | ||
|
|
c749f610c5 | ||
|
|
698686e1d4 | ||
|
|
c421956cd9 | ||
|
|
f8f59502b5 | ||
|
|
93e62c6336 | ||
|
|
129ce24308 | ||
|
|
85a4cbd64e | ||
|
|
af1bc749e1 | ||
|
|
3166e6dfe3 | ||
|
|
834c952f20 | ||
|
|
c5578e338d | ||
|
|
9d10e2bff1 | ||
|
|
752e9d1c75 | ||
|
|
421dc21f72 | ||
|
|
b909e4aac3 | ||
|
|
dfb214d47d | ||
|
|
f9f6da0a43 | ||
|
|
ddcccfeaa9 | ||
|
|
138e19fa19 | ||
|
|
37666770be | ||
|
|
5f3c4ffafe | ||
|
|
f9123a4cc6 | ||
|
|
8d6de4ec59 | ||
|
|
ec06e6ed95 | ||
|
|
d8e8bc868f | ||
|
|
0f45b5ab1b | ||
|
|
09f964ffcb | ||
|
|
6fc6a4dac9 | ||
|
|
43e931baa4 | ||
|
|
906c620327 | ||
|
|
6902485c12 | ||
|
|
b2be5638f8 | ||
|
|
68f8826ecf | ||
|
|
e43d660733 | ||
|
|
7b4d5e8317 | ||
|
|
fabc1f346e | ||
|
|
9f12721895 | ||
|
|
3f9319d55f | ||
|
|
77e05b285f | ||
|
|
e9515130e0 | ||
|
|
80d1fdaef3 | ||
|
|
8171e1753c | ||
|
|
b1f6cfb2c9 | ||
|
|
284233a920 | ||
|
|
90c084f818 | ||
|
|
cbb8a78c19 | ||
|
|
d3fd066209 | ||
|
|
fd45299b6b | ||
|
|
bf7ba84d93 | ||
|
|
608fcc17e0 | ||
|
|
28d29aa33c | ||
|
|
4fddcf6c92 | ||
|
|
e0e4155e89 | ||
|
|
d272896adf | ||
|
|
636e939d23 | ||
|
|
17fe724ca4 | ||
|
|
eb0f33df16 | ||
|
|
b042974673 | ||
|
|
be7274064b | ||
|
|
60756678ab | ||
|
|
384c579c4a | ||
|
|
c019443026 | ||
|
|
dc6771d604 | ||
|
|
4111acd1c1 | ||
|
|
aba1b39211 | ||
|
|
1f821ce2f6 | ||
|
|
a9a0bd6cd3 | ||
|
|
4edb5bf497 | ||
|
|
ca58928b6c | ||
|
|
d484517555 | ||
|
|
ad4f7cd3c9 | ||
|
|
a07fe2abee | ||
|
|
00f0f89cbd | ||
|
|
bbd8305310 | ||
|
|
06246d1aa4 | ||
|
|
816d2cd4b4 | ||
|
|
d13e6f14fb | ||
|
|
3070c8fc9e | ||
|
|
1f8b15c710 | ||
|
|
81c6ae3b2d | ||
|
|
cd9f672662 | ||
|
|
d0ec18f4db | ||
|
|
079e9f878e | ||
|
|
ac70770ba5 | ||
|
|
fb219afeba | ||
|
|
eb9cc3923a | ||
|
|
da6435ce28 | ||
|
|
54c918a10e | ||
|
|
e14ed4749d | ||
|
|
156d757bd8 | ||
|
|
8a0aec18eb | ||
|
|
bbaa618726 | ||
|
|
a5203ae363 | ||
|
|
246753c6d4 | ||
|
|
f4450b0091 | ||
|
|
1cc5017fb4 | ||
|
|
4d0e18db23 | ||
|
|
282730e635 | ||
|
|
3566bb6f5f | ||
|
|
2954098004 | ||
|
|
f081c3b41b | ||
|
|
6b1434f7a7 | ||
|
|
8454b0d1b8 | ||
|
|
c13c707a62 | ||
|
|
39b761c056 | ||
|
|
a64ecf24be | ||
|
|
b8fb45de9e | ||
|
|
55da03ad2f | ||
|
|
e53eea6ecc | ||
|
|
30c2a0b681 | ||
|
|
6e4a826dc1 | ||
|
|
2f915caff2 | ||
|
|
b03598b168 | ||
|
|
bb96e253c9 | ||
|
|
6b4b5fce13 | ||
|
|
79576f25b6 | ||
|
|
2f6300af46 | ||
|
|
b3ca36a8b0 | ||
|
|
f495cb41d9 | ||
|
|
3ee595f927 | ||
|
|
fd47a74b9e | ||
|
|
b3256f0ecd | ||
|
|
5af56793eb | ||
|
|
35ca78f642 | ||
|
|
164c703861 | ||
|
|
426ee1f76e | ||
|
|
3c0649d89f | ||
|
|
01b4c06916 | ||
|
|
03104bfbc3 | ||
|
|
a937424faa | ||
|
|
7873370583 | ||
|
|
31cee95b6f | ||
|
|
c64ccc4fcd | ||
|
|
52459768f2 | ||
|
|
558038be32 | ||
|
|
750e211649 | ||
|
|
8f59649eb6 | ||
|
|
a45f705bda | ||
|
|
1d74de2559 | ||
|
|
3afdb8fcff | ||
|
|
a71d93c63c | ||
|
|
67b43c6079 | ||
|
|
4aacf4f7c7 | ||
|
|
1c29609f08 | ||
|
|
9c485a7561 | ||
|
|
472c6871da | ||
|
|
9e2e73d39c | ||
|
|
1a31c74d5c | ||
|
|
bc5a19a37b | ||
|
|
658e1203b2 | ||
|
|
3decf7f519 | ||
|
|
a322d6c4e8 |
536 changed files with 56975 additions and 4142 deletions
4
.coveragerc
Normal file
4
.coveragerc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[report]
|
||||
omit =
|
||||
pelican/tests/*
|
||||
pelican/signals.py
|
||||
15
.editorconfig
Normal file
15
.editorconfig
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.py]
|
||||
max_line_length = 88
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
21
.git-blame-ignore-revs
Normal file
21
.git-blame-ignore-revs
Normal 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
|
||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# 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
1
.github/CODEOWNERS
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.github/workflows/github_pages.yml @seanh
|
||||
5
.github/FUNDING.yml
vendored
Normal file
5
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
|
||||
github: justinmayer
|
||||
custom: https://donate.getpelican.com
|
||||
liberapay: pelican
|
||||
44
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
name: "\U0001F41E Bug Report"
|
||||
about: Did you find a bug?
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Hi there! Thank you for discovering and submitting an issue.
|
||||
|
||||
Before you submit this, let’s make sure of a few things.
|
||||
Please make sure the following boxes are ticked if they are correct.
|
||||
If not, please try and fulfill them first.
|
||||
-->
|
||||
|
||||
<!-- 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.
|
||||
|
||||
<!--
|
||||
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 -->
|
||||
- **Python version**: <!-- Replace with version -->
|
||||
- **Pelican version**: <!-- Replace with version -->
|
||||
- **Link to theme**: <!-- Replace with link to the theme you are using -->
|
||||
- **Links to plugins**: <!-- Replace with list of links to plugins you are using -->
|
||||
- **Link to your site**: <!-- If available, replace with link to your site -->
|
||||
- **Link to your source**: <!-- If available, replace with link to relevant source repository -->
|
||||
- **Link to a [Gist](https://gist.github.com/) with the contents of your settings file**: <!-- If your source is not accessible, put Gist link here -->
|
||||
|
||||
## Issue
|
||||
<!--
|
||||
Now feel free to write your issue. Please avoid vague phrases like “[…] doesn’t work”.
|
||||
Be descriptive! Thanks again 🙌 ❤️
|
||||
-->
|
||||
22
.github/ISSUE_TEMPLATE/---documentation.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/---documentation.md
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
name: "\U0001F4DA Documentation"
|
||||
about: Did you find errors, problems, or anything unclear in the docs (https://docs.getpelican.com/)?
|
||||
title: ''
|
||||
labels: docs
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Hi there! Thank you for discovering and submitting an issue with our documentation.
|
||||
|
||||
Before you submit this, let’s make sure of a few things.
|
||||
Please make sure the following boxes are ticked if they are correct.
|
||||
If not, please try and fulfill them first.
|
||||
-->
|
||||
|
||||
<!-- 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.
|
||||
|
||||
## Issue
|
||||
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->
|
||||
24
.github/ISSUE_TEMPLATE/---enhancement-request.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/---enhancement-request.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
name: "\U0001F381 Feature Request"
|
||||
about: Do you have ideas for new features and improvements?
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Hi there! Thank you for wanting to make Pelican better.
|
||||
|
||||
Before you submit this, let’s make sure of a few things.
|
||||
Please make sure the following boxes are ticked if they are correct.
|
||||
If not, please try and fulfill them first. The last one is optional but encouraged.
|
||||
-->
|
||||
|
||||
<!-- 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 am willing to lend a hand to help implement this feature. <!-- optional but encouraged -->
|
||||
|
||||
## Feature Request
|
||||
<!-- Now feel free to write your idea for improvement. Thanks again 🙌 ❤️ -->
|
||||
28
.github/ISSUE_TEMPLATE/---everything-else.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/---everything-else.md
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
name: "\U0001F5C3 Everything Else"
|
||||
about: Do you have a question/issue that does not fall into any of the other categories?
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
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, let’s make sure of a few things.
|
||||
Please make sure the following boxes are ticked if they are correct.
|
||||
If not, please try and fulfill them first.
|
||||
-->
|
||||
|
||||
<!-- 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 🙌 ❤️ -->
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
|
@ -0,0 +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: false
|
||||
contact_links:
|
||||
- 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
9
.github/dependabot.yml
vendored
Normal 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"
|
||||
12
.github/pull_request_template.md
vendored
Normal file
12
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Pull Request Checklist
|
||||
|
||||
Resolves: #issue-number-here <!-- Only if related issue *already* exists — otherwise remove this line -->
|
||||
|
||||
<!-- This is just a reminder about the most common mistakes. Please make sure that you tick all *appropriate* boxes. Also, please read our [contribution guide](https://docs.getpelican.com/en/latest/contribute.html#contributing-code) at least once — it will save you unnecessary review cycles! -->
|
||||
|
||||
- [ ] Ensured **tests pass** and (if applicable) updated functional test output
|
||||
- [ ] Conformed to **code style guidelines** by running appropriate linting tools
|
||||
- [ ] Added **tests** for changed code
|
||||
- [ ] Updated **documentation** for changed code
|
||||
|
||||
<!-- If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! -->
|
||||
31
.github/stale.yml
vendored
Normal file
31
.github/stale.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 60
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
daysUntilClose: 30
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: true
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: true
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your participation and understanding.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 1
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
105
.github/workflows/github_pages.yml
vendored
Normal file
105
.github/workflows/github_pages.yml
vendored
Normal 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
|
||||
146
.github/workflows/main.yml
vendored
Normal file
146
.github/workflows/main.yml
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
name: build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
# color output for pytest and tox
|
||||
PYTEST_ADDOPTS: "--color=yes"
|
||||
PY_COLORS: 1
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test - ${{ matrix.python }} - ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu, macos, windows]
|
||||
python: ["3.10", "3.11", "3.12", "3.13"]
|
||||
include:
|
||||
- os: ubuntu
|
||||
python: "3.9"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
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@v2
|
||||
with:
|
||||
pandoc-version: "2.9.2"
|
||||
- name: Install tox
|
||||
run: python -m pip install -U pip tox
|
||||
- name: Info
|
||||
run: |
|
||||
echo "===== PYTHON ====="
|
||||
python --version
|
||||
echo "===== PANDOC ====="
|
||||
pandoc --version | head -2
|
||||
- name: Run tests
|
||||
run: tox -e py${{ matrix.python }}
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
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 --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@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
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
|
||||
environment: Deployment
|
||||
needs: [test, lint, docs, build]
|
||||
runs-on: ubuntu-latest
|
||||
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@v4
|
||||
with:
|
||||
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 --upgrade pip
|
||||
python -m pip install autopub[github]
|
||||
autopub check
|
||||
|
||||
- name: Publish
|
||||
if: ${{ steps.check_release.outputs.autopub_release=='true' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
run: |
|
||||
autopub prepare
|
||||
autopub commit
|
||||
autopub build
|
||||
autopub githubrelease
|
||||
|
||||
- name: Upload package to PyPI
|
||||
if: ${{ steps.check_release.outputs.autopub_release=='true' }}
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
*.egg-info
|
||||
.*.swp
|
||||
.*.swo
|
||||
*.pyc
|
||||
.DS_Store
|
||||
docs/_build
|
||||
docs/*/_build
|
||||
build
|
||||
dist
|
||||
tags
|
||||
.tox
|
||||
.coverage
|
||||
htmlcov
|
||||
*.orig
|
||||
venv
|
||||
samples/output
|
||||
*.pem
|
||||
*.lock
|
||||
.pdm-python
|
||||
.vale
|
||||
.venv
|
||||
**/LC_MESSAGES/*.mo
|
||||
|
||||
# direnv
|
||||
.envrc
|
||||
|
||||
# IDE cruft
|
||||
.idea
|
||||
.vscode
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
syntax: glob
|
||||
output/*
|
||||
*.pyc
|
||||
MANIFEST
|
||||
build
|
||||
dist
|
||||
docs/_build
|
||||
Paste-*
|
||||
*.egg-info
|
||||
26
.hgtags
26
.hgtags
|
|
@ -1,26 +0,0 @@
|
|||
7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2
|
||||
7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2
|
||||
ae850ab0fd62a98a98da7ce74ac794319c6a5066 1.2
|
||||
54a0309f79d6c5b54d8e1e3b5e3f744856b68a73 1.1
|
||||
8f5e0eb037768351eb08840e588a4364266a69b3 1.1.1
|
||||
bb986ed591734ca469f726753cbc48ebbfce0dcc 1.2.1
|
||||
8a3dad99cbfa6bb5d0ef073213d0d86e0b4c5dba 1.2.2
|
||||
4a20105a242ab154f6202aa6651979bfbb4cf95e 1.2.3
|
||||
803aa0976cca3dd737777c640722988b1f3769fe 1.2.4
|
||||
703c4511105fd9c8b85afda951a294c194e7cf3e 1.2.5
|
||||
6e46a40aaa850a979f5d09dd95d02791ec7ab0ef 2.0
|
||||
bf14d1a5c1fae9475447698f0f9b8d35c551f732 2.1
|
||||
da86343ebd543e5865050e47ecb0937755528d13 2.1.1
|
||||
760187f048bb23979402f950ecb5d3c5493995b1 2.2
|
||||
20aa16fe4daa3b70f6c063f170edc916b49837ed 2.3
|
||||
f9c1d94081504f21f5b2ba147a38099e45db1769 2.4
|
||||
e65199a0b2706d2fb48f7a3c015e869716e0bec1 2.4.1
|
||||
89dbd7b6f114508eae62fc821326f4797dfc8b23 2.4.2
|
||||
979b4473af56a191a278c83058bc9c8fa1fde30e 2.4.3
|
||||
26a444fbb78becae358afa0a5b47587db8739b21 2.4.4
|
||||
3542b65fd1963ae7065b6a3bc912fbb6c150e98c 2.4.5
|
||||
87745dfdd51b96bf18eaaf6c402effa902c1b856 2.5.0
|
||||
294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1
|
||||
294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1
|
||||
92b31e41134cb2c1a156ce623338cf634d2ebc3e 2.5.1
|
||||
7d728f8e771cbbc802ce81e424e08a8eecbd48dc 2.5.2
|
||||
24
.mailmap
Normal file
24
.mailmap
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Alexis Métaireau <alexis@notmyidea.org>
|
||||
Alexis Métaireau <alexis@notmyidea.org> <alexis, notmyidea, org>
|
||||
Alexis Métaireau <alexis@notmyidea.org> <ametaireau@gmail.com>
|
||||
Axel Haustant <noirbizarre@gmail.com> <axel.haustant.ext@mappy.com>
|
||||
Axel Haustant <noirbizarre@gmail.com> <axel.haustant@valtech.fr>
|
||||
Dave Mankoff <mankyd@gmail.com>
|
||||
Feth Arezki <feth@tuttu.info>
|
||||
Guillaume <guillaume@lame.homelinux.com>
|
||||
Guillaume <guillaume@lame.homelinux.com> <guillaume@mint.(none)>
|
||||
Guillaume B <guitreize@gmail.com>
|
||||
Guillermo López <guilan70@hotmail.com>
|
||||
Guillermo López <guilan70@hotmail.com> <guillermo.lopez@outlook.com>
|
||||
Jomel Imperio <jimperio@gmail.com>
|
||||
Justin Mayer <entrop@gmail.com>
|
||||
Justin Mayer <entrop@gmail.com> <entroP@gmail.com>
|
||||
Marco Milanesi <kpanic@gnufunk.org> <marcom@openquake.org>
|
||||
Massimo Santini <santini@dsi.unimi.it> <santini@spillane.docenti.dsi.unimi.it>
|
||||
Rémy HUBSCHER <hubscher.remy@gmail.com> <remy.hubscher@ionyse.com>
|
||||
Simon Conseil <contact@saimon.org>
|
||||
Simon Liedtke <liedtke.simon@googlemail.com>
|
||||
Skami18 <skami@skami-laptop.dyndns.org>
|
||||
Stuart Colville <muffinresearchlabs@gmail.com> <muffinresearch@gmail.com>
|
||||
Stéphane Bunel <stephane@lutetium.(none)>
|
||||
tBunnyMan <WagThatTail@Me.com>
|
||||
30
.pre-commit-config.yaml
Normal file
30
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
# See https://pre-commit.com/hooks.html for info on hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-ast
|
||||
- id: check-toml
|
||||
- id: check-yaml
|
||||
- id: debug-statements
|
||||
- id: detect-private-key
|
||||
- id: end-of-file-fixer
|
||||
- id: forbid-new-submodules
|
||||
- id: trailing-whitespace
|
||||
|
||||
- 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
28
.readthedocs.yaml
Normal 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
10
.vale.ini
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
StylesPath = .vale/styles
|
||||
|
||||
Vocab = Pelican
|
||||
|
||||
MinAlertLevel = suggestion
|
||||
|
||||
Packages = proselint, alex
|
||||
|
||||
[*]
|
||||
BasedOnStyles = Vale, proselint, alex
|
||||
139
CONTRIBUTING.rst
Normal file
139
CONTRIBUTING.rst
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
Filing 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
|
||||
===============
|
||||
|
||||
Before you ask for help, please make sure you do the following:
|
||||
|
||||
1. 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.
|
||||
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 ':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 ``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)
|
||||
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
|
||||
publicly-accessible location:
|
||||
|
||||
* 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``).
|
||||
* 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.
|
||||
* 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.).
|
||||
* 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.
|
||||
* Upload detailed and **complete** output logs and backtraces (remember to add
|
||||
the ``--debug`` flag: ``pelican --debug content [...]``)
|
||||
|
||||
.. _documentation: https://docs.getpelican.com/
|
||||
.. _`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
|
||||
=================
|
||||
|
||||
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.
|
||||
|
||||
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 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. 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::
|
||||
|
||||
Release type: minor
|
||||
|
||||
Reload browser window upon changes to content, settings, or theme
|
||||
|
||||
* Check for unnecessary whitespace via ``git diff --check`` before committing.
|
||||
* 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).
|
||||
* After the first line of the commit message, add a blank line and then a more
|
||||
detailed explanation (when relevant).
|
||||
* `Squash your commits`_ to eliminate merge commits and ensure a clean and
|
||||
readable commit history.
|
||||
* 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.)
|
||||
|
||||
Contribution quality standards
|
||||
------------------------------
|
||||
|
||||
* 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.
|
||||
* :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
|
||||
.. _`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
|
||||
.. _`Git Tips`: https://github.com/getpelican/pelican/wiki/Git-Tips
|
||||
.. _`ask for help`: `How to get help`_
|
||||
.. _`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
|
||||
669
LICENSE
669
LICENSE
|
|
@ -1,14 +1,661 @@
|
|||
This file is part of Pelican.
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Pelican is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://www.fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Pelican is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero Public License for more details.
|
||||
Preamble
|
||||
|
||||
You should have received a copy of the GNU Affero Public License
|
||||
along with Pelican. If not, see <http://www.gnu.org/licenses/>.
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
include *.rst
|
||||
recursive-include pelican *.html *.css *png
|
||||
include LICENSE
|
||||
89
README.rst
89
README.rst
|
|
@ -1,47 +1,78 @@
|
|||
Pelican
|
||||
#######
|
||||
Pelican |build-status| |pypi-version| |downloads| |repology|
|
||||
============================================================
|
||||
|
||||
Pelican is a simple weblog generator, writen 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.
|
||||
|
||||
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
|
||||
|
||||
* Write your weblog entries directly with your editor of choice (vim!) and
|
||||
directly in restructured text, or markdown.
|
||||
* A simple cli-tool to (re)generate the weblog.
|
||||
* Easy to interface with DVCSes and web hooks
|
||||
* Completely static output, so easy to host anywhere !
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Pelican currently supports:
|
||||
Pelican’s feature highlights include:
|
||||
|
||||
* blog articles
|
||||
* comments, via an external service (disqus). Please notice that while
|
||||
it's useful, it's an external service, and you'll not manage the
|
||||
comments by yourself. It could potentially eat your data.
|
||||
* theming support (themes are done using `jinja2 <http://jinjna.pocoo.org>`_)
|
||||
* PDF generation of the articles/pages (optional).
|
||||
* Chronological content (e.g., articles, blog posts) as well as static pages
|
||||
* Integration with external services
|
||||
* Site themes (created using Jinja2_ templates)
|
||||
* Publication of articles in multiple languages
|
||||
* Generation of Atom and RSS feeds
|
||||
* 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`_
|
||||
|
||||
Have a look to `the documentation <http://alexis.notmyidea.org/pelican/>`_ for
|
||||
more informations.
|
||||
Check out the `Pelican documentation`_ for further information.
|
||||
|
||||
Why the name "Pelican" ?
|
||||
------------------------
|
||||
|
||||
Heh, you didn't noticed? "Pelican" is an anagram for "Calepin" ;)
|
||||
How to get help, contribute, or provide feedback
|
||||
------------------------------------------------
|
||||
|
||||
See our `contribution submission and feedback guidelines <CONTRIBUTING.rst>`_.
|
||||
|
||||
|
||||
Source code
|
||||
-----------
|
||||
|
||||
You can access the source code via mercurial at http://hg.notmyidea.org/pelican/
|
||||
or via git on http://github.com/ametaireau/pelican/
|
||||
Pelican’s source code is `hosted on GitHub`_. For information on how it works,
|
||||
have a look at `Pelican's internals`_.
|
||||
|
||||
If you feel hackish, have a look to the `pelican's internals explanations
|
||||
<http://alexis.notmyidea.org/pelican/internals.html>`_.
|
||||
|
||||
Feedback !
|
||||
----------
|
||||
Why the name “Pelican”?
|
||||
-----------------------
|
||||
|
||||
If you want to see new features in Pelican, dont hesitate to tell me, to clone
|
||||
the repository, etc. That's open source, dude!
|
||||
“Pelican” is an anagram of *calepin*, which means “notebook” in French.
|
||||
|
||||
Contact me at "alexis at notmyidea dot org" for any request/feedback !
|
||||
|
||||
.. Links
|
||||
|
||||
.. _Python: https://www.python.org/
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||
.. _Markdown: https://daringfireball.net/projects/markdown/
|
||||
.. _Jinja2: https://palletsprojects.com/p/jinja/
|
||||
.. _Pygments: https://pygments.org/
|
||||
.. _`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/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
|
||||
|
|
|
|||
188
THANKS
188
THANKS
|
|
@ -1,12 +1,178 @@
|
|||
Some people have helped to improve pelican by contributing features, reporting
|
||||
bugs or giving ideas. Thanks to them !
|
||||
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
|
||||
|
||||
- Dan Jacka
|
||||
- solsTiCe on linuxfr for reporting bugs
|
||||
- Guillaume B (Gui13)
|
||||
- Ronny Pfannschmidt
|
||||
- Jérome Renard
|
||||
- Nicolas Martin
|
||||
- David Kulak
|
||||
- Arnaud Bos
|
||||
- nblock (Florian)
|
||||
If you want to contribute, check the documentation section about how to do so:
|
||||
<https://docs.getpelican.com/en/latest/contribute.html>
|
||||
|
||||
Aaron Kavlie
|
||||
Abhishek L
|
||||
Albrecht Mühlenschulte
|
||||
Aldiantoro Nugroho
|
||||
Alen Mujezinovic
|
||||
Alessandro Martin
|
||||
Alexander Artemenko
|
||||
Alexandre RODIERE
|
||||
Alexis Daboville
|
||||
Alexis Métaireau
|
||||
Allan Whatmough
|
||||
Andrea Crotti
|
||||
Andrew Laski
|
||||
Andrew Spiers
|
||||
Arnaud BOS
|
||||
asselinpaul
|
||||
Axel Haustant
|
||||
Ben Rosser (TC01)
|
||||
Ben Sturmfels
|
||||
Benoît HERVIER
|
||||
Bernhard Scheirle
|
||||
Borgar
|
||||
Brandon W Maister
|
||||
Brendan Wholihan
|
||||
Brian C. Lane
|
||||
Brian Hsu
|
||||
Brian St. Pierre
|
||||
Bruno Binet
|
||||
BunnyMan
|
||||
Chenguang Wang
|
||||
Chris Elston
|
||||
Chris McDonald (Wraithan)
|
||||
Chris Streeter
|
||||
Christophe Chauvet
|
||||
Clint Howarth
|
||||
Colin Dunklau
|
||||
Dafydd Crosby
|
||||
Dana Woodman
|
||||
Dave King
|
||||
Dave Mankoff
|
||||
David Beitey
|
||||
David Marble
|
||||
Deniz Turgut (Avaris)
|
||||
derdon
|
||||
Dirkjan Ochtman
|
||||
Dirk Makowski
|
||||
draftcode
|
||||
Edward Delaporte
|
||||
Emily Strickland
|
||||
epatters
|
||||
Eric Case
|
||||
Erik Hetzner
|
||||
FELD Boris
|
||||
Feth Arezki
|
||||
Florian Jacob
|
||||
Florian Preinstorfer
|
||||
Félix Delval
|
||||
Frederik Ring
|
||||
Freeculture
|
||||
George V. Reilly
|
||||
Guillaume
|
||||
Guillaume B
|
||||
Guillermo López
|
||||
guillermooo
|
||||
Ian Cordasco
|
||||
Igor Kalnitsky
|
||||
Irfan Ahmad
|
||||
Iuri de Silvio
|
||||
Ivan Dyedov
|
||||
James King
|
||||
James Rowe
|
||||
Jason K. Moore
|
||||
jawher
|
||||
Jered Boxman
|
||||
Jerome
|
||||
Jiachen Yang
|
||||
Jochen Breuer
|
||||
joe di castro
|
||||
John Kristensen
|
||||
John Mastro
|
||||
Jökull Sólberg Auðunsson
|
||||
Jomel Imperio
|
||||
Jonas Borges
|
||||
Joseph Reagle
|
||||
Joshua Adelman
|
||||
Julian Berman
|
||||
Justin Mayer
|
||||
Kevin Deldycke
|
||||
Kevin Yap
|
||||
Kyle Fuller
|
||||
Laureline Guerin
|
||||
Leonard Huang
|
||||
Leonardo Giordani
|
||||
Leroy Jiang
|
||||
Lucas Cimon
|
||||
Marcel Hellkamp
|
||||
Marco Milanesi
|
||||
Marcus Fredriksson
|
||||
Mario Rodas
|
||||
Mark Caudill
|
||||
Martin Brochhaus
|
||||
Massimo Santini
|
||||
Matt Bowcock
|
||||
Matt Layman
|
||||
Meir Kriheli
|
||||
Michael Guntsche
|
||||
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
|
||||
Nicolas Steinmetz
|
||||
Paolo Melchiorre
|
||||
Paul Asselin
|
||||
Pavel Puchkin
|
||||
Perry Roper
|
||||
Peter Desmet
|
||||
Peter Sabaini
|
||||
Petr Viktorin
|
||||
Philippe Pepiot
|
||||
Rachid Belaid
|
||||
Randall Degges
|
||||
Ranjhith Kalisamy
|
||||
Remi Rampin
|
||||
Rémy HUBSCHER
|
||||
renhbo
|
||||
Richard Duivenvoorde
|
||||
Rogdham
|
||||
Romain Porte
|
||||
Roman Skvazh
|
||||
Ronny Pfannschmidt
|
||||
Rory McCann
|
||||
Rıdvan Örsvuran
|
||||
saghul
|
||||
sam
|
||||
Samrat Man Singh
|
||||
Simon Conseil
|
||||
Simon Liedtke
|
||||
Skami18
|
||||
solsTiCe d'Hiver
|
||||
Steve Schwarz
|
||||
Stéphane Bunel
|
||||
Stéphane Raimbault
|
||||
Stuart Colville
|
||||
Talha Mansoor
|
||||
Tarek Ziade
|
||||
Thanos Lefteris
|
||||
Thomas Thurman
|
||||
Tobias
|
||||
Tom Adler
|
||||
Tomi Pieviläinen
|
||||
Trae Blain
|
||||
Tristan Miller
|
||||
Tshepang Lekhonkhobe
|
||||
Valentin-Costel Hăloiu
|
||||
Vlad Niculae
|
||||
William Light
|
||||
William Minchin
|
||||
Wladislaw Merezhko
|
||||
W. Trevor King
|
||||
Zoresvit
|
||||
|
|
|
|||
8
TODO
8
TODO
|
|
@ -1,8 +0,0 @@
|
|||
* Add a way to support pictures (see how sphinx makes that)
|
||||
* Find a way to extend the existing templates instead of rewriting all from scratch.
|
||||
* Make the program support UTF8-encoded files as input (and later: any encoding?)
|
||||
* Add status support (draft, published, hidden)
|
||||
* Add a serve + automatic generation behaviour.
|
||||
* Recompile only the changed files, not all.
|
||||
* Add a way to make the coffee (or not)
|
||||
* Add a sitemap generator.
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from pelican import main
|
||||
main()
|
||||
BIN
docs/_static/overall.png
vendored
Normal file
BIN
docs/_static/overall.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
1
docs/_static/pelican-logo.svg
vendored
Normal file
1
docs/_static/pelican-logo.svg
vendored
Normal 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 |
BIN
docs/_static/pelican.gif
vendored
BIN
docs/_static/pelican.gif
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
BIN
docs/_static/pelican.png
vendored
BIN
docs/_static/pelican.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 6.3 KiB |
BIN
docs/_static/theme-basic.zip
vendored
Normal file
BIN
docs/_static/theme-basic.zip
vendored
Normal file
Binary file not shown.
11
docs/_static/theme_overrides.css
vendored
Normal file
11
docs/_static/theme_overrides.css
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
/* override table width restrictions */
|
||||
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||
/* !important prevents the common CSS stylesheets from
|
||||
overriding this as on RTD they are loaded after this stylesheet */
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.wy-table-responsive {
|
||||
overflow: visible !important;
|
||||
}
|
||||
BIN
docs/_static/uml.jpg
vendored
Normal file
BIN
docs/_static/uml.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
201
docs/_templates/page.html
vendored
Normal file
201
docs/_templates/page.html
vendored
Normal 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> © {{ copyright }}
|
||||
{%- endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e -%}
|
||||
Copyright © {{ 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 %}
|
||||
3
docs/_themes/.gitignore
vendored
3
docs/_themes/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
*.pyc
|
||||
*.pyo
|
||||
.DS_Store
|
||||
37
docs/_themes/LICENSE
vendored
37
docs/_themes/LICENSE
vendored
|
|
@ -1,37 +0,0 @@
|
|||
Copyright (c) 2010 by Armin Ronacher.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms of the theme, with or
|
||||
without modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
We kindly ask you to only use these themes in an unmodified manner just
|
||||
for Flask and Flask-related products, not for unrelated projects. If you
|
||||
like the visual style and want to use it for your own projects, please
|
||||
consider making some larger changes to the themes (such as changing
|
||||
font faces, sizes, colors or margins).
|
||||
|
||||
THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
31
docs/_themes/README
vendored
31
docs/_themes/README
vendored
|
|
@ -1,31 +0,0 @@
|
|||
Flask Sphinx Styles
|
||||
===================
|
||||
|
||||
This repository contains sphinx styles for Flask and Flask related
|
||||
projects. To use this style in your Sphinx documentation, follow
|
||||
this guide:
|
||||
|
||||
1. put this folder as _themes into your docs folder. Alternatively
|
||||
you can also use git submodules to check out the contents there.
|
||||
2. add this to your conf.py:
|
||||
|
||||
sys.path.append(os.path.abspath('_themes'))
|
||||
html_theme_path = ['_themes']
|
||||
html_theme = 'flask'
|
||||
|
||||
The following themes exist:
|
||||
|
||||
- 'flask' - the standard flask documentation theme for large
|
||||
projects
|
||||
- 'flask_small' - small one-page theme. Intended to be used by
|
||||
very small addon libraries for flask.
|
||||
|
||||
The following options exist for the flask_small theme:
|
||||
|
||||
[options]
|
||||
index_logo = '' filename of a picture in _static
|
||||
to be used as replacement for the
|
||||
h1 in the index.rst file.
|
||||
index_logo_height = 120px height of the index logo
|
||||
github_fork = '' repository name on github for the
|
||||
"fork me" badge
|
||||
16
docs/_themes/flask/layout.html
vendored
16
docs/_themes/flask/layout.html
vendored
|
|
@ -1,16 +0,0 @@
|
|||
{%- extends "basic/layout.html" %}
|
||||
{%- block extrahead %}
|
||||
{{ super() }}
|
||||
{% if theme_touch_icon %}
|
||||
<link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" />
|
||||
{% endif %}
|
||||
<link media="only screen and (max-device-width: 480px)" href="{{
|
||||
pathto('_static/small_flask.css', 1) }}" type= "text/css" rel="stylesheet" />
|
||||
{% endblock %}
|
||||
{%- block relbar2 %}{% endblock %}
|
||||
{%- block footer %}
|
||||
<div class="footer">
|
||||
© Copyright {{ copyright }}.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
|
||||
</div>
|
||||
{%- endblock %}
|
||||
19
docs/_themes/flask/relations.html
vendored
19
docs/_themes/flask/relations.html
vendored
|
|
@ -1,19 +0,0 @@
|
|||
<h3>Related Topics</h3>
|
||||
<ul>
|
||||
<li><a href="{{ pathto(master_doc) }}">Documentation overview</a><ul>
|
||||
{%- for parent in parents %}
|
||||
<li><a href="{{ parent.link|e }}">{{ parent.title }}</a><ul>
|
||||
{%- endfor %}
|
||||
{%- if prev %}
|
||||
<li>Previous: <a href="{{ prev.link|e }}" title="{{ _('previous chapter')
|
||||
}}">{{ prev.title }}</a></li>
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<li>Next: <a href="{{ next.link|e }}" title="{{ _('next chapter')
|
||||
}}">{{ next.title }}</a></li>
|
||||
{%- endif %}
|
||||
{%- for parent in parents %}
|
||||
</ul></li>
|
||||
{%- endfor %}
|
||||
</ul></li>
|
||||
</ul>
|
||||
387
docs/_themes/flask/static/flasky.css_t
vendored
387
docs/_themes/flask/static/flasky.css_t
vendored
|
|
@ -1,387 +0,0 @@
|
|||
/*
|
||||
* flasky.css_t
|
||||
* ~~~~~~~~~~~~
|
||||
*
|
||||
* :copyright: Copyright 2010 by Armin Ronacher.
|
||||
* :license: Flask Design License, see LICENSE for details.
|
||||
*/
|
||||
|
||||
{% set page_width = '940px' %}
|
||||
{% set sidebar_width = '220px' %}
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 17px;
|
||||
background-color: white;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.document {
|
||||
width: {{ page_width }};
|
||||
margin: 30px auto 0 auto;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 0 0 {{ sidebar_width }};
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
width: {{ sidebar_width }};
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #B1B4B6;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: #ffffff;
|
||||
color: #3E4349;
|
||||
padding: 0 30px 0 30px;
|
||||
}
|
||||
|
||||
img.floatingflask {
|
||||
padding: 0 0 10px 10px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
width: {{ page_width }};
|
||||
margin: 20px auto 30px auto;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
div.related {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #444;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted #999;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a:hover {
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 18px 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper p.logo {
|
||||
padding: 0 0 20px 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3,
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: 'Garamond', 'Georgia', serif;
|
||||
color: #444;
|
||||
font-size: 24px;
|
||||
font-weight: normal;
|
||||
margin: 0 0 5px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.logo a,
|
||||
div.sphinxsidebar h3 a,
|
||||
div.sphinxsidebar p.logo a:hover,
|
||||
div.sphinxsidebar h3 a:hover {
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: #555;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #ccc;
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
a {
|
||||
color: #004B6B;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #6D4100;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: 'Garamond', 'Georgia', serif;
|
||||
font-weight: normal;
|
||||
margin: 30px 0px 10px 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
|
||||
div.body h2 { font-size: 180%; }
|
||||
div.body h3 { font-size: 150%; }
|
||||
div.body h4 { font-size: 130%; }
|
||||
div.body h5 { font-size: 100%; }
|
||||
div.body h6 { font-size: 100%; }
|
||||
|
||||
a.headerlink {
|
||||
color: #ddd;
|
||||
padding: 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
color: #444;
|
||||
background: #eaeaea;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
div.admonition {
|
||||
background: #fafafa;
|
||||
margin: 20px -30px;
|
||||
padding: 10px 30px;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.admonition tt.xref, div.admonition a tt {
|
||||
border-bottom: 1px solid #fafafa;
|
||||
}
|
||||
|
||||
dd div.admonition {
|
||||
margin-left: -60px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title {
|
||||
font-family: 'Garamond', 'Georgia', serif;
|
||||
font-weight: normal;
|
||||
font-size: 24px;
|
||||
margin: 0 0 10px 0;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
div.admonition p.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.highlight {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
dt:target, .highlight {
|
||||
background: #FAF3E8;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
pre, tt {
|
||||
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
img.screenshot {
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
padding-right: 0.08em;
|
||||
}
|
||||
|
||||
img.screenshot {
|
||||
-moz-box-shadow: 2px 2px 4px #eee;
|
||||
-webkit-box-shadow: 2px 2px 4px #eee;
|
||||
box-shadow: 2px 2px 4px #eee;
|
||||
}
|
||||
|
||||
table.docutils {
|
||||
border: 1px solid #888;
|
||||
-moz-box-shadow: 2px 2px 4px #eee;
|
||||
-webkit-box-shadow: 2px 2px 4px #eee;
|
||||
box-shadow: 2px 2px 4px #eee;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
border: 1px solid #888;
|
||||
padding: 0.25em 0.7em;
|
||||
}
|
||||
|
||||
table.field-list, table.footnote {
|
||||
border: none;
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
table.footnote {
|
||||
margin: 15px 0;
|
||||
width: 100%;
|
||||
border: 1px solid #eee;
|
||||
background: #fdfdfd;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
table.footnote + table.footnote {
|
||||
margin-top: -15px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
table.field-list th {
|
||||
padding: 0 0.8em 0 0;
|
||||
}
|
||||
|
||||
table.field-list td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.footnote td.label {
|
||||
width: 0px;
|
||||
padding: 0.3em 0 0.3em 0.5em;
|
||||
}
|
||||
|
||||
table.footnote td {
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 0 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 10px 0 10px 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #eee;
|
||||
padding: 7px 30px;
|
||||
margin: 15px -30px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
dl pre, blockquote pre, li pre {
|
||||
margin-left: -60px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
dl dl pre {
|
||||
margin-left: -90px;
|
||||
padding-left: 90px;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
color: #222;
|
||||
/* padding: 1px 2px; */
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: #FBFBFB;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
|
||||
a.reference {
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted #004B6B;
|
||||
}
|
||||
|
||||
a.reference:hover {
|
||||
border-bottom: 1px solid #6D4100;
|
||||
}
|
||||
|
||||
a.footnote-reference {
|
||||
text-decoration: none;
|
||||
font-size: 0.7em;
|
||||
vertical-align: top;
|
||||
border-bottom: 1px dotted #004B6B;
|
||||
}
|
||||
|
||||
a.footnote-reference:hover {
|
||||
border-bottom: 1px solid #6D4100;
|
||||
}
|
||||
|
||||
a:hover tt {
|
||||
background: #EEE;
|
||||
}
|
||||
70
docs/_themes/flask/static/small_flask.css
vendored
70
docs/_themes/flask/static/small_flask.css
vendored
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* small_flask.css_t
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* :copyright: Copyright 2010 by Armin Ronacher.
|
||||
* :license: Flask Design License, see LICENSE for details.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px 30px;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: none;
|
||||
background: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
display: block;
|
||||
float: none;
|
||||
width: 102.5%;
|
||||
margin: 50px -30px -20px -30px;
|
||||
padding: 10px 20px;
|
||||
background: #333;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,
|
||||
div.sphinxsidebar h3 a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.document {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.related {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
div.related ul,
|
||||
div.related ul li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.body {
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
7
docs/_themes/flask/theme.conf
vendored
7
docs/_themes/flask/theme.conf
vendored
|
|
@ -1,7 +0,0 @@
|
|||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = flasky.css
|
||||
pygments_style = flask_theme_support.FlaskyStyle
|
||||
|
||||
[options]
|
||||
touch_icon =
|
||||
22
docs/_themes/flask_small/layout.html
vendored
22
docs/_themes/flask_small/layout.html
vendored
|
|
@ -1,22 +0,0 @@
|
|||
{% extends "basic/layout.html" %}
|
||||
{% block header %}
|
||||
{{ super() }}
|
||||
{% if pagename == 'index' %}
|
||||
<div class=indexwrapper>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block footer %}
|
||||
{% if pagename == 'index' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{# do not display relbars #}
|
||||
{% block relbar1 %}{% endblock %}
|
||||
{% block relbar2 %}
|
||||
{% if theme_github_fork %}
|
||||
<a href="http://github.com/{{ theme_github_fork }}"><img style="position: fixed; top: 0; right: 0; border: 0;"
|
||||
src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block sidebar1 %}{% endblock %}
|
||||
{% block sidebar2 %}{% endblock %}
|
||||
287
docs/_themes/flask_small/static/flasky.css_t
vendored
287
docs/_themes/flask_small/static/flasky.css_t
vendored
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* flasky.css_t
|
||||
* ~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- flasky theme based on nature theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 17px;
|
||||
color: #000;
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 40px auto 0 auto;
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #B1B4B6;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: #ffffff;
|
||||
color: #3E4349;
|
||||
padding: 0 30px 30px 30px;
|
||||
}
|
||||
|
||||
img.floatingflask {
|
||||
padding: 0 0 10px 10px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
text-align: right;
|
||||
color: #888;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
width: 650px;
|
||||
margin: 0 auto 40px auto;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #888;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.related {
|
||||
line-height: 32px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
a {
|
||||
color: #004B6B;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #6D4100;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.body {
|
||||
padding-bottom: 40px; /* saved for footer */
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: 'Garamond', 'Georgia', serif;
|
||||
font-weight: normal;
|
||||
margin: 30px 0px 10px 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
{% if theme_index_logo %}
|
||||
div.indexwrapper h1 {
|
||||
text-indent: -999999px;
|
||||
background: url({{ theme_index_logo }}) no-repeat center center;
|
||||
height: {{ theme_index_logo_height }};
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
div.body h2 { font-size: 180%; }
|
||||
div.body h3 { font-size: 150%; }
|
||||
div.body h4 { font-size: 130%; }
|
||||
div.body h5 { font-size: 100%; }
|
||||
div.body h6 { font-size: 100%; }
|
||||
|
||||
a.headerlink {
|
||||
color: white;
|
||||
padding: 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
color: #444;
|
||||
background: #eaeaea;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
div.admonition {
|
||||
background: #fafafa;
|
||||
margin: 20px -30px;
|
||||
padding: 10px 30px;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title {
|
||||
font-family: 'Garamond', 'Georgia', serif;
|
||||
font-weight: normal;
|
||||
font-size: 24px;
|
||||
margin: 0 0 10px 0;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
div.admonition p.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.highlight{
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
dt:target, .highlight {
|
||||
background: #FAF3E8;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
pre, tt {
|
||||
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
img.screenshot {
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
padding-right: 0.08em;
|
||||
}
|
||||
|
||||
img.screenshot {
|
||||
-moz-box-shadow: 2px 2px 4px #eee;
|
||||
-webkit-box-shadow: 2px 2px 4px #eee;
|
||||
box-shadow: 2px 2px 4px #eee;
|
||||
}
|
||||
|
||||
table.docutils {
|
||||
border: 1px solid #888;
|
||||
-moz-box-shadow: 2px 2px 4px #eee;
|
||||
-webkit-box-shadow: 2px 2px 4px #eee;
|
||||
box-shadow: 2px 2px 4px #eee;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
border: 1px solid #888;
|
||||
padding: 0.25em 0.7em;
|
||||
}
|
||||
|
||||
table.field-list, table.footnote {
|
||||
border: none;
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
table.footnote {
|
||||
margin: 15px 0;
|
||||
width: 100%;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
table.field-list th {
|
||||
padding: 0 0.8em 0 0;
|
||||
}
|
||||
|
||||
table.field-list td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.footnote td {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
margin: 15px -30px;
|
||||
padding: 8px;
|
||||
line-height: 1.3em;
|
||||
padding: 7px 30px;
|
||||
background: #eee;
|
||||
border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
}
|
||||
|
||||
dl pre {
|
||||
margin-left: -60px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
color: #222;
|
||||
/* padding: 1px 2px; */
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: #FBFBFB;
|
||||
}
|
||||
|
||||
a:hover tt {
|
||||
background: #EEE;
|
||||
}
|
||||
10
docs/_themes/flask_small/theme.conf
vendored
10
docs/_themes/flask_small/theme.conf
vendored
|
|
@ -1,10 +0,0 @@
|
|||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = flasky.css
|
||||
nosidebar = true
|
||||
pygments_style = flask_theme_support.FlaskyStyle
|
||||
|
||||
[options]
|
||||
index_logo_height = 120px
|
||||
index_logo =
|
||||
github_fork =
|
||||
86
docs/_themes/flask_theme_support.py
vendored
86
docs/_themes/flask_theme_support.py
vendored
|
|
@ -1,86 +0,0 @@
|
|||
# flasky extensions. flasky pygments style based on tango style
|
||||
from pygments.style import Style
|
||||
from pygments.token import Keyword, Name, Comment, String, Error, \
|
||||
Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
|
||||
|
||||
|
||||
class FlaskyStyle(Style):
|
||||
background_color = "#f8f8f8"
|
||||
default_style = ""
|
||||
|
||||
styles = {
|
||||
# No corresponding class for the following:
|
||||
#Text: "", # class: ''
|
||||
Whitespace: "underline #f8f8f8", # class: 'w'
|
||||
Error: "#a40000 border:#ef2929", # class: 'err'
|
||||
Other: "#000000", # class 'x'
|
||||
|
||||
Comment: "italic #8f5902", # class: 'c'
|
||||
Comment.Preproc: "noitalic", # class: 'cp'
|
||||
|
||||
Keyword: "bold #004461", # class: 'k'
|
||||
Keyword.Constant: "bold #004461", # class: 'kc'
|
||||
Keyword.Declaration: "bold #004461", # class: 'kd'
|
||||
Keyword.Namespace: "bold #004461", # class: 'kn'
|
||||
Keyword.Pseudo: "bold #004461", # class: 'kp'
|
||||
Keyword.Reserved: "bold #004461", # class: 'kr'
|
||||
Keyword.Type: "bold #004461", # class: 'kt'
|
||||
|
||||
Operator: "#582800", # class: 'o'
|
||||
Operator.Word: "bold #004461", # class: 'ow' - like keywords
|
||||
|
||||
Punctuation: "bold #000000", # class: 'p'
|
||||
|
||||
# because special names such as Name.Class, Name.Function, etc.
|
||||
# are not recognized as such later in the parsing, we choose them
|
||||
# to look the same as ordinary variables.
|
||||
Name: "#000000", # class: 'n'
|
||||
Name.Attribute: "#c4a000", # class: 'na' - to be revised
|
||||
Name.Builtin: "#004461", # class: 'nb'
|
||||
Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
|
||||
Name.Class: "#000000", # class: 'nc' - to be revised
|
||||
Name.Constant: "#000000", # class: 'no' - to be revised
|
||||
Name.Decorator: "#888", # class: 'nd' - to be revised
|
||||
Name.Entity: "#ce5c00", # class: 'ni'
|
||||
Name.Exception: "bold #cc0000", # class: 'ne'
|
||||
Name.Function: "#000000", # class: 'nf'
|
||||
Name.Property: "#000000", # class: 'py'
|
||||
Name.Label: "#f57900", # class: 'nl'
|
||||
Name.Namespace: "#000000", # class: 'nn' - to be revised
|
||||
Name.Other: "#000000", # class: 'nx'
|
||||
Name.Tag: "bold #004461", # class: 'nt' - like a keyword
|
||||
Name.Variable: "#000000", # class: 'nv' - to be revised
|
||||
Name.Variable.Class: "#000000", # class: 'vc' - to be revised
|
||||
Name.Variable.Global: "#000000", # class: 'vg' - to be revised
|
||||
Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
|
||||
|
||||
Number: "#990000", # class: 'm'
|
||||
|
||||
Literal: "#000000", # class: 'l'
|
||||
Literal.Date: "#000000", # class: 'ld'
|
||||
|
||||
String: "#4e9a06", # class: 's'
|
||||
String.Backtick: "#4e9a06", # class: 'sb'
|
||||
String.Char: "#4e9a06", # class: 'sc'
|
||||
String.Doc: "italic #8f5902", # class: 'sd' - like a comment
|
||||
String.Double: "#4e9a06", # class: 's2'
|
||||
String.Escape: "#4e9a06", # class: 'se'
|
||||
String.Heredoc: "#4e9a06", # class: 'sh'
|
||||
String.Interpol: "#4e9a06", # class: 'si'
|
||||
String.Other: "#4e9a06", # class: 'sx'
|
||||
String.Regex: "#4e9a06", # class: 'sr'
|
||||
String.Single: "#4e9a06", # class: 's1'
|
||||
String.Symbol: "#4e9a06", # class: 'ss'
|
||||
|
||||
Generic: "#000000", # class: 'g'
|
||||
Generic.Deleted: "#a40000", # class: 'gd'
|
||||
Generic.Emph: "italic #000000", # class: 'ge'
|
||||
Generic.Error: "#ef2929", # class: 'gr'
|
||||
Generic.Heading: "bold #000080", # class: 'gh'
|
||||
Generic.Inserted: "#00A000", # class: 'gi'
|
||||
Generic.Output: "#888", # class: 'go'
|
||||
Generic.Prompt: "#745334", # class: 'gp'
|
||||
Generic.Strong: "bold #000000", # class: 'gs'
|
||||
Generic.Subheading: "bold #800080", # class: 'gu'
|
||||
Generic.Traceback: "bold #a40000", # class: 'gt'
|
||||
}
|
||||
577
docs/changelog.rst
Normal file
577
docs/changelog.rst
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
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 theme’s 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
|
||||
==================
|
||||
|
||||
* Add new URL pattern to ``PAGINATION_PATTERNS`` for the last page in the list `(#1401) <https://github.com/getpelican/pelican/issues/1401>`_
|
||||
* Speed up ``livereload`` Invoke task via caching `(#2847) <https://github.com/getpelican/pelican/pull/2847>`_
|
||||
* Ignore ``None`` return value from ``get_generators`` signal `(#2850) <https://github.com/getpelican/pelican/pull/2850>`_
|
||||
* Relax dependency minimum versions and remove upper bounds
|
||||
|
||||
4.5.4 - 2021-01-04
|
||||
==================
|
||||
|
||||
Replace plugin definitions in settings with string representations after registering, so they can be cached correctly `(#2828) <https://github.com/getpelican/pelican/issues/2828>`_.
|
||||
|
||||
4.5.3 - 2020-12-01
|
||||
==================
|
||||
|
||||
Fix a mistake made in PR #2821
|
||||
|
||||
4.5.2 - 2020-11-22
|
||||
==================
|
||||
|
||||
Improve logging of generators and writer loaders
|
||||
|
||||
4.5.1 - 2020-11-02
|
||||
==================
|
||||
|
||||
* Refactor intra-site link discovery in order to match more permissively `(#2646) <https://github.com/getpelican/pelican/issues/2646>`_
|
||||
* Fix plugins running twice in auto-reload mode `(#2817) <https://github.com/getpelican/pelican/issues/2817>`_
|
||||
* Add notice to use ``from pelican import signals`` instead of ``import pelican.signals`` `(#2805) <https://github.com/getpelican/pelican/issues/2805>`_
|
||||
|
||||
4.5.0 - 2020-08-20
|
||||
==================
|
||||
|
||||
* Add namespace plugin support; list plugins via ``pelican-plugins`` command
|
||||
* Override settings via ``-e`` / ``--extra-settings`` CLI option flags
|
||||
* Add settings for custom Jinja globals and tests
|
||||
* Customize article summary ellipsis via ``SUMMARY_END_SUFFIX`` setting
|
||||
* Customize Typogrify dash handling via new ``TYPOGRIFY_DASHES`` setting
|
||||
* Support Unicode when generating slugs
|
||||
* Support Asciidoc ``.adoc`` file generation in Pelican importer
|
||||
* Improve user experience when ``pelican --listen`` web server is quit
|
||||
* Improve Invoke tasks template
|
||||
* Include tests in source distributions
|
||||
* Switch CI from Travis to GitHub Actions
|
||||
* Remove support for Python 2.7
|
||||
|
||||
4.2.0 - 2019-10-17
|
||||
==================
|
||||
|
||||
* Support inline SVGs; don't treat titles in SVGs as HTML titles
|
||||
* Add category to feeds (in addition to tags)
|
||||
* Improve content metadata field docs
|
||||
* Add docs for including other Markdown/reST files in content
|
||||
|
||||
4.1.3 - 2019-10-09
|
||||
==================
|
||||
|
||||
* Fix quick-start docs regarding ``pelican --listen``
|
||||
* Set default listen address to 127.0.0.1
|
||||
* Add extra/optional Markdown dependency to setup.py
|
||||
* Use correct SSH port syntax for rsync in tasks.py
|
||||
* Place all deprecated settings handling together
|
||||
* Add related project URLs for display on PyPI
|
||||
* Skip some tests on Windows that can't pass due to filesystem differences
|
||||
|
||||
4.1.2 - 2019-09-23
|
||||
==================
|
||||
|
||||
Fix pelican.settings.load_source to avoid caching issues - PR #2621
|
||||
|
||||
4.1.1 - 2019-08-23
|
||||
==================
|
||||
|
||||
* Add AutoPub to auto-publish releases on PR merge
|
||||
* Add CSS classes for reStructuredText figures
|
||||
* Pass ``argv`` to Pelican ``main`` entrypoint
|
||||
* Set default content status to a blank string rather than ``None``
|
||||
|
||||
4.1.0 - 2019-07-14
|
||||
==================
|
||||
|
||||
* Live browser reload upon changed files (provided via Invoke task)
|
||||
* Add ``pyproject.toml``, managed by Poetry
|
||||
* Support for invoking ``python -m pelican``
|
||||
* Add relative source path attribute to content
|
||||
* Allow directories in ``EXTRA_PATH_METADATA``
|
||||
* Add ``all_articles`` variable to period pages (for recent posts functionality)
|
||||
* Improve debug mode output
|
||||
* Remove blank or duplicate summaries from Atom feed
|
||||
* Fix bugs in pagination, pelican-import, pelican-quickstart, and feed importer
|
||||
|
||||
4.0.1 (2018-11-30)
|
||||
==================
|
||||
|
||||
* Refactor ``pelican.server`` logging
|
||||
* Fix bug in which all static files were processed as "draft"
|
||||
* Bug fixes for Invoke/Makefile automation, Importer, and other miscellanea
|
||||
|
||||
If upgrading from 3.7.x or earlier, please note that slug-related settings in
|
||||
4.0+ use ``{slug}`` and/or ``{lang}`` rather than ``%s``. If ``%s``-style
|
||||
settings are encountered, Pelican will emit a warning and fall back to the
|
||||
default setting. Some user-submitted themes might try to format setting values
|
||||
but fail upon site build with a ``TypeError``. In such cases, the theme needs
|
||||
to be updated. For example, instead of ``TAG_FEED_ATOM|format(tag.slug)``, use
|
||||
``TAG_FEED_ATOM.format(slug=tag.slug)``
|
||||
|
||||
4.0.0 (2018-11-13)
|
||||
==================
|
||||
|
||||
* Replace ``develop_server.sh`` script with ``pelican --listen``
|
||||
* Improved copy/link behavior for large static files (e.g., videos)
|
||||
* New ``{static}`` syntax to link to static content; content linked to by
|
||||
``{static}`` and ``{attach}`` is automatically copied over even if not in
|
||||
``STATIC_PATHS``
|
||||
* Pages can now have ``draft`` status
|
||||
* Show current settings via new ``--print-settings`` flag
|
||||
* All settings for slugs now use ``{slug}`` and/or ``{lang}`` rather than
|
||||
``%s``. If ``%s``-style settings are encountered, Pelican will emit a warning
|
||||
and fallback to the default setting.
|
||||
* New signals: ``feed_generated`` and ``page_generated_write_page``
|
||||
* Replace Fabric with Invoke and ``fabfile.py`` template with ``tasks.py``
|
||||
* Replace ``PAGINATED_DIRECT_TEMPLATES`` by ``PAGINATED_TEMPLATES``, extending
|
||||
control over pagination to all templates and making page size variable
|
||||
* Replace ``SLUG_SUBSTITUTIONS`` (and friends) by ``SLUG_REGEX_SUBSTITUTIONS``
|
||||
for more finegrained control
|
||||
* ``'{base_name}'`` value in ``PAGINATION_PATTERNS`` setting no longer strips
|
||||
``'bar'`` from ``'foo/bar.html'`` (unless ``'bar' == 'index'``).
|
||||
* ``ARTICLE_ORDER_BY`` and ``PAGE_ORDER_BY`` now also affect 1) category, tag
|
||||
and author pages 2) feeds 3) draft and hidden articles and pages
|
||||
* New ``ARTICLE_TRANSLATION_ID`` and ``PAGE_TRANSLATION_ID`` settings to
|
||||
specify metadata attributes used to identify/disable translations
|
||||
* Make the HTML reader parse multiple occurrences of metadata tags as a list
|
||||
* New Blogger XML backup importer
|
||||
* Wordpress importer now updates file links to point to local copies if the
|
||||
files were downloaded with ``--wp-attach``.
|
||||
* Importer no longer inserts extra newlines, to prevent breaking of HTML
|
||||
attributes.
|
||||
* Pelican server now prioritises ``foo.html`` and ``foo/index.html`` over
|
||||
``foo/`` when resolving ``foo``.
|
||||
|
||||
3.7.1 (2017-01-10)
|
||||
==================
|
||||
|
||||
* Fix locale issues in Quickstart script
|
||||
* Specify encoding for README and CHANGELOG in setup.py
|
||||
|
||||
3.7.0 (2016-12-12)
|
||||
==================
|
||||
|
||||
* Atom feeds output ``<content>`` in addition to ``<summary>``
|
||||
* Atom feeds use ``<published>`` for the original publication date and
|
||||
``<updated>`` for modifications
|
||||
* Simplify Atom feed ID generation and support URL fragments
|
||||
* Produce category feeds with category-specific titles
|
||||
* RSS feeds now default to summary instead of full content;
|
||||
set ``RSS_FEED_SUMMARY_ONLY = False`` to revert to previous behavior
|
||||
* Replace ``MD_EXTENSIONS`` with ``MARKDOWN`` setting
|
||||
* Replace ``JINJA_EXTENSIONS`` with more-robust ``JINJA_ENVIRONMENT`` setting
|
||||
* Improve summary truncation logic to handle special characters and tags that
|
||||
span multiple lines, using HTML parser instead of regular expressions
|
||||
* Include summary when looking for intra-site link substitutions
|
||||
* Link to authors and index via ``{author}name`` and ``{index}`` syntax
|
||||
* Override widget names via ``LINKS_WIDGET_NAME`` and ``SOCIAL_WIDGET_NAME``
|
||||
* Add ``INDEX_SAVE_AS`` option to override default ``index.html`` value
|
||||
* Remove ``PAGES`` context variable for themes in favor of ``pages``
|
||||
* ``SLUG_SUBSTITUTIONS`` now accepts 3-tuple elements, allowing URL slugs to
|
||||
contain non-alphanumeric characters
|
||||
* Tag and category slugs can be controlled with greater precision using the
|
||||
``TAG_SUBSTITUTIONS`` and ``CATEGORY_SUBSTITUTIONS`` settings
|
||||
* Author slugs can be controlled with greater precision using the
|
||||
``AUTHOR_SUBSTITUTIONS`` setting
|
||||
* ``DEFAULT_DATE`` can be defined as a string
|
||||
* Use ``mtime`` instead of ``ctime`` when ``DEFAULT_DATE = 'fs'``
|
||||
* Add ``--fatal=errors|warnings`` option for use with continuous integration
|
||||
* When using generator-level caching, ensure previously-cached files are
|
||||
processed instead of just new files.
|
||||
* Add Python and Pelican version information to debug output
|
||||
* Improve compatibility with Python 3.5
|
||||
* Comply with and enforce PEP8 guidelines
|
||||
* Replace tables in settings documentation with ``data::`` directives
|
||||
|
||||
3.6.3 (2015-08-14)
|
||||
==================
|
||||
|
||||
* Fix permissions issue in release tarball
|
||||
|
||||
3.6.2 (2015-08-01)
|
||||
==================
|
||||
|
||||
* Fix installation errors related to Unicode in tests
|
||||
* Don't show pagination in ``notmyidea`` theme if there's only one page
|
||||
* Make hidden pages available in context
|
||||
* Improve URLWrapper comparison
|
||||
|
||||
3.6.0 (2015-06-15)
|
||||
==================
|
||||
|
||||
* Disable caching by default in order to prevent potential confusion
|
||||
* Improve caching behavior, replacing ``pickle`` with ``cpickle``
|
||||
* Allow Markdown or reST content in metadata fields other than ``summary``
|
||||
* Support semicolon-separated author/tag lists
|
||||
* Improve flexibility of article sorting
|
||||
* Add ``--relative-urls`` argument
|
||||
* Support devserver listening on addresses other than localhost
|
||||
* Unify HTTP server handlers to ``pelican.server`` throughout
|
||||
* Handle intra-site links to draft posts
|
||||
* Move ``tag_cloud`` from core to plugin
|
||||
* Load default theme's external resources via HTTPS
|
||||
* Import drafts from WordPress XML
|
||||
* Improve support for Windows users
|
||||
* Enhance logging and test suite
|
||||
* Clean up and refactor codebase
|
||||
* New signals: ``all_generators_finalized`` and ``page_writer_finalized``
|
||||
|
||||
3.5.0 (2014-11-04)
|
||||
==================
|
||||
|
||||
* Introduce ``ARTICLE_ORDER_BY`` and ``PAGE_ORDER_BY`` settings to control the
|
||||
order of articles and pages.
|
||||
* Include time zone information in dates rendered in templates.
|
||||
* Expose the reader name in the metadata for articles and pages.
|
||||
* Add the ability to store static files along with content in the same
|
||||
directory as articles and pages using ``{attach}`` in the path.
|
||||
* Prevent Pelican from raising an exception when there are duplicate pieces of
|
||||
metadata in a Markdown file.
|
||||
* Introduce the ``TYPOGRIFY_IGNORE_TAGS`` setting to add HTML tags to be
|
||||
ignored by Typogrify.
|
||||
* Add the ability to use ``-`` in date formats to strip leading zeros. For
|
||||
example, ``%-d/%-m/%y`` will now result in the date ``9/8/12``.
|
||||
* Ensure feed generation is correctly disabled during quickstart configuration.
|
||||
* Fix ``PAGE_EXCLUDES`` and ``ARTICLE_EXCLUDES`` from incorrectly matching
|
||||
sub-directories.
|
||||
* Introduce ``STATIC_EXCLUDE`` setting to add static file excludes.
|
||||
* Fix an issue when using ``PAGINATION_PATTERNS`` while ``RELATIVE_URLS``
|
||||
is enabled.
|
||||
* Fix feed generation causing links to use the wrong language for month
|
||||
names when using other locales.
|
||||
* Fix an issue where the authors list in the simple template wasn't correctly
|
||||
formatted.
|
||||
* Fix an issue when parsing non-string URLs from settings.
|
||||
* Improve consistency of debug and warning messages.
|
||||
|
||||
3.4.0 (2014-07-01)
|
||||
==================
|
||||
|
||||
* Speed up content generation via new caching mechanism
|
||||
* Add selective post generation (instead of always building entire site)
|
||||
* Many documentation improvements, including switching to prettier RtD theme
|
||||
* Add support for multiple content and plugin paths
|
||||
* Add ``:modified:`` metadata field to complement ``:date:``.
|
||||
Used to specify the last date and time an article was updated independently
|
||||
from the date and time it was published.
|
||||
* Add support for multiple authors via new ``:authors:`` metadata field
|
||||
* Watch for changes in static directories when in auto-regeneration mode
|
||||
* Add filters to limit log output when desired
|
||||
* Add language support to drafts
|
||||
* Add ``SLUGIFY_SOURCE`` setting to control how post slugs are generated
|
||||
* Fix many issues relating to locale and encoding
|
||||
* Apply Typogrify filter to post summary
|
||||
* Preserve file metadata (e.g. time stamps) when copying static files to output
|
||||
* Move AsciiDoc support from Pelican core into separate plugin
|
||||
* Produce inline links instead of reference-style links when importing content
|
||||
* Improve handling of ``IGNORE_FILES`` setting behavior
|
||||
* Properly escape symbol characters in tag names (e.g., ``C++``)
|
||||
* Minor tweaks for Python 3.4 compatibility
|
||||
* Add several new signals
|
||||
|
||||
3.3.0 (2013-09-24)
|
||||
==================
|
||||
|
||||
* Drop Python 3.2 support in favor of Python 3.3
|
||||
* Add ``Fabfile`` so Fabric can be used for workflow automation instead of Make
|
||||
* ``OUTPUT_RETENTION`` setting can be used to preserve metadata (e.g., VCS
|
||||
data such as ``.hg`` and ``.git``) from being removed from output directory
|
||||
* Tumblr import
|
||||
* Improve logic and consistency when cleaning output folder
|
||||
* Improve documentation versioning and release automation
|
||||
* Improve pagination flexibility
|
||||
* Rename signals for better consistency (some plugins may need to be updated)
|
||||
* Move metadata extraction from generators to readers; metadata extraction no
|
||||
longer article-specific
|
||||
* Deprecate ``FILES_TO_COPY`` in favor of ``STATIC_PATHS`` and
|
||||
``EXTRA_PATH_METADATA``
|
||||
* Summaries in Markdown posts no longer include footnotes
|
||||
* Remove unnecessary whitespace in output via ``lstrip_blocks`` Jinja parameter
|
||||
* Move PDF generation from core to plugin
|
||||
* Replace ``MARKUP`` setting with ``READERS``
|
||||
* Add warning if img tag is missing ``alt`` attribute
|
||||
* Add support for ``{}`` in relative links syntax, besides ``||``
|
||||
* Add support for ``{tag}`` and ``{category}`` relative links
|
||||
* Add a ``content_written`` signal
|
||||
|
||||
3.2.1 and 3.2.2
|
||||
===============
|
||||
|
||||
* Facilitate inclusion in FreeBSD Ports Collection
|
||||
|
||||
3.2 (2013-04-24)
|
||||
================
|
||||
|
||||
* Support for Python 3!
|
||||
* Override page save-to location from meta-data (enables using a static page as
|
||||
the site's home page, for example)
|
||||
* Time period archives (per-year, per-month, and per-day archives of posts)
|
||||
* Posterous blog import
|
||||
* Improve WordPress blog import
|
||||
* Migrate plugins to separate repository
|
||||
* Improve HTML parser
|
||||
* Provide ability to show or hide categories from menu using
|
||||
``DISPLAY_CATEGORIES_ON_MENU`` option
|
||||
* Auto-regeneration can be told to ignore files via ``IGNORE_FILES`` setting
|
||||
* Improve post-generation feedback to user
|
||||
* For multilingual posts, use meta-data to designate which is the original
|
||||
and which is the translation
|
||||
* Add ``.mdown`` to list of supported Markdown file extensions
|
||||
* Document-relative URL generation (``RELATIVE_URLS``) is now off by default
|
||||
|
||||
3.1 (2012-12-04)
|
||||
================
|
||||
|
||||
* Importer now stores slugs within files by default. This can be disabled with
|
||||
the ``--disable-slugs`` option.
|
||||
* Improve handling of links to intra-site resources
|
||||
* Ensure WordPress import adds paragraphs for all types of line endings
|
||||
in post content
|
||||
* Decode HTML entities within WordPress post titles on import
|
||||
* Improve appearance of LinkedIn icon in default theme
|
||||
* Add GitHub and Google+ social icons support in default theme
|
||||
* Optimize social icons
|
||||
* Add ``FEED_ALL_ATOM`` and ``FEED_ALL_RSS`` to generate feeds containing all
|
||||
posts regardless of their language
|
||||
* Split ``TRANSLATION_FEED`` into ``TRANSLATION_FEED_ATOM`` and
|
||||
``TRANSLATION_FEED_RSS``
|
||||
* Different feeds can now be enabled/disabled individually
|
||||
* Allow for blank author: if ``AUTHOR`` setting is not set, author won't
|
||||
default to ``${USER}`` anymore, and a post won't contain any author
|
||||
information if the post author is empty
|
||||
* Move LESS and Webassets support from Pelican core to plugin
|
||||
* The ``DEFAULT_DATE`` setting now defaults to ``None``, which means that
|
||||
articles won't be generated unless date metadata is specified
|
||||
* Add ``FILENAME_METADATA`` setting to support metadata extraction from
|
||||
filename
|
||||
* Add ``gzip_cache`` plugin to compress common text files into a ``.gz``
|
||||
file within the same directory as the original file, preventing the server
|
||||
(e.g. Nginx) from having to compress files during an HTTP call
|
||||
* Add support for AsciiDoc-formatted content
|
||||
* Add ``USE_FOLDER_AS_CATEGORY`` setting so that feature can be toggled on/off
|
||||
* Support arbitrary Jinja template files
|
||||
* Restore basic functional tests
|
||||
* New signals: ``generator_init``, ``get_generators``, and
|
||||
``article_generate_preread``
|
||||
|
||||
3.0 (2012-08-08)
|
||||
================
|
||||
|
||||
* Refactored the way URLs are handled
|
||||
* Improved the English documentation
|
||||
* Fixed packaging using ``setuptools`` entrypoints
|
||||
* Added ``typogrify`` support
|
||||
* Added a way to disable feed generation
|
||||
* Added support for ``DIRECT_TEMPLATES``
|
||||
* Allow multiple extensions for content files
|
||||
* Added LESS support
|
||||
* Improved the import script
|
||||
* Added functional tests
|
||||
* Rsync support in the generated Makefile
|
||||
* Improved feed support (easily pluggable with Feedburner for instance)
|
||||
* Added support for ``abbr`` in reST
|
||||
* Fixed a bunch of bugs :-)
|
||||
|
||||
2.8 (2012-02-28)
|
||||
==================
|
||||
|
||||
* Dotclear importer
|
||||
* Allow the usage of Markdown extensions
|
||||
* Themes are now easily extensible
|
||||
* Don't output pagination information if there is only one page
|
||||
* Add a page per author, with all their articles
|
||||
* Improved the test suite
|
||||
* Made the themes easier to extend
|
||||
* Removed Skribit support
|
||||
* Added a ``pelican-quickstart`` script
|
||||
* Fixed timezone-related issues
|
||||
* Added some scripts for Windows support
|
||||
* Date can be specified in seconds
|
||||
* Never fail when generating posts (skip and continue)
|
||||
* Allow the use of future dates
|
||||
* Support having different timezones per language
|
||||
* Enhanced the documentation
|
||||
|
||||
2.7 (2011-06-11)
|
||||
==================
|
||||
|
||||
* Use ``logging`` rather than echoing to stdout
|
||||
* Support custom Jinja filters
|
||||
* Compatibility with Python 2.5
|
||||
* Added a theme manager
|
||||
* Packaged for Debian
|
||||
* Added draft support
|
||||
|
||||
2.6 (2011-03-08)
|
||||
==================
|
||||
|
||||
* Changes in the output directory structure
|
||||
* Makes templates easier to work with / create
|
||||
* Added RSS support (was Atom-only)
|
||||
* Added tag support for the feeds
|
||||
* Enhance the documentation
|
||||
* Added another theme (brownstone)
|
||||
* Added translations
|
||||
* Added a way to use cleaner URLs with a rewrite url module (or equivalent)
|
||||
* Added a tag cloud
|
||||
* Added an autoreloading feature: the blog is automatically regenerated each
|
||||
time a modification is detected
|
||||
* Translate the documentation into French
|
||||
* Import a blog from an RSS feed
|
||||
* Pagination support
|
||||
* Added Skribit support
|
||||
|
||||
2.5 (2010-11-20)
|
||||
==================
|
||||
|
||||
* Import from WordPress
|
||||
* Added some new themes (martyalchin / wide-notmyidea)
|
||||
* First bug report!
|
||||
* Linkedin support
|
||||
* Added a FAQ
|
||||
* Google Analytics support
|
||||
* Twitter support
|
||||
* Use relative URLs, not static ones
|
||||
|
||||
2.4 (2010-11-06)
|
||||
================
|
||||
|
||||
* Minor themes changes
|
||||
* Add Disqus support (so we have comments)
|
||||
* Another code refactoring
|
||||
* Added config settings about pages
|
||||
* Blog entries can also be generated in PDF
|
||||
|
||||
2.3 (2010-10-31)
|
||||
================
|
||||
|
||||
* Markdown support
|
||||
|
||||
2.2 (2010-10-30)
|
||||
================
|
||||
|
||||
* Prettify output
|
||||
* Manages static pages as well
|
||||
|
||||
2.1 (2010-10-30)
|
||||
================
|
||||
|
||||
* Make notmyidea the default theme
|
||||
|
||||
2.0 (2010-10-30)
|
||||
================
|
||||
|
||||
* Refactoring to be more extensible
|
||||
* Change into the setting variables
|
||||
|
||||
1.2 (2010-09-28)
|
||||
================
|
||||
|
||||
* Added a debug option
|
||||
* Added per-category feeds
|
||||
* Use filesystem to get dates if no metadata is provided
|
||||
* Add Pygments support
|
||||
|
||||
1.1 (2010-08-19)
|
||||
================
|
||||
|
||||
* First working version
|
||||
203
docs/conf.py
203
docs/conf.py
|
|
@ -1,149 +1,102 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys, os
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
# sys.path.insert(0, os.path.abspath('..'))
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
import tomli as tomllib
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
project = u'Pelican'
|
||||
copyright = u'2010, Alexis Metaireau'
|
||||
exclude_patterns = ['_build']
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
sys.path.append(os.path.abspath(os.pardir))
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
sys.path.append(os.path.abspath('_themes'))
|
||||
html_theme_path = ['_themes']
|
||||
html_theme = 'flask_small'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
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"]
|
||||
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]}
|
||||
"""
|
||||
|
||||
extlinks = {"pelican-doc": ("https://docs.getpelican.com/en/latest/%s.html", "%s")}
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
html_theme = "furo"
|
||||
html_title = f"<strong>{project}</strong> <i>{release}</i>"
|
||||
html_static_path = ["_static"]
|
||||
html_theme_options = {
|
||||
'index_logo': 'pelican.png',
|
||||
'github_fork': 'ametaireau/pelican',
|
||||
"light_logo": "pelican-logo.svg",
|
||||
"dark_logo": "pelican-logo.svg",
|
||||
"navigation_with_keys": True,
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = "Pelicandoc"
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
html_use_smartypants = True
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
html_use_modindex = False
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
html_use_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Raclettedoc'
|
||||
html_show_sourcelink = False
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
def setup(app):
|
||||
# overrides for wide tables in RTD theme
|
||||
app.add_css_file("theme_overrides.css") # path relative to _static
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
# -- Options for LaTeX output -------------------------------------------------
|
||||
latex_documents = [
|
||||
('index', 'Raclette.tex', u'Raclette Documentation',
|
||||
u'Alexis Métaireau', 'manual'),
|
||||
("index", "Pelican.tex", "Pelican Documentation", "Justin Mayer", "manual"),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
# -- Options for manual page output -------------------------------------------
|
||||
man_pages = [
|
||||
('index', 'raclette', u'Raclette Documentation',
|
||||
[u'Alexis Métaireau'], 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,
|
||||
),
|
||||
]
|
||||
|
|
|
|||
652
docs/content.rst
Normal file
652
docs/content.rst
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
Writing content
|
||||
###############
|
||||
|
||||
Articles and pages
|
||||
==================
|
||||
|
||||
Pelican considers "articles" to be chronological content, such as posts on a
|
||||
blog, and thus associated with a date.
|
||||
|
||||
The idea behind "pages" is that they are usually not temporal in nature and are
|
||||
used for content that does not change very often (e.g., "About" or "Contact"
|
||||
pages).
|
||||
|
||||
You can find sample content in the repository at ``samples/content/``.
|
||||
|
||||
.. _internal_metadata:
|
||||
|
||||
File metadata
|
||||
=============
|
||||
|
||||
Pelican tries to be smart enough to get the information it needs from the
|
||||
file system (for instance, about the category of your articles), but some
|
||||
information you need to provide in the form of metadata inside your files.
|
||||
|
||||
If you are writing your content in reStructuredText format, you can provide
|
||||
this metadata in text files via the following syntax (give your file the
|
||||
``.rst`` extension)::
|
||||
|
||||
My super title
|
||||
##############
|
||||
|
||||
:date: 2010-10-03 10:20
|
||||
:modified: 2010-10-04 18:40
|
||||
:tags: thats, awesome
|
||||
:category: yeah
|
||||
:slug: my-super-post
|
||||
:authors: Alexis Metaireau, Conan Doyle
|
||||
:summary: Short version for index and feeds
|
||||
|
||||
Author and tag lists may be semicolon-separated instead, which allows
|
||||
you to write authors and tags containing commas::
|
||||
|
||||
:tags: pelican, publishing tool; pelican, bird
|
||||
:authors: Metaireau, Alexis; Doyle, Conan
|
||||
|
||||
Pelican implements an extension to reStructuredText to enable support for the
|
||||
``abbr`` HTML tag. To use it, write something like this in your post::
|
||||
|
||||
This will be turned into :abbr:`HTML (HyperText Markup Language)`.
|
||||
|
||||
You can also use Markdown syntax (with a file ending in ``.md``, ``.markdown``,
|
||||
``.mkd``, or ``.mdown``). Markdown generation requires that you first
|
||||
explicitly install the Python-Markdown_ package, which can be done via ``pip
|
||||
install Markdown``.
|
||||
|
||||
Pelican also supports `Markdown Extensions`_, which might have to be installed
|
||||
separately if they are not included in the default ``Markdown`` package and can
|
||||
be configured and loaded via the ``MARKDOWN`` setting.
|
||||
|
||||
Metadata syntax for Markdown posts should follow this pattern::
|
||||
|
||||
Title: My super title
|
||||
Date: 2010-12-03 10:20
|
||||
Modified: 2010-12-05 19:30
|
||||
Category: Python
|
||||
Tags: pelican, publishing
|
||||
Slug: my-super-post
|
||||
Authors: Alexis Metaireau, Conan Doyle
|
||||
Summary: Short version for index and feeds
|
||||
|
||||
This is the content of my super blog post.
|
||||
|
||||
You can also have your own metadata keys (so long as they don't conflict with
|
||||
reserved metadata keywords) for use in your templates. The following table
|
||||
contains a list of reserved metadata keywords:
|
||||
|
||||
=============== ===============================================================
|
||||
Metadata Description
|
||||
=============== ===============================================================
|
||||
``title`` Title of the article or page
|
||||
``date`` Publication date (e.g., ``YYYY-MM-DD HH:SS``)
|
||||
``modified`` Modification date (e.g., ``YYYY-MM-DD HH:SS``)
|
||||
``tags`` Content tags, separated by commas
|
||||
``keywords`` Content keywords, separated by commas (HTML content only)
|
||||
``category`` Content category (one only — not multiple)
|
||||
``slug`` Identifier used in URLs and translations
|
||||
``author`` Content author, when there is only one
|
||||
``authors`` Content authors, when there are multiple
|
||||
``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``, ``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,
|
||||
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
|
||||
``meta`` tags, the title from the ``title`` tag, and the body out from the
|
||||
``body`` tag::
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>My super title</title>
|
||||
<meta name="tags" content="thats, awesome" />
|
||||
<meta name="date" content="2012-07-09 22:28" />
|
||||
<meta name="modified" content="2012-07-10 20:14" />
|
||||
<meta name="category" content="yeah" />
|
||||
<meta name="authors" content="Alexis Métaireau, Conan Doyle" />
|
||||
<meta name="summary" content="Short version for index and feeds" />
|
||||
</head>
|
||||
<body>
|
||||
This is the content of my super blog post.
|
||||
</body>
|
||||
</html>
|
||||
|
||||
With HTML, there is one simple exception to the standard metadata: tags can be
|
||||
specified either via the ``tags`` metadata, as is standard in Pelican, or via
|
||||
the ``keywords`` metadata, as is standard in HTML. The two can be used
|
||||
interchangeably.
|
||||
|
||||
Note that, aside from the title, none of this content metadata is mandatory:
|
||||
if the date is not specified and ``DEFAULT_DATE`` is set to ``'fs'``, Pelican
|
||||
will rely on the file's "mtime" timestamp, and the category can be determined
|
||||
by the directory in which the file resides. For example, a file located at
|
||||
``python/foobar/myfoobar.rst`` will have a category of ``foobar``. If you would
|
||||
like to organize your files in other ways where the name of the subfolder would
|
||||
not be a good category name, you can set the setting ``USE_FOLDER_AS_CATEGORY``
|
||||
to ``False``. When parsing dates given in the page metadata, Pelican supports
|
||||
the W3C's `suggested subset ISO 8601`__.
|
||||
|
||||
So the title is the only required metadata. If that bothers you, worry not.
|
||||
Instead of manually specifying a title in your metadata each time, you can use
|
||||
the source content file name as the title. For example, a Markdown source file
|
||||
named ``Publishing via Pelican.md`` would automatically be assigned a title of
|
||||
*Publishing via Pelican*. If you would prefer this behavior, add the following
|
||||
line to your settings file::
|
||||
|
||||
FILENAME_METADATA = '(?P<title>.*)'
|
||||
|
||||
.. note::
|
||||
|
||||
When experimenting with different settings (especially the metadata
|
||||
ones) 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.
|
||||
|
||||
__ `W3C ISO 8601`_
|
||||
|
||||
``modified`` should be last time you updated the article, and defaults to
|
||||
``date`` if not specified. Besides you can show ``modified`` in the templates,
|
||||
feed entries in feed readers will be updated automatically when you set
|
||||
``modified`` to the current date after you modified your article.
|
||||
|
||||
``authors`` is a comma-separated list of article authors. If there's only one
|
||||
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. 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
|
||||
that are matched will be set in the metadata object. The default value for the
|
||||
``FILENAME_METADATA`` setting will only extract the date from the filename. For
|
||||
example, if you would like to extract both the date and the slug, you could set
|
||||
something like: ``'(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)'``
|
||||
|
||||
Please note that the metadata available inside your files takes precedence over
|
||||
the metadata extracted from the filename.
|
||||
|
||||
Pages
|
||||
=====
|
||||
|
||||
If you create a folder named ``pages`` inside the content folder, all the
|
||||
files in it will be used to generate static pages, such as **About** or
|
||||
**Contact** pages. (See example filesystem layout below.)
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
Static content
|
||||
==============
|
||||
|
||||
Static files are files other than articles and pages that are copied to the
|
||||
output folder as-is, without processing. You can control which static files
|
||||
are copied over with the ``STATIC_PATHS`` setting of the project's
|
||||
``pelicanconf.py`` file. Pelican's default configuration includes the
|
||||
``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
|
||||
-----------------------------------
|
||||
|
||||
Starting with Pelican 3.5, static files can safely share a source directory
|
||||
with page source files, without exposing the page sources in the generated
|
||||
site. Any such directory must be added to both ``STATIC_PATHS`` and
|
||||
``PAGE_PATHS`` (or ``STATIC_PATHS`` and ``ARTICLE_PATHS``). Pelican will
|
||||
identify and process the page source files normally, and copy the remaining
|
||||
files as if they lived in a separate directory reserved for static files.
|
||||
|
||||
Note: Placing static and content source files together in the same source
|
||||
directory does not guarantee that they will end up in the same place in the
|
||||
generated site. The easiest way to do this is by using the ``{attach}`` link
|
||||
syntax (described below). Alternatively, the ``STATIC_SAVE_AS``,
|
||||
``PAGE_SAVE_AS``, and ``ARTICLE_SAVE_AS`` settings (and the corresponding
|
||||
``*_URL`` settings) can be configured to place files of different types
|
||||
together, just as they could in earlier versions of Pelican.
|
||||
|
||||
.. _ref-linking-to-internal-content:
|
||||
|
||||
Linking to internal content
|
||||
===========================
|
||||
|
||||
From Pelican 3.1 onwards, it is now possible to specify intra-site links to
|
||||
files in the *source content* hierarchy instead of files in the *generated*
|
||||
hierarchy. This makes it easier to link from the current post to other content
|
||||
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``.
|
||||
Note: forward slashes, ``/``,
|
||||
are the required path separator in the ``{filename}`` directive
|
||||
on all operating systems, including Windows.
|
||||
|
||||
For example, a Pelican project might be structured like this::
|
||||
|
||||
website/
|
||||
├── content
|
||||
│ ├── category/
|
||||
│ │ └── article1.rst
|
||||
│ ├── article2.md
|
||||
│ └── pages
|
||||
│ └── about.md
|
||||
└── pelican.conf.py
|
||||
|
||||
In this example, ``article1.rst`` could look like this::
|
||||
|
||||
The first article
|
||||
#################
|
||||
|
||||
:date: 2012-12-01 10:02
|
||||
|
||||
See below intra-site link examples in reStructuredText format.
|
||||
|
||||
`a link relative to the current file <{filename}../article2.md>`_
|
||||
`a link relative to the content root <{filename}/article2.md>`_
|
||||
|
||||
and ``article2.md``::
|
||||
|
||||
Title: The second article
|
||||
Date: 2012-12-01 10:02
|
||||
|
||||
See below intra-site link examples in Markdown format.
|
||||
|
||||
[a link relative to the current file]({filename}category/article1.rst)
|
||||
[a link relative to the content root]({filename}/category/article1.rst)
|
||||
|
||||
Linking to static files
|
||||
-----------------------
|
||||
|
||||
You can link to static content using ``{static}path/to/file``. Files linked to
|
||||
with this syntax will automatically be copied to the output directory, even if
|
||||
the source directories containing them are not included in the ``STATIC_PATHS``
|
||||
setting of the project's ``pelicanconf.py`` file.
|
||||
|
||||
For example, a project's content directory might be structured like this::
|
||||
|
||||
content
|
||||
├── images
|
||||
│ └── han.jpg
|
||||
├── pdfs
|
||||
│ └── menu.pdf
|
||||
└── pages
|
||||
└── test.md
|
||||
|
||||
``test.md`` would include::
|
||||
|
||||

|
||||
[Our Menu]({static}/pdfs/menu.pdf)
|
||||
|
||||
Site generation would then copy ``han.jpg`` to ``output/images/han.jpg``,
|
||||
``menu.pdf`` to ``output/pdfs/menu.pdf``, and write the appropriate links
|
||||
in ``test.md``.
|
||||
|
||||
If you use ``{static}`` to link to an article or a page, this will be turned
|
||||
into a link to its source code.
|
||||
|
||||
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
|
||||
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
|
||||
preserved on output. Otherwise, it will become a sibling of the linking
|
||||
document.
|
||||
|
||||
This only works for linking to static files.
|
||||
|
||||
For example, a project's content directory might be structured like this::
|
||||
|
||||
content
|
||||
├── blog
|
||||
│ ├── icons
|
||||
│ │ └── icon.png
|
||||
│ ├── photo.jpg
|
||||
│ └── testpost.md
|
||||
└── downloads
|
||||
└── archive.zip
|
||||
|
||||
``pelicanconf.py`` would include::
|
||||
|
||||
PATH = 'content'
|
||||
ARTICLE_PATHS = ['blog']
|
||||
ARTICLE_SAVE_AS = '{date:%Y}/{slug}.html'
|
||||
ARTICLE_URL = '{date:%Y}/{slug}.html'
|
||||
|
||||
``testpost.md`` would include::
|
||||
|
||||
Title: Test Post
|
||||
Category: test
|
||||
Date: 2014-10-31
|
||||
|
||||

|
||||

|
||||
[Downloadable File]({attach}/downloads/archive.zip)
|
||||
|
||||
Site generation would then produce an output directory structured like this::
|
||||
|
||||
output
|
||||
└── 2014
|
||||
├── archive.zip
|
||||
├── icons
|
||||
│ └── icon.png
|
||||
├── photo.jpg
|
||||
└── test-post.html
|
||||
|
||||
Notice that all the files linked using ``{attach}`` ended up in or beneath
|
||||
the article's output directory.
|
||||
|
||||
If a static file is linked multiple times, the relocating feature of
|
||||
``{attach}`` will only work in the first of those links to be processed.
|
||||
After the first link, Pelican will treat ``{attach}`` like ``{static}``.
|
||||
This avoids breaking the already-processed links.
|
||||
|
||||
**Be careful when linking to a file from multiple documents:**
|
||||
Since the first link to a file finalizes its location and Pelican does
|
||||
not define the order in which documents are processed, using ``{attach}`` on a
|
||||
file linked by multiple documents can cause its location to change from one
|
||||
site build to the next. (Whether this happens in practice will depend on the
|
||||
operating system, file system, version of Pelican, and documents being added,
|
||||
modified, or removed from the project.) Any external sites linking to the
|
||||
file's old location might then find their links broken. **It is therefore
|
||||
advisable to use {attach} only if you use it in all links to a file, and only
|
||||
if the linking documents share a single directory.** Under these conditions,
|
||||
the file's output location will not change in future builds. In cases where
|
||||
these precautions are not possible, consider using ``{static}`` links instead
|
||||
of ``{attach}``, and letting the file's location be determined by the project's
|
||||
``STATIC_SAVE_AS`` and ``STATIC_URL`` settings. (Per-file ``save_as`` and
|
||||
``url`` overrides can still be set in ``EXTRA_PATH_METADATA``.)
|
||||
|
||||
.. note::
|
||||
When using ``{attach}``, any parent directory in ``*_URL`` / ``*_SAVE_AS``
|
||||
settings should match each other. See also: :ref:`url-settings`
|
||||
|
||||
Linking to authors, categories, index and tags
|
||||
----------------------------------------------
|
||||
|
||||
You can link to authors, categories, index and tags using the ``{author}name``,
|
||||
``{category}foobar``, ``{index}`` and ``{tag}tagname`` syntax.
|
||||
|
||||
Deprecated internal link syntax
|
||||
-------------------------------
|
||||
|
||||
To remain compatible with earlier versions, Pelican still supports vertical
|
||||
bars (``||``) in addition to curly braces (``{}``) for internal links. For
|
||||
example: ``|filename|an_article.rst``, ``|tag|tagname``, ``|category|foobar``.
|
||||
The syntax was changed from ``||`` to ``{}`` to avoid collision with Markdown
|
||||
extensions or reST directives. Similarly, Pelican also still supports linking
|
||||
to static content with ``{filename}``. The syntax was changed to ``{static}``
|
||||
to allow linking to both generated articles and pages and their static sources.
|
||||
|
||||
Support for the old syntax may eventually be removed.
|
||||
|
||||
Including other files
|
||||
---------------------
|
||||
Both Markdown and reStructuredText syntaxes provide mechanisms for this.
|
||||
|
||||
Following below are some examples for **reStructuredText** using `the include directive`_:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. include:: file.rst
|
||||
|
||||
Include a fragment of a file delimited by two identifiers, highlighted as C++ (slicing based on line numbers is also possible):
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. include:: main.cpp
|
||||
:code: c++
|
||||
:start-after: // begin
|
||||
:end-before: // end
|
||||
|
||||
Include a raw HTML file (or an inline SVG) and put it directly into the output without any processing:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. raw:: html
|
||||
:file: table.html
|
||||
|
||||
For **Markdown**, one must rely on an extension. For example, using the `mdx_include plugin`_:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
```html
|
||||
{! template.html !}
|
||||
```
|
||||
|
||||
|
||||
Importing an existing site
|
||||
==========================
|
||||
|
||||
It is possible to import your site from several other blogging sites
|
||||
(like WordPress, Tumblr, ..) using a simple script. See :ref:`import`.
|
||||
|
||||
Translations
|
||||
============
|
||||
|
||||
It is possible to translate articles. To do so, you need to add a ``lang`` meta
|
||||
attribute to your articles/pages and set a ``DEFAULT_LANG`` setting (which is
|
||||
English [en] by default). With those settings in place, only articles with the
|
||||
default language will be listed, and each article will be accompanied by a list
|
||||
of available translations for that article.
|
||||
|
||||
.. note::
|
||||
|
||||
This core Pelican functionality does not create sub-sites
|
||||
(e.g. ``example.com/de``) with translated templates for each
|
||||
language. For such advanced functionality the `i18n_subsites
|
||||
plugin`_ can be used.
|
||||
|
||||
By default, Pelican uses the article's URL "slug" to determine if two or more
|
||||
articles are translations of one another. (This can be changed with the
|
||||
``ARTICLE_TRANSLATION_ID`` setting.) The slug can be set manually in the file's
|
||||
metadata; if not set explicitly, Pelican will auto-generate the slug from the
|
||||
title of the article.
|
||||
|
||||
Here is an example of two articles, one in English and the other in French.
|
||||
|
||||
The English article::
|
||||
|
||||
Foobar is not dead
|
||||
##################
|
||||
|
||||
:slug: foobar-is-not-dead
|
||||
:lang: en
|
||||
|
||||
That's true, foobar is still alive!
|
||||
|
||||
And the French version::
|
||||
|
||||
Foobar n'est pas mort !
|
||||
#######################
|
||||
|
||||
:slug: foobar-is-not-dead
|
||||
:lang: fr
|
||||
|
||||
Oui oui, foobar est toujours vivant !
|
||||
|
||||
Post content quality notwithstanding, you can see that only item in common
|
||||
between the two articles is the slug, which is functioning here as an
|
||||
identifier. If you'd rather not explicitly define the slug this way, you must
|
||||
then instead ensure that the translated article titles are identical, since the
|
||||
slug will be auto-generated from the article title.
|
||||
|
||||
If you do not want the original version of one specific article to be detected
|
||||
by the ``DEFAULT_LANG`` setting, use the ``translation`` metadata to specify
|
||||
which posts are translations::
|
||||
|
||||
Foobar is not dead
|
||||
##################
|
||||
|
||||
:slug: foobar-is-not-dead
|
||||
:lang: en
|
||||
:translation: true
|
||||
|
||||
That's true, foobar is still alive!
|
||||
|
||||
|
||||
.. _internal_pygments_options:
|
||||
|
||||
Syntax highlighting
|
||||
===================
|
||||
|
||||
Pelican can provide colorized syntax highlighting for your code blocks.
|
||||
To do so, you must use the following conventions inside your content files.
|
||||
|
||||
For reStructuredText, use the ``code-block`` directive to specify the type
|
||||
of code to be highlighted (in these examples, we'll use ``python``)::
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
print("Pelican is a static site generator.")
|
||||
|
||||
For Markdown, which utilizes the `CodeHilite extension`_ to provide syntax
|
||||
highlighting, include the language identifier just above the code block,
|
||||
indenting both the identifier and the code::
|
||||
|
||||
There are two ways to specify the identifier:
|
||||
|
||||
:::python
|
||||
print("The triple-colon syntax will *not* show line numbers.")
|
||||
|
||||
To display line numbers, use a path-less shebang instead of colons:
|
||||
|
||||
#!python
|
||||
print("The path-less shebang syntax *will* show line numbers.")
|
||||
|
||||
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:
|
||||
|
||||
============= ============ =========================================
|
||||
Option Valid values Description
|
||||
============= ============ =========================================
|
||||
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
|
||||
by a space. This is similar to
|
||||
``emphasize-lines`` in Sphinx, but it
|
||||
does not support a range of line numbers
|
||||
separated by a hyphen, or comma-separated
|
||||
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
|
||||
do not output the line numbers for this
|
||||
table.
|
||||
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
|
||||
the wrapping element
|
||||
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.
|
||||
============= ============ =========================================
|
||||
|
||||
Note that, depending on the version, your Pygments module might not have
|
||||
all of these options available. Refer to the *HtmlFormatter* section of the
|
||||
`Pygments documentation <https://pygments.org/docs/formatters/>`_ for more
|
||||
details on each of the options.
|
||||
|
||||
For example, the following code block enables line numbers, starting at 153,
|
||||
and prefixes the Pygments CSS classes with *pgcss* to make the names
|
||||
more unique and avoid possible CSS conflicts::
|
||||
|
||||
.. code-block:: identifier
|
||||
:classprefix: pgcss
|
||||
:linenos: table
|
||||
:linenostart: 153
|
||||
|
||||
<indented code block goes here>
|
||||
|
||||
It is also possible to specify the ``PYGMENTS_RST_OPTIONS`` variable in your
|
||||
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::
|
||||
|
||||
PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'}
|
||||
|
||||
If specified, settings for individual code blocks will override the defaults in
|
||||
your settings file.
|
||||
|
||||
Publishing drafts
|
||||
=================
|
||||
|
||||
If you want to publish an article or a page as a draft (for friends to review
|
||||
before publishing, for example), you can add a ``Status: draft`` attribute to
|
||||
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
|
||||
the ``DEFAULT_METADATA``::
|
||||
|
||||
DEFAULT_METADATA = {
|
||||
'status': 'draft',
|
||||
}
|
||||
|
||||
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://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/
|
||||
.. _CodeHilite extension: https://python-markdown.github.io/extensions/code_hilite/#syntax
|
||||
.. _i18n_subsites plugin: https://github.com/getpelican/pelican-plugins/tree/master/i18n_subsites
|
||||
.. _the include directive: http://docutils.sourceforge.net/docs/ref/rst/directives.html#include
|
||||
.. _mdx_include plugin: https://github.com/neurobin/mdx_include
|
||||
299
docs/contribute.rst
Normal file
299
docs/contribute.rst
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
Contributing and feedback guidelines
|
||||
####################################
|
||||
|
||||
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>`_.
|
||||
|
||||
Don't hesitate to fork Pelican and submit an issue or pull request on GitHub.
|
||||
When doing so, please consider the following guidelines.
|
||||
|
||||
.. include:: ../CONTRIBUTING.rst
|
||||
|
||||
Setting up the development environment
|
||||
======================================
|
||||
|
||||
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.
|
||||
|
||||
Please note that Python |min_python| is required for Pelican development.
|
||||
|
||||
*(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://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
|
||||
as a Git remote::
|
||||
|
||||
mkdir ~/projects
|
||||
git clone https://github.com/YOUR_USERNAME/pelican.git ~/projects/pelican
|
||||
cd ~/projects/pelican
|
||||
git remote add upstream https://github.com/getpelican/pelican.git
|
||||
|
||||
While PDM can dynamically create and manage virtual environments, we're going
|
||||
to manually create and activate a virtual environment::
|
||||
|
||||
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
|
||||
|
||||
Your local environment should now be ready to go!
|
||||
|
||||
.. _Pip: https://pip.pypa.io/
|
||||
.. _PDM: https://pdm.fming.dev/latest/
|
||||
.. _Pelican repository: https://github.com/getpelican/pelican
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
Once Pelican has been set up for local development, create a topic branch for
|
||||
your bug fix or feature::
|
||||
|
||||
git checkout -b name-of-your-bugfix-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
|
||||
----------------------
|
||||
|
||||
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::
|
||||
|
||||
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 ``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
|
||||
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::
|
||||
|
||||
invoke update-functional-tests
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
.. _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
|
||||
-----------------
|
||||
|
||||
If you make changes to the documentation, you should build and inspect your
|
||||
changes before committing them::
|
||||
|
||||
invoke docserve
|
||||
|
||||
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.
|
||||
|
||||
Plugin development
|
||||
------------------
|
||||
|
||||
To create a *new* Pelican plugin, please refer to the `plugin template`_
|
||||
repository for detailed instructions.
|
||||
|
||||
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::
|
||||
|
||||
mkdir -p ~/projects/pelican-plugins
|
||||
|
||||
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::
|
||||
|
||||
git clone https://github.com/YOUR_USERNAME/simple-footnotes.git ~/projects/pelican-plugins/simple-footnotes
|
||||
cd ~/projects/pelican-plugins/simple-footnotes
|
||||
git remote add upstream https://github.com/pelican-plugins/simple-footnotes.git
|
||||
|
||||
Install the needed dependencies and set up the project::
|
||||
|
||||
invoke setup
|
||||
|
||||
Create a topic branch for your plugin bug fix or feature::
|
||||
|
||||
git checkout -b name-of-your-bugfix-or-feature
|
||||
|
||||
After writing new tests for your plugin changes, run the plugin test suite and
|
||||
check for code style compliance via::
|
||||
|
||||
invoke tests
|
||||
invoke lint
|
||||
|
||||
If style violations are found, many of them can be addressed automatically via::
|
||||
|
||||
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
|
||||
reports any code style violations.
|
||||
|
||||
.. _plugin template: https://github.com/getpelican/cookiecutter-pelican-plugin
|
||||
.. _Simple Footnotes: https://github.com/pelican-plugins/simple-footnotes
|
||||
|
||||
Submitting your changes
|
||||
-----------------------
|
||||
|
||||
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::
|
||||
|
||||
Release type: patch
|
||||
|
||||
Fix browser reloading upon changes to content, settings, or theme
|
||||
|
||||
Commit your changes and push your topic branch::
|
||||
|
||||
git add .
|
||||
git commit -m "Your detailed description of your changes"
|
||||
git push origin name-of-your-bugfix-or-feature
|
||||
|
||||
Finally, browse to your repository fork on GitHub and submit a pull request.
|
||||
|
||||
|
||||
Logging tips
|
||||
============
|
||||
|
||||
Try to use logging with appropriate levels.
|
||||
|
||||
For logging messages that are not repeated, use the usual Python way::
|
||||
|
||||
# at top of file
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# when needed
|
||||
logger.warning("A warning with %s formatting", arg_to_be_formatted)
|
||||
|
||||
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.
|
||||
|
||||
Limiting extraneous log messages
|
||||
--------------------------------
|
||||
|
||||
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::
|
||||
|
||||
logger.warning("A warning with %s formatting", arg_to_be_formatted,
|
||||
extra={'limit_msg': 'A generic message for too many warnings'})
|
||||
|
||||
Optionally, you can also set ``'limit_args'`` as a tuple of arguments in
|
||||
``extra`` dict if your generic message needs formatting.
|
||||
|
||||
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.
|
||||
|
||||
For example, if you want to log missing resources, use the following code::
|
||||
|
||||
for resource in resources:
|
||||
if resource.is_missing:
|
||||
logger.warning(
|
||||
'The resource %s is missing', resource.name,
|
||||
extra={'limit_msg': 'Other resources were missing'})
|
||||
|
||||
The log messages will be displayed as follows::
|
||||
|
||||
WARNING: The resource prettiest_cat.jpg is missing
|
||||
WARNING: The resource best_cat_ever.jpg is missing
|
||||
WARNING: The resource cutest_cat.jpg is missing
|
||||
WARNING: The resource lolcat.jpg is missing
|
||||
WARNING: Other resources were missing
|
||||
|
||||
|
||||
Outputting traceback in the logs
|
||||
--------------------------------
|
||||
|
||||
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::
|
||||
|
||||
try:
|
||||
some_action()
|
||||
except Exception as e:
|
||||
logger.error('Exception occurred: %s', e,
|
||||
exc_info=settings.get('DEBUG', False))
|
||||
299
docs/faq.rst
Normal file
299
docs/faq.rst
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
Frequently Asked Questions (FAQ)
|
||||
################################
|
||||
|
||||
Here are some frequently asked questions about Pelican.
|
||||
|
||||
What's the best way to communicate a problem, question, or suggestion?
|
||||
======================================================================
|
||||
|
||||
Please read our :doc:`feedback guidelines <contribute>`.
|
||||
|
||||
How can I help?
|
||||
===============
|
||||
|
||||
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
|
||||
<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.
|
||||
|
||||
You can also contribute by creating themes and improving the documentation.
|
||||
|
||||
Is the Pelican settings file mandatory?
|
||||
=======================================
|
||||
|
||||
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.
|
||||
|
||||
Changes to the settings file take no effect
|
||||
===========================================
|
||||
|
||||
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.
|
||||
|
||||
I'm creating my own theme. How do I use Pygments for syntax highlighting?
|
||||
=========================================================================
|
||||
|
||||
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/>`_.
|
||||
|
||||
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::
|
||||
|
||||
pygmentize -S monokai -f html -a .highlight > pygment.css
|
||||
cp pygment.css path/to/theme/static/css/
|
||||
|
||||
Don't forget to import your ``pygment.css`` file from your main CSS file.
|
||||
|
||||
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, 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::
|
||||
|
||||
python -m pip install markdown
|
||||
|
||||
Can I use arbitrary metadata in my templates?
|
||||
=============================================
|
||||
|
||||
Yes. For example, to include a modified date in a Markdown post, one could
|
||||
include the following at the top of the article::
|
||||
|
||||
Modified: 2012-08-08
|
||||
|
||||
For reStructuredText, this metadata should of course be prefixed with a colon::
|
||||
|
||||
:Modified: 2012-08-08
|
||||
|
||||
This metadata can then be accessed in templates such as ``article.html`` via::
|
||||
|
||||
{% if article.modified %}
|
||||
Last modified: {{ article.modified }}
|
||||
{% endif %}
|
||||
|
||||
If you want to include metadata in templates outside the article context (e.g.,
|
||||
``base.html``), the ``if`` statement should instead be::
|
||||
|
||||
{% 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?
|
||||
=====================================================
|
||||
|
||||
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::
|
||||
|
||||
:template: template_name
|
||||
|
||||
For content in Markdown format::
|
||||
|
||||
Template: template_name
|
||||
|
||||
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`).
|
||||
|
||||
How can I override the generated URL of a specific page or article?
|
||||
===================================================================
|
||||
|
||||
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::
|
||||
|
||||
Override url/save_as page
|
||||
#########################
|
||||
|
||||
:url: override/url/
|
||||
:save_as: override/url/index.html
|
||||
|
||||
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.
|
||||
|
||||
How can I use a static page as my home page?
|
||||
============================================
|
||||
|
||||
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``::
|
||||
|
||||
Title: Welcome to My Site
|
||||
URL:
|
||||
save_as: index.html
|
||||
|
||||
Thank you for visiting. Welcome!
|
||||
|
||||
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.
|
||||
|
||||
What if I want to disable feed generation?
|
||||
==========================================
|
||||
|
||||
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::
|
||||
|
||||
FEED_ALL_ATOM = None
|
||||
CATEGORY_FEED_ATOM = None
|
||||
TRANSLATION_FEED_ATOM = None
|
||||
AUTHOR_FEED_ATOM = None
|
||||
AUTHOR_FEED_RSS = None
|
||||
|
||||
The word ``None`` should not be surrounded by quotes. Please note that ``None``
|
||||
and ``''`` are not the same thing.
|
||||
|
||||
I'm getting a warning about feeds generated without SITEURL being set properly
|
||||
==============================================================================
|
||||
|
||||
`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.
|
||||
|
||||
Feeds are still generated when this warning is displayed, but links within may
|
||||
be malformed and thus the feed may not validate.
|
||||
|
||||
Can I force Atom feeds to show only summaries instead of article content?
|
||||
=========================================================================
|
||||
|
||||
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.
|
||||
|
||||
Is Pelican only suitable for blogs?
|
||||
===================================
|
||||
|
||||
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::
|
||||
|
||||
TAGS_SAVE_AS = ''
|
||||
TAG_SAVE_AS = ''
|
||||
|
||||
Why does Pelican always write all HTML files even with content caching enabled?
|
||||
===============================================================================
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
How to process only a subset of all articles?
|
||||
=============================================
|
||||
|
||||
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``.
|
||||
|
||||
My tag cloud is missing/broken since I upgraded Pelican
|
||||
=======================================================
|
||||
|
||||
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.
|
||||
|
||||
Since I upgraded Pelican my pages are no longer rendered
|
||||
========================================================
|
||||
|
||||
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::
|
||||
|
||||
{% for pg in PAGES %}
|
||||
|
||||
with something like::
|
||||
|
||||
{% for pg in pages %}
|
||||
|
||||
How can I stop Pelican from trying to parse my static files as content?
|
||||
=======================================================================
|
||||
|
||||
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.
|
||||
|
||||
To circumvent this issue either use the appropriate ``*_EXCLUDES`` setting or
|
||||
disable the offending reader via ``READERS`` if you don't need it.
|
||||
|
||||
Why is [arbitrary Markdown syntax] not supported?
|
||||
=================================================
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. _Python-Markdown: https://github.com/Python-Markdown/markdown
|
||||
.. _Markdown Extensions: https://python-markdown.github.io/extensions/
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
Getting started
|
||||
###############
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
You're ready? Let's go ! You can install pelican in a lot of different ways,
|
||||
the simpler one is via `pip <http://pip.openplans.org/>`_::
|
||||
|
||||
$ pip install pelican
|
||||
|
||||
If you have the sources, you can install pelican using the distutils command
|
||||
install. I recommend to do so in a virtualenv::
|
||||
|
||||
$ virtualenv .
|
||||
$ source bin/activate
|
||||
$ python setup.py install
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
At this time, pelican is dependent of the following python packages:
|
||||
|
||||
* feedgenerator, to generate the ATOM feeds.
|
||||
* jinja2, for templating support.
|
||||
* pygments, to have syntactic colorization
|
||||
* docutils and Markdown
|
||||
|
||||
If you're not using python 2.7, you will also need `argparse`.
|
||||
|
||||
All those dependencies will be processed automatically if you install pelican
|
||||
using setuptools/distribute or pip.
|
||||
|
||||
Files metadata
|
||||
==============
|
||||
|
||||
Pelican tries to be smart enough to get the informations he needs from the
|
||||
file system (for instance, about the category of your articles), but you need to
|
||||
provide by hand some of those informations in your files.
|
||||
|
||||
You could provide the metadata in the restructured text files, using the
|
||||
following syntax (give your file the `.rst` extension)::
|
||||
|
||||
My super title
|
||||
##############
|
||||
|
||||
:date: 2010-10-03 10:20
|
||||
:tags: thats, awesome
|
||||
:category: yeah
|
||||
:author: Alexis Metaireau
|
||||
|
||||
|
||||
You can also use a markdown syntax (with a file ending in `.md`)::
|
||||
|
||||
Date: 2010-12-03
|
||||
Title: My super title
|
||||
|
||||
Put you content here.
|
||||
|
||||
Note that none of those are mandatory: if the date is not specified, pelican will
|
||||
rely on the mtime of your file, and the category can also be determined by the
|
||||
directory where the rst file is. For instance, the category of
|
||||
`python/foobar/myfoobar.rst` is `foobar`.
|
||||
|
||||
Generate your blog
|
||||
==================
|
||||
|
||||
To launch pelican, just use the `pelican` command::
|
||||
|
||||
$ pelican /path/to/your/content/
|
||||
|
||||
And… that's all! You can see your weblog generated on the `content/` folder.
|
||||
|
||||
This one will just generate a simple output, with the default theme. It's not
|
||||
really sexy, as it's a simple HTML output (without any style).
|
||||
|
||||
You can create your own style if you want, have a look to the help to see all
|
||||
the options you can use::
|
||||
|
||||
$ pelican --help
|
||||
|
||||
Pages
|
||||
=====
|
||||
|
||||
If you create a folder named `pages`, all the files in it will be used to
|
||||
generate static pages.
|
||||
|
||||
Then, use the `DISPLAY_PAGES_ON_MENU` setting, which will add all the pages to
|
||||
the menu.
|
||||
156
docs/importer.rst
Normal file
156
docs/importer.rst
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
.. _import:
|
||||
|
||||
Importing an existing site
|
||||
##########################
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
``pelican-import`` is a command-line tool for converting articles from other
|
||||
software to reStructuredText or Markdown. The supported import formats are:
|
||||
|
||||
- Blogger XML export
|
||||
- Dotclear export
|
||||
- Medium export
|
||||
- Tumblr API
|
||||
- WordPress XML export
|
||||
- RSS/Atom feed
|
||||
|
||||
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).
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
.. 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
|
||||
============
|
||||
|
||||
``pelican-import`` has some dependencies not required by the rest of Pelican:
|
||||
|
||||
- *BeautifulSoup4* and *lxml*, for WordPress and Dotclear import. Can be
|
||||
installed like any other Python package (``pip install BeautifulSoup4
|
||||
lxml``).
|
||||
- *Feedparser*, for feed import (``pip install feedparser``).
|
||||
- *Pandoc*, see the `Pandoc site`_ for installation instructions on your
|
||||
operating system.
|
||||
|
||||
.. _Pandoc: https://pandoc.org/
|
||||
.. _Pandoc site: https://pandoc.org/installing.html
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
::
|
||||
|
||||
pelican-import [-h] [--blogger] [--dotclear] [--tumblr] [--wpfile] [--feed]
|
||||
[-o OUTPUT] [-m MARKUP] [--dir-cat] [--dir-page] [--strip-raw] [--wp-custpost]
|
||||
[--wp-attach] [--disable-slugs] [-b BLOGNAME]
|
||||
input|api_key
|
||||
|
||||
Positional arguments
|
||||
--------------------
|
||||
============= ============================================================================
|
||||
``input`` The input file to read
|
||||
``api_key`` (Tumblr only) api_key can be obtained from https://www.tumblr.com/oauth/apps
|
||||
============= ============================================================================
|
||||
|
||||
Optional arguments
|
||||
------------------
|
||||
|
||||
-h, --help Show this help message and exit
|
||||
--blogger Blogger XML export (default: False)
|
||||
--dotclear Dotclear export (default: False)
|
||||
--medium Medium export (default: False)
|
||||
--tumblr Tumblr API (default: False)
|
||||
--wpfile WordPress XML export (default: False)
|
||||
--feed Feed to parse (default: False)
|
||||
-o OUTPUT, --output OUTPUT
|
||||
Output path (default: content)
|
||||
-m MARKUP, --markup MARKUP
|
||||
Output markup format: ``rst``, ``markdown``, or ``asciidoc``
|
||||
(default: ``rst``)
|
||||
--dir-cat Put files in directories with categories name
|
||||
(default: False)
|
||||
--dir-page Put files recognised as pages in "pages/" sub-
|
||||
directory (blogger and wordpress import only)
|
||||
(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 (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)
|
||||
--wp-attach 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)
|
||||
--disable-slugs Disable storing slugs from imported posts within
|
||||
output. With this disabled, your Pelican URLs may not
|
||||
be consistent with your original posts. (default:
|
||||
False)
|
||||
-b BLOGNAME, --blogname=BLOGNAME
|
||||
Blog name used in Tumblr API
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For Blogger::
|
||||
|
||||
$ pelican-import --blogger -o ~/output ~/posts.xml
|
||||
|
||||
For Dotclear::
|
||||
|
||||
$ pelican-import --dotclear -o ~/output ~/backup.txt
|
||||
|
||||
For Medium::
|
||||
|
||||
$ 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_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
|
||||
=====
|
||||
|
||||
To test the module, one can use sample files:
|
||||
|
||||
- for WordPress: https://www.wpbeginner.com/wp-themes/how-to-add-dummy-content-for-theme-development-in-wordpress/
|
||||
- for Dotclear: http://media.dotaddict.org/tda/downloads/lorem-backup.txt
|
||||
|
||||
.. _More Categories: https://github.com/pelican-plugins/more-categories
|
||||
|
|
@ -1,52 +1,74 @@
|
|||
Pelican
|
||||
#######
|
||||
Pelican |release|
|
||||
=================
|
||||
|
||||
Pelican is a simple weblog generator, writen in python.
|
||||
Pelican is a static site generator, written in Python_. Highlights include:
|
||||
|
||||
* Write your weblog entries directly with your editor of choice (vim!) and
|
||||
directly in restructured text, or markdown.
|
||||
* A simple cli-tool to (re)generate the weblog.
|
||||
* Easy to interface with DVCSes and web hooks
|
||||
* Completely static output, so easy to host anywhere !
|
||||
* Write your content directly with your editor of choice in reStructuredText_
|
||||
or Markdown_ formats
|
||||
* Includes a simple CLI tool to (re)generate your site
|
||||
* Easy to interface with distributed version control systems and web hooks
|
||||
* Completely static output is easy to host anywhere
|
||||
|
||||
Ready to get started? Check out the :doc:`Quickstart<quickstart>` guide.
|
||||
|
||||
Features
|
||||
========
|
||||
--------
|
||||
|
||||
Pelican currently supports:
|
||||
Pelican’s feature highlights include:
|
||||
|
||||
* blog articles
|
||||
* comments, via an external service (disqus). Please notice that while
|
||||
it's useful, it's an external service, and you'll not manage the
|
||||
comments by yourself. It could potentially eat your data.
|
||||
* theming support (themes are done using `jinja2 <http://jinjna.pocoo.org>`_)
|
||||
* PDF generation of the articles/pages (optional).
|
||||
* Articles (e.g., blog posts) and pages (e.g., "About", "Projects", "Contact")
|
||||
* Integration with external services
|
||||
* Site themes (created using Jinja2_ templates)
|
||||
* Publication of articles in multiple languages
|
||||
* Generation of Atom and RSS feeds
|
||||
* Code syntax highlighting
|
||||
* 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" ?
|
||||
========================
|
||||
Why the name "Pelican"?
|
||||
-----------------------
|
||||
|
||||
Heh, you didn't noticed? "Pelican" is an anagram for "Calepin" ;)
|
||||
"Pelican" is an anagram for *calepin*, which means "notebook" in French. ;)
|
||||
|
||||
Source code
|
||||
===========
|
||||
-----------
|
||||
|
||||
You can access the source code via mercurial at http://hg.notmyidea.org/pelican/
|
||||
or via git on http://github.com/ametaireau/pelican/
|
||||
You can access the source code at: https://github.com/getpelican/pelican
|
||||
|
||||
Feedback !
|
||||
==========
|
||||
How to get help, contribute, or provide feedback
|
||||
------------------------------------------------
|
||||
|
||||
If you want to see new features in Pelican, dont hesitate to tell me, to clone
|
||||
the repository, etc. That's open source, dude!
|
||||
|
||||
Contact me at "alexis at notmyidea dot org" for any request/feedback !
|
||||
See our :doc:`feedback and contribution submission guidelines <contribute>`.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
-------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
getting_started
|
||||
|
||||
quickstart
|
||||
install
|
||||
content
|
||||
publish
|
||||
settings
|
||||
plugins
|
||||
themes
|
||||
pelican-themes
|
||||
importer
|
||||
faq
|
||||
tips
|
||||
contribute
|
||||
internals
|
||||
report
|
||||
changelog
|
||||
|
||||
.. Links
|
||||
|
||||
.. _Python: https://www.python.org/
|
||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||
.. _Markdown: https://daringfireball.net/projects/markdown/
|
||||
.. _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/pelican-plugins
|
||||
|
|
|
|||
122
docs/install.rst
Normal file
122
docs/install.rst
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Installing Pelican
|
||||
##################
|
||||
|
||||
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_::
|
||||
|
||||
python -m pip install pelican
|
||||
|
||||
Or, if you plan on using Markdown::
|
||||
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
(Keep in mind that some operating systems will require you to prefix the above
|
||||
command with ``sudo`` in order to install Pelican system-wide.)
|
||||
|
||||
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::
|
||||
|
||||
virtualenv ~/virtualenvs/pelican
|
||||
cd ~/virtualenvs/pelican
|
||||
source bin/activate
|
||||
|
||||
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::
|
||||
|
||||
cd path-to-Pelican-source
|
||||
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::
|
||||
|
||||
python -m pip install -e "git+https://github.com/getpelican/pelican.git#egg=pelican"
|
||||
|
||||
Once Pelican is installed, you can run ``pelican --help`` to see basic usage
|
||||
options. For more detail, refer to the :doc:`Publish<publish>` section.
|
||||
|
||||
Optional packages
|
||||
-----------------
|
||||
|
||||
If you plan on using `Markdown <https://pypi.org/project/Markdown/>`_ as a
|
||||
markup format, you can install Pelican with Markdown support::
|
||||
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
Typographical enhancements can be enabled in your settings file, but first the
|
||||
requisite `Typogrify <https://pypi.org/project/typogrify/>`_ library must be
|
||||
installed::
|
||||
|
||||
python -m pip install typogrify
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
When Pelican is installed, the following dependent Python packages should be
|
||||
automatically installed without any action on your part:
|
||||
|
||||
* `feedgenerator <https://pypi.org/project/feedgenerator/>`_, to generate the
|
||||
Atom feeds
|
||||
* `jinja2 <https://pypi.org/project/Jinja2/>`_, for templating support
|
||||
* `pygments <https://pypi.org/project/Pygments/>`_, for syntax highlighting
|
||||
* `docutils <https://pypi.org/project/docutils/>`_, for supporting
|
||||
reStructuredText as an input format
|
||||
* `blinker <https://pypi.org/project/blinker/>`_, an object-to-object and
|
||||
broadcast signaling system
|
||||
* `unidecode <https://pypi.org/project/Unidecode/>`_, for ASCII
|
||||
transliterations of Unicode text
|
||||
utilities
|
||||
* `MarkupSafe <https://pypi.org/project/MarkupSafe/>`_, for a markup-safe
|
||||
string implementation
|
||||
* `python-dateutil <https://pypi.org/project/python-dateutil/>`_, to read
|
||||
the date metadata
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
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``::
|
||||
|
||||
python -m pip install --upgrade pelican
|
||||
|
||||
If you installed Pelican via distutils or the bleeding-edge method, simply
|
||||
perform the same step to install the most recent version.
|
||||
|
||||
Kickstart your site
|
||||
-------------------
|
||||
|
||||
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::
|
||||
|
||||
pelican-quickstart
|
||||
|
||||
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``
|
||||
|
||||
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)::
|
||||
|
||||
yourproject/
|
||||
├── content
|
||||
│ └── (pages)
|
||||
├── output
|
||||
├── tasks.py
|
||||
├── Makefile
|
||||
├── pelicanconf.py # Main settings file
|
||||
└── publishconf.py # Settings to use when ready to publish
|
||||
|
||||
The next step is to begin to adding content to the *content* folder that has
|
||||
been created for you.
|
||||
|
||||
.. _Pip: https://pip.pypa.io/
|
||||
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
|
||||
|
|
@ -1,81 +1,98 @@
|
|||
Pelican internals
|
||||
#################
|
||||
|
||||
This section describe how pelican is working internally. As you'll see, it's
|
||||
quite simple, but a bit of documentation doesn't hurt :)
|
||||
This section describe how Pelican works internally. As you'll see, it's quite
|
||||
simple, but a bit of documentation doesn't hurt. :)
|
||||
|
||||
You can also find in the :doc:`report` section an excerpt of a report the
|
||||
original author wrote with some software design information.
|
||||
|
||||
.. _report: :doc:`report`
|
||||
|
||||
Overall structure
|
||||
=================
|
||||
|
||||
What `pelican` does, is taking a list of files, and processing them, to some
|
||||
sort of output. Usually, the files are restructured text and markdown files,
|
||||
and the output is a blog, but it can be anything you want.
|
||||
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.
|
||||
|
||||
I've separated the logic in different classes and concepts:
|
||||
The logic is separated into different classes and concepts:
|
||||
|
||||
* `writers` are responsible of all the writing process of the
|
||||
files. It's 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.
|
||||
* **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.
|
||||
|
||||
* `readers` are used to read from various formats (Markdown, and Restructured
|
||||
Text for now, but the system is extensible). Given a file, they return
|
||||
metadata (author, tags, category etc) and content (HTML formated)
|
||||
* **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).
|
||||
|
||||
* `generators` generate the different outputs. For instance, pelican comes with
|
||||
`ArticlesGenerator` and `PageGenerator`, into others. Given
|
||||
a configurations, they can do whatever they want. Most of the time it's
|
||||
generating files from inputs.
|
||||
* **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.
|
||||
|
||||
* `pelican` also uses `templates`, so it's easy to write you own theme. The
|
||||
syntax is `jinja2`, and, trust me, really easy to learn, so don't hesitate
|
||||
a second.
|
||||
* 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.
|
||||
|
||||
How to implement a new reader ?
|
||||
===============================
|
||||
How to implement a new reader?
|
||||
==============================
|
||||
|
||||
There is an awesome markup language you want to add to pelican ?
|
||||
Well, the only thing you have to do is to create a class that have a `read`
|
||||
method, that is returning an HTML content and some metadata.
|
||||
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.
|
||||
|
||||
Take a look to the Markdown reader::
|
||||
Take a look at the Markdown reader::
|
||||
|
||||
class MarkdownReader(object):
|
||||
from pelican.readers import BaseReader
|
||||
from pelican.utils import pelican_open
|
||||
from markdown import Markdown
|
||||
|
||||
def read(self, filename):
|
||||
class MarkdownReader(BaseReader):
|
||||
enabled = True
|
||||
|
||||
def read(self, source_path):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
text = open(filename)
|
||||
md = Markdown(extensions = ['meta', 'codehilite'])
|
||||
content = md.convert(text)
|
||||
|
||||
metadatas = {}
|
||||
|
||||
with pelican_open(source_path) as text:
|
||||
md_extensions = {'markdown.extensions.meta': {},
|
||||
'markdown.extensions.codehilite': {}}
|
||||
md = Markdown(extensions=md_extensions.keys(),
|
||||
extension_configs=md_extensions)
|
||||
content = md.convert(text)
|
||||
|
||||
metadata = {}
|
||||
for name, value in md.Meta.items():
|
||||
if name in _METADATAS_FIELDS:
|
||||
meta = _METADATAS_FIELDS[name](value[0])
|
||||
else:
|
||||
meta = value[0]
|
||||
metadatas[name.lower()] = meta
|
||||
return content, metadatas
|
||||
name = name.lower()
|
||||
meta = self.process_metadata(name, value[0])
|
||||
metadata[name] = meta
|
||||
return content, metadata
|
||||
|
||||
Simple isn't it ?
|
||||
Simple, isn't it?
|
||||
|
||||
How to implement a new generator ?
|
||||
==================================
|
||||
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.
|
||||
|
||||
Generators have basically two important methods. You're not forced to create
|
||||
both, only the existing ones will be called.
|
||||
How to implement a new generator?
|
||||
=================================
|
||||
|
||||
* `generate_context`, that is called in a first place, for all the generators.
|
||||
Generators have two important methods. You're not forced to create both; only
|
||||
the existing ones will be called.
|
||||
|
||||
* ``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 find
|
||||
all the pages, transform them into objects, and populate the context with
|
||||
them. Be careful to *not* output anything using this context at this stage,
|
||||
as it is likely to change by the effect of others generators.
|
||||
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.
|
||||
|
||||
* `generate_output` is then called. And guess what is it made for ? Oh,
|
||||
generating the output :) That's here that you may want to look at the context
|
||||
and call the methods of the `writer` object, that is passed at 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.
|
||||
* ``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.
|
||||
|
|
|
|||
1789
docs/locale/zh_CN/LC_MESSAGES/changelog.po
Normal file
1789
docs/locale/zh_CN/LC_MESSAGES/changelog.po
Normal file
File diff suppressed because it is too large
Load diff
1074
docs/locale/zh_CN/LC_MESSAGES/content.po
Normal file
1074
docs/locale/zh_CN/LC_MESSAGES/content.po
Normal file
File diff suppressed because it is too large
Load diff
669
docs/locale/zh_CN/LC_MESSAGES/contribute.po
Normal file
669
docs/locale/zh_CN/LC_MESSAGES/contribute.po
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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 ""
|
||||
484
docs/locale/zh_CN/LC_MESSAGES/faq.po
Normal file
484
docs/locale/zh_CN/LC_MESSAGES/faq.po
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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`` )。"
|
||||
321
docs/locale/zh_CN/LC_MESSAGES/importer.po
Normal file
321
docs/locale/zh_CN/LC_MESSAGES/importer.po
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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"
|
||||
134
docs/locale/zh_CN/LC_MESSAGES/index.po
Normal file
134
docs/locale/zh_CN/LC_MESSAGES/index.po
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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 "Pelican’s 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 "文档"
|
||||
220
docs/locale/zh_CN/LC_MESSAGES/install.po
Normal file
220
docs/locale/zh_CN/LC_MESSAGES/install.po
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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* 目录中添加自己创作的内容了。"
|
||||
172
docs/locale/zh_CN/LC_MESSAGES/internals.po
Normal file
172
docs/locale/zh_CN/LC_MESSAGES/internals.po
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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`` 方法为全局上下文中的每一个页面输出一个文件。"
|
||||
206
docs/locale/zh_CN/LC_MESSAGES/pelican-themes.po
Normal file
206
docs/locale/zh_CN/LC_MESSAGES/pelican-themes.po
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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`` 主题。"
|
||||
669
docs/locale/zh_CN/LC_MESSAGES/plugins.po
Normal file
669
docs/locale/zh_CN/LC_MESSAGES/plugins.po
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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`` 信号构建一个添加自定义文章的插件:"
|
||||
329
docs/locale/zh_CN/LC_MESSAGES/publish.po
Normal file
329
docs/locale/zh_CN/LC_MESSAGES/publish.po
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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`` 来覆盖默认的可执行文件名)"
|
||||
151
docs/locale/zh_CN/LC_MESSAGES/quickstart.po
Normal file
151
docs/locale/zh_CN/LC_MESSAGES/quickstart.po
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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/>`_ 来"
|
||||
"本地化默认字段。"
|
||||
249
docs/locale/zh_CN/LC_MESSAGES/report.po
Normal file
249
docs/locale/zh_CN/LC_MESSAGES/report.po
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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 "I’ve 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`` 来生成想要的输出。"
|
||||
2070
docs/locale/zh_CN/LC_MESSAGES/settings.po
Normal file
2070
docs/locale/zh_CN/LC_MESSAGES/settings.po
Normal file
File diff suppressed because it is too large
Load diff
60
docs/locale/zh_CN/LC_MESSAGES/sphinx.po
Normal file
60
docs/locale/zh_CN/LC_MESSAGES/sphinx.po
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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> © %(copyright)s"
|
||||
msgstr "<a href=\"%(path)s\">Copyright</a> © %(copyright)s"
|
||||
|
||||
#: ../../_templates/page.html:133 0a35c662e6574da48f7ac5c6b2c82874
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Copyright © %(copyright)s, <a "
|
||||
"href=\"https://justinmayer.com\">Justin Mayer</a>, Alexis Metaireau, and "
|
||||
"contributors"
|
||||
msgstr ""
|
||||
"Copyright © %(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 "本页目录"
|
||||
1269
docs/locale/zh_CN/LC_MESSAGES/themes.po
Normal file
1269
docs/locale/zh_CN/LC_MESSAGES/themes.po
Normal file
File diff suppressed because it is too large
Load diff
723
docs/locale/zh_CN/LC_MESSAGES/tips.po
Normal file
723
docs/locale/zh_CN/LC_MESSAGES/tips.po
Normal file
|
|
@ -0,0 +1,723 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2010–2024
|
||||
# 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 ""
|
||||
170
docs/pelican-themes.rst
Normal file
170
docs/pelican-themes.rst
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
pelican-themes
|
||||
##############
|
||||
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
``pelican-themes`` is a command line tool for managing themes for Pelican. See
|
||||
:ref:`settings/themes` for settings related to themes.
|
||||
|
||||
|
||||
Usage
|
||||
"""""
|
||||
|
||||
| pelican-themes [-h] [-l] [-i theme path [theme path ...]]
|
||||
| [-r theme name [theme name ...]]
|
||||
| [-s theme path [theme path ...]] [-v] [--version]
|
||||
|
||||
Optional arguments:
|
||||
"""""""""""""""""""
|
||||
|
||||
|
||||
-h, --help Show the help and exit
|
||||
|
||||
-l, --list Show the themes already installed
|
||||
|
||||
-i theme_path, --install theme_path One or more themes to install
|
||||
|
||||
-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.
|
||||
Useful for theme development
|
||||
|
||||
-v, --verbose Verbose output
|
||||
|
||||
--version Print the version of this script
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
|
||||
Listing the installed themes
|
||||
""""""""""""""""""""""""""""
|
||||
|
||||
With ``pelican-themes``, you can see the available themes by using the ``-l``
|
||||
or ``--list`` option:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pelican-themes -l
|
||||
notmyidea
|
||||
two-column@
|
||||
simple
|
||||
$ pelican-themes --list
|
||||
notmyidea
|
||||
two-column@
|
||||
simple
|
||||
|
||||
In this example, we can see there are three themes available: ``notmyidea``,
|
||||
``simple``, and ``two-column``.
|
||||
|
||||
``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).
|
||||
|
||||
Note that you can combine the ``--list`` option with the ``-v`` or
|
||||
``--verbose`` option to get more verbose output, like this:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pelican-themes -v -l
|
||||
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/notmyidea
|
||||
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/two-column (symbolic link to `/home/skami/Dev/Python/pelican-themes/two-column')
|
||||
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/simple
|
||||
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms --verbose
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms\
|
||||
~/Dev/Python/pelican-themes/martyalchin \
|
||||
--verbose
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes -vi ~/Dev/Python/pelican-themes/two-column
|
||||
|
||||
|
||||
Removing themes
|
||||
"""""""""""""""
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes --remove two-column
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes -r martyachin notmyidea-cmd -v
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Creating symbolic links
|
||||
"""""""""""""""""""""""
|
||||
|
||||
``pelican-themes`` can also install themes by creating symbolic links instead
|
||||
of copying entire themes into the Pelican themes path.
|
||||
|
||||
To symbolically link a theme, you can use the ``-s`` or ``--symlink``, which
|
||||
works exactly as the ``--install`` option:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes --symlink ~/Dev/Python/pelican-themes/two-column
|
||||
|
||||
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.
|
||||
|
||||
This is useful for theme development:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ sudo pelican-themes -s ~/Dev/Python/pelican-themes/two-column
|
||||
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||
$ firefox /tmp/out/index.html
|
||||
$ vim ~/Dev/Pelican/pelican-themes/two-column/static/css/main.css
|
||||
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||
$ cp /tmp/bg.png ~/Dev/Pelican/pelican-themes/two-column/static/img/bg.png
|
||||
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||
$ vim ~/Dev/Pelican/pelican-themes/two-column/templates/index.html
|
||||
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||
|
||||
|
||||
|
||||
Doing several things at once
|
||||
""""""""""""""""""""""""""""
|
||||
|
||||
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:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# pelican-themes --remove notmyidea-cms two-column \
|
||||
--install ~/Dev/Python/pelican-themes/notmyidea-cms-fr \
|
||||
--symlink ~/Dev/Python/pelican-themes/two-column \
|
||||
--verbose
|
||||
|
||||
In this example, the theme ``notmyidea-cms`` is replaced by the theme
|
||||
``notmyidea-cms-fr``
|
||||
348
docs/plugins.rst
Normal file
348
docs/plugins.rst
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
.. _plugins:
|
||||
|
||||
Plugins
|
||||
#######
|
||||
|
||||
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.
|
||||
|
||||
How to use plugins
|
||||
==================
|
||||
|
||||
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::
|
||||
|
||||
pelican-plugins
|
||||
|
||||
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.
|
||||
|
||||
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``)::
|
||||
|
||||
PLUGINS = ['package.myplugin',
|
||||
'namespace_plugin1',
|
||||
'pelican.plugins.namespace_plugin2']
|
||||
|
||||
Alternatively, you can import them in your settings file and pass the modules::
|
||||
|
||||
from package import myplugin
|
||||
from pelican.plugins import namespace_plugin1, namespace_plugin2
|
||||
PLUGINS = [myplugin, namespace_plugin1, namespace_plugin2]
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
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::
|
||||
|
||||
PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"]
|
||||
PLUGINS = ["assets", "liquid_tags", "sitemap"]
|
||||
|
||||
Where to find plugins
|
||||
=====================
|
||||
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.
|
||||
|
||||
.. _pelican-plugins organization: https://github.com/pelican-plugins
|
||||
.. _pelican-plugins repository: https://github.com/getpelican/pelican-plugins
|
||||
|
||||
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.
|
||||
|
||||
How to create plugins
|
||||
=====================
|
||||
|
||||
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.
|
||||
|
||||
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::
|
||||
|
||||
import logging
|
||||
|
||||
from pelican import signals
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def test(sender):
|
||||
log.debug("%s initialized !!", sender)
|
||||
|
||||
def register():
|
||||
signals.initialized.connect(test)
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
--------------------------
|
||||
|
||||
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::
|
||||
|
||||
myplugin
|
||||
├── pelican
|
||||
│ └── plugins
|
||||
│ └── myplugin
|
||||
│ ├── __init__.py
|
||||
│ └── ...
|
||||
├── ...
|
||||
└── setup.py
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
.. _cookiecutter template for plugins: https://github.com/getpelican/cookiecutter-pelican-plugin
|
||||
|
||||
List of signals
|
||||
===============
|
||||
|
||||
Here is the list of currently implemented signals:
|
||||
|
||||
================================= ============================ ===========================================================================
|
||||
Signal Arguments Description
|
||||
================================= ============================ ===========================================================================
|
||||
initialized pelican object
|
||||
finalized pelican object 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.
|
||||
generator_init generator invoked in the Generator.__init__
|
||||
all_generators_finalized generators invoked after all the generators are executed and before writing output
|
||||
readers_init readers invoked in the Readers.__init__
|
||||
article_generator_context article_generator, metadata
|
||||
article_generator_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context;
|
||||
use if code needs to do something before every article is parsed
|
||||
article_generator_init article_generator invoked in the ArticlesGenerator.__init__
|
||||
article_generator_pretaxonomy article_generator 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
|
||||
article_generator_finalized article_generator invoked at the end of ArticlesGenerator.generate_context
|
||||
article_generator_write_article article_generator, content invoked before writing each article, the article is passed as content
|
||||
article_writer_finalized article_generator, writer invoked after all articles and related pages have been written, but before
|
||||
the article generator is closed.
|
||||
get_generators pelican object invoked in Pelican.get_generator_classes,
|
||||
can return a Generator, or several
|
||||
generators in a tuple or in a list.
|
||||
get_writer pelican object invoked in Pelican.get_writer,
|
||||
can return a custom Writer.
|
||||
page_generator_context page_generator, metadata
|
||||
page_generator_preread page_generator invoked before a page is read in PageGenerator.generate_context;
|
||||
use if code needs to do something before every page is parsed.
|
||||
page_generator_init page_generator invoked in the PagesGenerator.__init__
|
||||
page_generator_finalized page_generator invoked at the end of PagesGenerator.generate_context
|
||||
page_generator_write_page page_generator, content invoked before writing each page, the page is passed as content
|
||||
page_writer_finalized page_generator, writer invoked after all pages have been written, but before the page generator
|
||||
is closed.
|
||||
static_generator_context static_generator, metadata
|
||||
static_generator_preread static_generator 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.
|
||||
static_generator_init static_generator invoked in the StaticGenerator.__init__
|
||||
static_generator_finalized static_generator invoked at the end of StaticGenerator.generate_context
|
||||
content_object_init content_object invoked at the end of Content.__init__
|
||||
content_written path, context invoked each time a content file is written.
|
||||
feed_generated context, feed invoked each time a feed gets generated. Can be used to modify a feed
|
||||
object before it gets written.
|
||||
feed_written path, context, feed invoked each time a feed file is written.
|
||||
================================= ============================ ===========================================================================
|
||||
|
||||
.. warning::
|
||||
|
||||
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``).
|
||||
|
||||
.. note::
|
||||
|
||||
After Pelican 3.2, signal names were standardized. Older plugins may need
|
||||
to be updated to use the new names:
|
||||
|
||||
========================== ===========================
|
||||
Old name New name
|
||||
========================== ===========================
|
||||
article_generate_context article_generator_context
|
||||
article_generate_finalized article_generator_finalized
|
||||
article_generate_preread article_generator_preread
|
||||
pages_generate_context page_generator_context
|
||||
pages_generate_preread page_generator_preread
|
||||
pages_generator_finalized page_generator_finalized
|
||||
pages_generator_init page_generator_init
|
||||
static_generate_context static_generator_context
|
||||
static_generate_preread static_generator_preread
|
||||
========================== ===========================
|
||||
|
||||
Recipes
|
||||
=======
|
||||
|
||||
We eventually realised some of the recipes to create plugins would be best
|
||||
shared in the documentation somewhere, so here they are!
|
||||
|
||||
How to create a new reader
|
||||
--------------------------
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
No more talking — here is an example::
|
||||
|
||||
from pelican import signals
|
||||
from pelican.readers import BaseReader
|
||||
|
||||
# Create a new reader class, inheriting from the pelican.reader.BaseReader
|
||||
class NewReader(BaseReader):
|
||||
enabled = True # Yeah, you probably want that :-)
|
||||
|
||||
# The list of file extensions you want this reader to match with.
|
||||
# If multiple readers were to use the same extension, the latest will
|
||||
# win (so the one you're defining here, most probably).
|
||||
file_extensions = ['yeah']
|
||||
|
||||
# You need to have a read method, which takes a filename and returns
|
||||
# some content and the associated metadata.
|
||||
def read(self, filename):
|
||||
metadata = {'title': 'Oh yeah',
|
||||
'category': 'Foo',
|
||||
'date': '2012-12-01'}
|
||||
|
||||
parsed = {}
|
||||
for key, value in metadata.items():
|
||||
parsed[key] = self.process_metadata(key, value)
|
||||
|
||||
return "Some content", parsed
|
||||
|
||||
def add_reader(readers):
|
||||
readers.reader_classes['yeah'] = NewReader
|
||||
|
||||
# This is how pelican works.
|
||||
def register():
|
||||
signals.readers_init.connect(add_reader)
|
||||
|
||||
|
||||
Adding a new generator
|
||||
----------------------
|
||||
|
||||
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.
|
||||
|
||||
::
|
||||
|
||||
def get_generators(pelican_object):
|
||||
# define a new generator here if you need to
|
||||
return MyGenerator
|
||||
|
||||
def register():
|
||||
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
|
||||
198
docs/publish.rst
Normal file
198
docs/publish.rst
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
Publish your site
|
||||
#################
|
||||
|
||||
.. _site_generation:
|
||||
|
||||
Site generation
|
||||
===============
|
||||
|
||||
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::
|
||||
|
||||
pelican /path/to/your/content/ [-s path/to/your/settings.py]
|
||||
|
||||
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.
|
||||
|
||||
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::
|
||||
|
||||
pelican --autoreload --listen
|
||||
|
||||
Pelican has other command-line switches available. Have a look at the help to
|
||||
see all the options you can use::
|
||||
|
||||
pelican --help
|
||||
|
||||
Viewing the generated files
|
||||
---------------------------
|
||||
|
||||
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::
|
||||
|
||||
firefox output/index.html
|
||||
|
||||
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::
|
||||
|
||||
pelican --listen
|
||||
|
||||
Once the web server has been started, you can preview your site at:
|
||||
http://localhost:8000/
|
||||
|
||||
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,
|
||||
feeds, etc.) that you may have defined::
|
||||
|
||||
pelican content -s publishconf.py
|
||||
|
||||
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``::
|
||||
|
||||
from pelicanconf import *
|
||||
|
||||
If you have generated a ``publishconf.py`` using ``pelican-quickstart``, this
|
||||
line is included by default.
|
||||
|
||||
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::
|
||||
|
||||
rsync -avc --delete output/ host.example.com:/var/www/your-site/
|
||||
|
||||
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.
|
||||
|
||||
Automation
|
||||
==========
|
||||
|
||||
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.
|
||||
|
||||
Following are automation tools that "wrap" the ``pelican`` command and can
|
||||
simplify the process of generating, previewing, and uploading your site.
|
||||
|
||||
Invoke
|
||||
------
|
||||
|
||||
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::
|
||||
|
||||
python -m pip install invoke
|
||||
|
||||
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::
|
||||
|
||||
invoke build
|
||||
|
||||
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::
|
||||
|
||||
invoke regenerate
|
||||
|
||||
To serve the generated site so it can be previewed in your browser at
|
||||
http://localhost:8000/::
|
||||
|
||||
invoke serve
|
||||
|
||||
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::
|
||||
|
||||
invoke livereload
|
||||
|
||||
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::
|
||||
|
||||
invoke publish
|
||||
|
||||
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.
|
||||
|
||||
Make
|
||||
----
|
||||
|
||||
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.
|
||||
|
||||
If you want to use ``make`` to generate your site using the settings in
|
||||
``pelicanconf.py``, run::
|
||||
|
||||
make html
|
||||
|
||||
To generate the site for production, using the settings in ``publishconf.py``,
|
||||
run::
|
||||
|
||||
make publish
|
||||
|
||||
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::
|
||||
|
||||
make regenerate
|
||||
|
||||
To serve the generated site so it can be previewed in your browser at
|
||||
http://localhost:8000/::
|
||||
|
||||
make serve
|
||||
|
||||
Normally you would need to run ``make regenerate`` and ``make serve`` in two
|
||||
separate terminal sessions, but you can run both at once via::
|
||||
|
||||
make devserver
|
||||
|
||||
The above command will simultaneously run Pelican in regeneration mode as well
|
||||
as serve the output at http://localhost:8000.
|
||||
|
||||
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::
|
||||
|
||||
make rsync_upload
|
||||
|
||||
That's it! Your site should now be live.
|
||||
|
||||
(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.)
|
||||
|
||||
.. _Invoke: https://www.pyinvoke.org/
|
||||
82
docs/quickstart.rst
Normal file
82
docs/quickstart.rst
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
Quickstart
|
||||
##########
|
||||
|
||||
Reading through all the documentation is highly recommended, but for the truly
|
||||
impatient, following are some quick steps to get started.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
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::
|
||||
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
Create a project
|
||||
----------------
|
||||
|
||||
First, choose a name for your project, create an appropriately-named directory
|
||||
for your site, and switch to that directory::
|
||||
|
||||
mkdir -p ~/projects/yoursite
|
||||
cd ~/projects/yoursite
|
||||
|
||||
Create a skeleton project via the ``pelican-quickstart`` command, which begins
|
||||
by asking some questions about your site::
|
||||
|
||||
pelican-quickstart
|
||||
|
||||
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``).
|
||||
|
||||
Create an article
|
||||
-----------------
|
||||
|
||||
You cannot run Pelican until you have created some content. Use your preferred
|
||||
text editor to create your first article with the following content::
|
||||
|
||||
Title: My First Review
|
||||
Date: 2010-12-03 10:20
|
||||
Category: Review
|
||||
|
||||
Following is a review of my favorite mechanical keyboard.
|
||||
|
||||
Given that this example article is in Markdown format, save it as
|
||||
``~/projects/yoursite/content/keyboard-review.md``.
|
||||
|
||||
Generate your site
|
||||
------------------
|
||||
|
||||
From your project root directory, run the ``pelican`` command to generate your site::
|
||||
|
||||
pelican content
|
||||
|
||||
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.)
|
||||
|
||||
Preview your site
|
||||
-----------------
|
||||
|
||||
Open a new terminal session, navigate to your project root directory, and
|
||||
run the following command to launch Pelican's web server::
|
||||
|
||||
pelican --listen
|
||||
|
||||
Preview your site by navigating to http://localhost:8000/ in your browser.
|
||||
|
||||
Continue reading the other documentation sections for more detail, and check
|
||||
out the Pelican wiki's Tutorials_ page for links to community-published
|
||||
tutorials.
|
||||
|
||||
.. _Tutorials: https://github.com/getpelican/pelican/wiki/Tutorials
|
||||
|
||||
Footnotes
|
||||
---------
|
||||
|
||||
.. [#tzlocal_fn] You can help localize default fields by installing the
|
||||
optional `tzlocal <https://pypi.org/project/tzlocal/>`_
|
||||
module.
|
||||
114
docs/report.rst
Normal file
114
docs/report.rst
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
Some history about Pelican
|
||||
##########################
|
||||
|
||||
.. warning::
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Use case
|
||||
========
|
||||
|
||||
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.
|
||||
|
||||
.. image:: _static/overall.png
|
||||
|
||||
To be flexible enough, Pelican has template support, so you can easily write
|
||||
your own themes if you want to.
|
||||
|
||||
Design process
|
||||
==============
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
I’ve separated the logic in different classes and concepts:
|
||||
|
||||
* *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.
|
||||
|
||||
* *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).
|
||||
|
||||
* *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).
|
||||
|
||||
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.
|
||||
|
||||
In more detail
|
||||
==============
|
||||
|
||||
Here is an overview of the classes involved in Pelican.
|
||||
|
||||
.. image:: _static/uml.jpg
|
||||
|
||||
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.
|
||||
|
||||
Internally, the following process is followed:
|
||||
|
||||
* First of all, the command line is parsed, and some content from the user is
|
||||
used to initialize the different generator objects.
|
||||
|
||||
* A ``context`` is created. It contains the settings from the command line and
|
||||
a settings file if provided.
|
||||
* The ``generate_context`` method of each generator is called, updating
|
||||
the context.
|
||||
* The writer is created and given to the ``generate_output`` method of each
|
||||
generator.
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
* 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.
|
||||
* Update the ``context`` with all those articles.
|
||||
|
||||
Then, the ``generate_content`` method uses the ``context`` and the ``writer``
|
||||
to generate the wanted output.
|
||||
1558
docs/settings.rst
1558
docs/settings.rst
File diff suppressed because it is too large
Load diff
685
docs/themes.rst
685
docs/themes.rst
|
|
@ -1,8 +1,32 @@
|
|||
How to create themes for pelican
|
||||
################################
|
||||
.. _theming-pelican:
|
||||
|
||||
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/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::
|
||||
|
||||
pelican content -s pelicanconf.py -t /projects/your-site/themes/your-theme
|
||||
|
||||
If you'd rather not specify the theme on every invocation, you can define
|
||||
``THEME`` in your settings to point to the location of your preferred theme.
|
||||
|
||||
Pelican uses the great `jinja2 <http://jinjna.pocoo.org>`_ templating engine to
|
||||
generate it's HTML output.
|
||||
|
||||
Structure
|
||||
=========
|
||||
|
|
@ -10,92 +34,635 @@ Structure
|
|||
To make your own theme, you must follow the following structure::
|
||||
|
||||
├── static
|
||||
│ ├── css
|
||||
│ └── images
|
||||
│ ├── css
|
||||
│ └── images
|
||||
└── templates
|
||||
├── archives.html // to display archives
|
||||
├── article.html // processed for each article
|
||||
├── categories.html // must list all the categories
|
||||
├── category.html // processed for each category
|
||||
├── index.html // the index. List all the articles
|
||||
├── page.html // processed for each page
|
||||
├── tag.html // processed for each tag
|
||||
└── tags.html // must list all the tags. Can be a tag cloud.
|
||||
├── archives.html // to display archives
|
||||
├── article.html // processed for each article
|
||||
├── author.html // processed for each author
|
||||
├── authors.html // must list all the authors
|
||||
├── categories.html // must list all the categories
|
||||
├── 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.
|
||||
|
||||
* `static` contains all the static content. It will be copied on the output
|
||||
`theme/static` folder then. I've put the css and image folders, but they are
|
||||
just examples. Put what you need here.
|
||||
* `static` contains all the static assets, which will be copied to the output
|
||||
`theme` folder. The above filesystem layout includes CSS and image folders,
|
||||
but those are just examples. Put what you need here.
|
||||
|
||||
* `templates` contains all the templates that will be used to generate the content.
|
||||
I've just put the mandatory templates here, you can define your own if it helps
|
||||
you to organize yourself while doing the theme.
|
||||
|
||||
Templates and variables
|
||||
* `templates` contains all the templates that will be used to generate the
|
||||
content. The template files listed above are mandatory; you can add your own
|
||||
templates if it helps you keep things organized while creating your theme.
|
||||
|
||||
|
||||
.. _templates-variables:
|
||||
|
||||
Templates and Variables
|
||||
=======================
|
||||
|
||||
It's using a simple syntax, that you can embbed into your html pages.
|
||||
This document describes which templates should exists on a theme, and which
|
||||
variables will be passed to each template, while generating it.
|
||||
The idea is to use a simple syntax that you can embed into your HTML pages.
|
||||
This document describes which templates should exist in a theme, and which
|
||||
variables will be passed to each template at generation time.
|
||||
|
||||
All templates will receive the variables defined in your settings file, if they
|
||||
are in caps. You can access them directly.
|
||||
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 those settings will be given to all templates.
|
||||
All of these settings will be available to all templates.
|
||||
|
||||
============= ===================================================
|
||||
=============== ===================================================
|
||||
Variable Description
|
||||
============= ===================================================
|
||||
articles That's the list of articles, ordsered desc. by date
|
||||
all the elements are `Article` objects, so you can
|
||||
access their properties (e.g. title, summary, author
|
||||
etc.
|
||||
dates The same list of article, but ordered by date,
|
||||
ascending
|
||||
tags A dict containing each tags (keys), and the list of
|
||||
relative articles.
|
||||
categories A dict containing each category (keys), and the
|
||||
list of relative articles.
|
||||
=============== ===================================================
|
||||
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".
|
||||
articles The list of articles, ordered descending by date.
|
||||
All the elements are `Article` objects, so you can
|
||||
access their attributes (e.g. title, summary, author
|
||||
etc.). Sometimes this is shadowed (for instance, in
|
||||
the tags page). You will then find info about it
|
||||
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
|
||||
all the categories and corresponding articles (values)
|
||||
tags A list of (tag, articles) tuples, containing all
|
||||
the tags and corresponding articles (values)
|
||||
pages The list of pages
|
||||
============= ===================================================
|
||||
hidden_pages The list of hidden pages
|
||||
draft_pages The list of draft pages
|
||||
=============== ===================================================
|
||||
|
||||
|
||||
Sorting
|
||||
-------
|
||||
|
||||
URL wrappers (currently categories, tags, and authors), have comparison methods
|
||||
that allow them to be easily sorted by name::
|
||||
|
||||
{% for tag, articles in tags|sort %}
|
||||
|
||||
If you want to sort based on different criteria, `Jinja's sort command`__ has a
|
||||
number of options.
|
||||
|
||||
__ https://jinja.palletsprojects.com/en/latest/templates/#sort
|
||||
|
||||
|
||||
Date Formatting
|
||||
---------------
|
||||
|
||||
Pelican formats the date according to your settings and locale
|
||||
(``DATE_FORMATS``/``DEFAULT_DATE_FORMAT``) and provides a ``locale_date``
|
||||
attribute. On the other hand, the ``date`` attribute will be a `datetime`_
|
||||
object. If you need custom formatting for a date different than your settings,
|
||||
use the Jinja filter ``strftime`` that comes with Pelican. Usage is same as
|
||||
Python `strftime`_ format, but the filter will do the right thing and format
|
||||
your date according to the locale given in your settings::
|
||||
|
||||
{{ article.date|strftime('%d %B %Y') }}
|
||||
|
||||
.. _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
|
||||
----------
|
||||
|
||||
This is the home page or index of your blog, generated at ``index.html``.
|
||||
|
||||
If pagination is active, subsequent pages will reside in
|
||||
``index{number}.html``.
|
||||
|
||||
====================== ===================================================
|
||||
Variable Description
|
||||
====================== ===================================================
|
||||
articles_paginator A paginator object for the list of articles
|
||||
articles_page The current page of articles
|
||||
articles_previous_page The previous page of articles (``None`` if page does
|
||||
not exist)
|
||||
articles_next_page The next page of articles (``None`` if page does
|
||||
not exist)
|
||||
dates_paginator A paginator object for the article list, ordered by
|
||||
date, ascending.
|
||||
dates_page The current page of articles, ordered by date,
|
||||
ascending.
|
||||
dates_previous_page The previous page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
dates_next_page The next page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
page_name 'index' -- useful for pagination links
|
||||
====================== ===================================================
|
||||
|
||||
|
||||
author.html
|
||||
-------------
|
||||
|
||||
This template will be processed for each of the existing authors, with output
|
||||
generated according to the ``AUTHOR_SAVE_AS`` setting (`Default:`
|
||||
``author/{slug}.html``). If pagination is active, subsequent pages will by
|
||||
default reside at ``author/{slug}{number}.html``.
|
||||
|
||||
====================== ===================================================
|
||||
Variable Description
|
||||
====================== ===================================================
|
||||
author The name of the author being processed
|
||||
articles Articles by this author
|
||||
dates Articles by this author, but ordered by date,
|
||||
ascending
|
||||
articles_paginator A paginator object for the list of articles
|
||||
articles_page The current page of articles
|
||||
articles_previous_page The previous page of articles (``None`` if page does
|
||||
not exist)
|
||||
articles_next_page The next page of articles (``None`` if page does
|
||||
not exist)
|
||||
dates_paginator A paginator object for the article list, ordered by
|
||||
date, ascending.
|
||||
dates_page The current page of articles, ordered by date,
|
||||
ascending.
|
||||
dates_previous_page The previous page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
dates_next_page The next page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
page_name AUTHOR_URL where everything after `{slug}` is
|
||||
removed -- useful for pagination links
|
||||
====================== ===================================================
|
||||
|
||||
|
||||
category.html
|
||||
-------------
|
||||
|
||||
This template will be processed for each of the existing categories, and will
|
||||
finally remain at output/category/`category_name`.html.
|
||||
This template will be processed for each of the existing categories, with
|
||||
output generated according to the ``CATEGORY_SAVE_AS`` setting (`Default:`
|
||||
``category/{slug}.html``). If pagination is active, subsequent pages will by
|
||||
default reside at ``category/{slug}{number}.html``.
|
||||
|
||||
====================== ===================================================
|
||||
Variable Description
|
||||
====================== ===================================================
|
||||
category The name of the category being processed
|
||||
articles Articles for this category
|
||||
dates Articles for this category, but ordered by date,
|
||||
ascending
|
||||
articles_paginator A paginator object for the list of articles
|
||||
articles_page The current page of articles
|
||||
articles_previous_page The previous page of articles (``None`` if page does
|
||||
not exist)
|
||||
articles_next_page The next page of articles (``None`` if page does
|
||||
not exist)
|
||||
dates_paginator A paginator object for the list of articles,
|
||||
ordered by date, ascending
|
||||
dates_page The current page of articles, ordered by date,
|
||||
ascending
|
||||
dates_previous_page The previous page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
dates_next_page The next page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
page_name CATEGORY_URL where everything after `{slug}` is
|
||||
removed -- useful for pagination links
|
||||
====================== ===================================================
|
||||
|
||||
============= ===================================================
|
||||
Variable Description
|
||||
============= ===================================================
|
||||
articles The articles of this category
|
||||
category The name of the category being processed
|
||||
============= ===================================================
|
||||
|
||||
article.html
|
||||
-------------
|
||||
|
||||
This template will be processed for each article. .html files will be outputed
|
||||
in output/`article_name`.html. Here are the specific variables it gets.
|
||||
This template will be processed for each article, with output generated
|
||||
according to the ``ARTICLE_SAVE_AS`` setting (`Default:` ``{slug}.html``). The
|
||||
following variables are available when rendering.
|
||||
|
||||
============= ===================================================
|
||||
Variable Description
|
||||
============= ===================================================
|
||||
article The article object to be displayed
|
||||
category The name of the category of the current article
|
||||
category The name of the category for the current article
|
||||
============= ===================================================
|
||||
|
||||
tag.html
|
||||
--------
|
||||
Any metadata that you put in the header of the article source file will be
|
||||
available as fields on the ``article`` object. The field name will be the same
|
||||
as the name of the metadata field, except in all-lowercase characters.
|
||||
|
||||
For each tag, this template will be processed. It will create .html files in
|
||||
/output/tag/`tag_name`.html
|
||||
For example, you could add a field called `FacebookImage` to your article
|
||||
metadata, as shown below:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
Title: I love Python more than music
|
||||
Date: 2013-11-06 10:06
|
||||
Tags: personal, python
|
||||
Category: Tech
|
||||
Slug: python-je-l-aime-a-mourir
|
||||
Author: Francis Cabrel
|
||||
FacebookImage: http://franciscabrel.com/images/pythonlove.png
|
||||
|
||||
This new metadata will be made available as `article.facebookimage` in your
|
||||
`article.html` template. This would allow you, for example, to specify an image
|
||||
for the Facebook open graph tags that will change for each article:
|
||||
|
||||
.. code-block:: html+jinja
|
||||
|
||||
<meta property="og:image" content="{{ article.facebookimage }}"/>
|
||||
|
||||
|
||||
page.html
|
||||
---------
|
||||
|
||||
This template will be processed for each page, with output generated according
|
||||
to the ``PAGE_SAVE_AS`` setting (`Default:` ``pages/{slug}.html``). The
|
||||
following variables are available when rendering.
|
||||
|
||||
============= ===================================================
|
||||
Variable Description
|
||||
============= ===================================================
|
||||
tag The name of the tag being processed
|
||||
articles Articles related to this tag
|
||||
page The page object to be displayed. You can access its
|
||||
title, slug, and content.
|
||||
============= ===================================================
|
||||
|
||||
|
||||
tag.html
|
||||
--------
|
||||
|
||||
This template will be processed for each tag, with output generated according
|
||||
to the ``TAG_SAVE_AS`` setting (`Default:` ``tag/{slug}.html``). If pagination
|
||||
is active, subsequent pages will by default reside at
|
||||
``tag/{slug}{number}.html``.
|
||||
|
||||
====================== ===================================================
|
||||
Variable Description
|
||||
====================== ===================================================
|
||||
tag The name of the tag being processed
|
||||
articles Articles related to this tag
|
||||
dates Articles related to this tag, but ordered by date,
|
||||
ascending
|
||||
articles_paginator A paginator object for the list of articles
|
||||
articles_page The current page of articles
|
||||
articles_previous_page The previous page of articles (``None`` if page does
|
||||
not exist)
|
||||
articles_next_page The next page of articles (``None`` if page does
|
||||
not exist)
|
||||
dates_paginator A paginator object for the list of articles,
|
||||
ordered by date, ascending
|
||||
dates_page The current page of articles, ordered by date,
|
||||
ascending
|
||||
dates_previous_page The previous page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
dates_next_page The next page of articles, ordered by date,
|
||||
ascending (``None`` if page does not exist)
|
||||
page_name TAG_URL where everything after `{slug}` is removed
|
||||
-- useful for pagination links
|
||||
====================== ===================================================
|
||||
|
||||
|
||||
period_archives.html
|
||||
--------------------
|
||||
|
||||
This template will be processed for each year of your posts if a path for
|
||||
``YEAR_ARCHIVE_SAVE_AS`` is defined, each month if ``MONTH_ARCHIVE_SAVE_AS`` is
|
||||
defined, and each day if ``DAY_ARCHIVE_SAVE_AS`` is defined.
|
||||
|
||||
=================== ===================================================
|
||||
Variable Description
|
||||
=================== ===================================================
|
||||
period A tuple of the form (`year`, `month`, `day`) that
|
||||
indicates the current time period. `year` and `day`
|
||||
are numbers while `month` is a string. This tuple
|
||||
only contains `year` if the time period is a
|
||||
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/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
|
||||
=======
|
||||
|
||||
Detail objects attributes that are available and useful in templates. Not all
|
||||
attributes are listed here, this is a selection of attributes considered useful
|
||||
in a template.
|
||||
|
||||
.. _object-article:
|
||||
|
||||
Article
|
||||
-------
|
||||
|
||||
The string representation of an Article is the `source_path` attribute.
|
||||
|
||||
====================== ===================================================
|
||||
Attribute Description
|
||||
====================== ===================================================
|
||||
author The :ref:`Author <object-author_cat_tag>` of
|
||||
this article.
|
||||
authors A list of :ref:`Authors <object-author_cat_tag>`
|
||||
of this article.
|
||||
category The :ref:`Category <object-author_cat_tag>`
|
||||
of this article.
|
||||
content The rendered content of the article.
|
||||
date Datetime object representing the article date.
|
||||
date_format Either default date format or locale date format.
|
||||
default_template Default template name.
|
||||
in_default_lang Boolean representing if the article is written
|
||||
in the default language.
|
||||
lang Language of the article.
|
||||
locale_date Date formatted by the `date_format`.
|
||||
metadata Article header metadata `dict`.
|
||||
save_as Location to save the article page.
|
||||
slug Page slug.
|
||||
source_path Full system path of the article source file.
|
||||
relative_source_path Relative path from PATH_ to the article source file.
|
||||
status The article status, can be any of 'published' or
|
||||
'draft'.
|
||||
summary Rendered summary content.
|
||||
tags List of :ref:`Tag <object-author_cat_tag>`
|
||||
objects.
|
||||
template Template name to use for rendering.
|
||||
title Title of the article.
|
||||
translations List of translations
|
||||
:ref:`Article <object-article>` objects.
|
||||
url URL to the article page.
|
||||
====================== ===================================================
|
||||
|
||||
.. _PATH: settings.html#PATH
|
||||
|
||||
|
||||
.. _object-author_cat_tag:
|
||||
|
||||
Author / Category / Tag
|
||||
-----------------------
|
||||
|
||||
The string representation of those objects is the `name` attribute.
|
||||
|
||||
=================== ===================================================
|
||||
Attribute Description
|
||||
=================== ===================================================
|
||||
name Name of this object [1]_.
|
||||
page_name Author page name.
|
||||
save_as Location to save the author page.
|
||||
slug Page slug.
|
||||
url URL to the author page.
|
||||
=================== ===================================================
|
||||
|
||||
.. [1] for Author object, coming from `:authors:` or `AUTHOR`.
|
||||
|
||||
.. _object-page:
|
||||
|
||||
Page
|
||||
----
|
||||
|
||||
The string representation of a Page is the `source_path` attribute.
|
||||
|
||||
===================== ===================================================
|
||||
Attribute Description
|
||||
===================== ===================================================
|
||||
author The :ref:`Author <object-author_cat_tag>` of
|
||||
this page.
|
||||
content The rendered content of the page.
|
||||
date Datetime object representing the page date.
|
||||
date_format Either default date format or locale date format.
|
||||
default_template Default template name.
|
||||
in_default_lang Boolean representing if the article is written
|
||||
in the default language.
|
||||
lang Language of the article.
|
||||
locale_date Date formatted by the `date_format`.
|
||||
metadata Page header metadata `dict`.
|
||||
save_as Location to save the page.
|
||||
slug Page slug.
|
||||
source_path Full system path of the page source file.
|
||||
relative_source_path Relative path from PATH_ to the page source file.
|
||||
status The page status, can be any of 'published', 'hidden' or
|
||||
'draft'.
|
||||
summary Rendered summary content.
|
||||
tags List of :ref:`Tag <object-author_cat_tag>`
|
||||
objects.
|
||||
template Template name to use for rendering.
|
||||
title Title of the page.
|
||||
translations List of translations
|
||||
:ref:`Article <object-article>` objects.
|
||||
url URL to the page.
|
||||
===================== ===================================================
|
||||
|
||||
.. _PATH: settings.html#PATH
|
||||
|
||||
|
||||
Feeds
|
||||
=====
|
||||
|
||||
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::
|
||||
|
||||
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
|
||||
TRANSLATION_FEED_RSS
|
||||
|
||||
|
||||
Inheritance
|
||||
===========
|
||||
|
||||
Since version 3.0, Pelican supports inheritance from the ``simple`` theme, so
|
||||
you can re-use the ``simple`` theme templates in your own themes.
|
||||
|
||||
If one of the mandatory files in the ``templates/`` directory of your theme is
|
||||
missing, it will be replaced by the matching template from the ``simple``
|
||||
theme. So if the HTML structure of a template in the ``simple`` theme is right
|
||||
for you, you don't have to write a new template from scratch.
|
||||
|
||||
You can also extend templates from the ``simple`` theme in your own themes by
|
||||
using the ``{% extends %}`` directive as in the following example:
|
||||
|
||||
.. code-block:: html+jinja
|
||||
|
||||
{% extends "!simple/index.html" %} <!-- extends the ``index.html`` template from the ``simple`` theme -->
|
||||
|
||||
{% extends "index.html" %} <!-- "regular" extending -->
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
With this system, it is possible to create a theme with just two files.
|
||||
|
||||
base.html
|
||||
"""""""""
|
||||
|
||||
The first file is the ``templates/base.html`` template:
|
||||
|
||||
.. code-block:: html+jinja
|
||||
|
||||
{% extends "!simple/base.html" %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/style.css" />
|
||||
{% endblock %}
|
||||
|
||||
1. On the first line, we extend the ``base.html`` template from the ``simple``
|
||||
theme, so we don't have to rewrite the entire file.
|
||||
2. On the third line, we open the ``head`` block which has already been defined
|
||||
in the ``simple`` theme.
|
||||
3. On the fourth line, the function ``super()`` keeps the content previously
|
||||
inserted in the ``head`` block.
|
||||
4. On the fifth line, we append a stylesheet to the page.
|
||||
5. On the last line, we close the ``head`` block.
|
||||
|
||||
This file will be extended by all the other templates, so the stylesheet will
|
||||
be linked from all pages.
|
||||
|
||||
style.css
|
||||
"""""""""
|
||||
|
||||
The second file is the ``static/css/style.css`` CSS stylesheet:
|
||||
|
||||
.. code-block:: css
|
||||
|
||||
body {
|
||||
font-family : monospace ;
|
||||
font-size : 100% ;
|
||||
background-color : white ;
|
||||
color : #111 ;
|
||||
width : 80% ;
|
||||
min-width : 400px ;
|
||||
min-height : 200px ;
|
||||
padding : 1em ;
|
||||
margin : 5% 10% ;
|
||||
border : thin solid gray ;
|
||||
border-radius : 5px ;
|
||||
display : block ;
|
||||
}
|
||||
|
||||
a:link { color : blue ; text-decoration : none ; }
|
||||
a:hover { color : blue ; text-decoration : underline ; }
|
||||
a:visited { color : blue ; }
|
||||
|
||||
h1 a { color : inherit !important }
|
||||
h2 a { color : inherit !important }
|
||||
h3 a { color : inherit !important }
|
||||
h4 a { color : inherit !important }
|
||||
h5 a { color : inherit !important }
|
||||
h6 a { color : inherit !important }
|
||||
|
||||
pre {
|
||||
margin : 2em 1em 2em 4em ;
|
||||
}
|
||||
|
||||
#menu li {
|
||||
display : inline ;
|
||||
}
|
||||
|
||||
#post-list {
|
||||
margin-bottom : 1em ;
|
||||
margin-top : 1em ;
|
||||
}
|
||||
|
||||
Download
|
||||
""""""""
|
||||
|
||||
You can download this example theme :download:`here <_static/theme-basic.zip>`.
|
||||
|
||||
|
||||
.. Links
|
||||
|
||||
.. _`Pelican Themes`: https://github.com/getpelican/pelican-themes
|
||||
|
|
|
|||
377
docs/tips.rst
Normal file
377
docs/tips.rst
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
Tips
|
||||
####
|
||||
|
||||
Here are some tips about Pelican that you might find useful.
|
||||
|
||||
Custom 404 Pages
|
||||
================
|
||||
|
||||
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``::
|
||||
|
||||
Title: Not Found
|
||||
Status: hidden
|
||||
Save_as: 404.html
|
||||
|
||||
The requested item could not be located. Perhaps you might want to check
|
||||
the [Archives](/archives.html)?
|
||||
|
||||
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::
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
For Apache::
|
||||
|
||||
ErrorDocument 404 /404.html
|
||||
|
||||
For Amazon S3, first navigate to the ``Static Site Hosting`` menu in the bucket
|
||||
settings on your AWS console. From there::
|
||||
|
||||
Error Document: 404.html
|
||||
|
||||
Publishing to GitHub 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>`_.
|
||||
|
||||
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
|
||||
on GitHub.
|
||||
|
||||
The excellent `ghp-import <https://github.com/davisp/ghp-import>`_, which can
|
||||
be installed with ``pip``, makes this process really easy.
|
||||
|
||||
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::
|
||||
|
||||
$ pelican content -o output -s pelicanconf.py
|
||||
$ ghp-import output -b gh-pages
|
||||
$ git push origin gh-pages
|
||||
|
||||
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.
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
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 ``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: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
|
||||
``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 main
|
||||
branch of your GitHub repository::
|
||||
|
||||
$ 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
|
||||
----------------
|
||||
|
||||
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/>`_.
|
||||
|
||||
Update your site on each commit
|
||||
-------------------------------
|
||||
|
||||
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``::
|
||||
|
||||
pelican content -o output -s pelicanconf.py && ghp-import output && git push origin gh-pages
|
||||
|
||||
Copy static files to the root of your site
|
||||
------------------------------------------
|
||||
|
||||
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::
|
||||
|
||||
STATIC_PATHS = ['images', 'extra/CNAME']
|
||||
EXTRA_PATH_METADATA = {'extra/CNAME': {'path': 'CNAME'},}
|
||||
|
||||
Note: use forward slashes, ``/``, even on Windows.
|
||||
|
||||
You can also use the ``EXTRA_PATH_METADATA`` mechanism to place a
|
||||
``favicon.ico`` or ``robots.txt`` at the root of any site.
|
||||
|
||||
How to add YouTube or Vimeo Videos
|
||||
==================================
|
||||
|
||||
The easiest way is to paste the embed code of the video from these sites
|
||||
directly into your source content.
|
||||
|
||||
Alternatively, you can also use Pelican plugins like ``liquid_tags``,
|
||||
``pelican_youtube``, or ``pelican_vimeo`` to embed videos in your content.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Develop Locally Using SSL
|
||||
==================================
|
||||
|
||||
Here's how you can set up your local pelican server to support SSL.
|
||||
|
||||
First, create a self-signed certificate and key using ``openssl`` (this creates ``cert.pem`` and ``key.pem``)::
|
||||
|
||||
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
|
||||
|
||||
And use this command to launch the server (the server starts within your ``output`` directory)::
|
||||
|
||||
python -m pelican.server 8443 --key=../key.pem --cert=../cert.pem
|
||||
|
||||
If you are using ``develop-server.sh``, add this to the top::
|
||||
|
||||
CERT="$BASEDIR/cert.pem"
|
||||
KEY="$BASEDIR/key.pem"
|
||||
|
||||
and modify the ``pelican.server`` line as follows::
|
||||
|
||||
$PY -m pelican.server $port --ssl --cert="$CERT" --key="$KEY" &
|
||||
|
|
@ -1,113 +1,687 @@
|
|||
import argparse
|
||||
import importlib.metadata
|
||||
import json
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import pprint
|
||||
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,
|
||||
PagesGenerator,
|
||||
SourceFileGenerator,
|
||||
StaticGenerator,
|
||||
TemplatePagesGenerator,
|
||||
)
|
||||
from pelican.plugins import signals
|
||||
from pelican.plugins._utils import get_plugin_name, load_plugins
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import read_settings
|
||||
from pelican.utils import clean_output_dir
|
||||
from pelican.utils import clean_output_dir, maybe_pluralize, wait_for_changes
|
||||
from pelican.writers import Writer
|
||||
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
||||
StaticGenerator, PdfGenerator)
|
||||
|
||||
VERSION = "2.5.2"
|
||||
try:
|
||||
__version__ = importlib.metadata.version("pelican")
|
||||
except Exception:
|
||||
__version__ = "unknown"
|
||||
|
||||
DEFAULT_CONFIG_NAME = "pelicanconf.py"
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def init_params(settings=None, path=None, theme=None, output_path=None,
|
||||
markup=None, keep=False):
|
||||
"""Read the settings, and performs some checks on the environment
|
||||
before doing anything else.
|
||||
"""
|
||||
if settings is None:
|
||||
settings = {}
|
||||
settings = read_settings(settings)
|
||||
path = path or settings['PATH']
|
||||
if path.endswith('/'):
|
||||
path = path[:-1]
|
||||
class Pelican:
|
||||
def __init__(self, settings):
|
||||
"""Pelican initialization
|
||||
|
||||
# define the default settings
|
||||
theme = theme or settings['THEME']
|
||||
output_path = output_path or settings['OUTPUT_PATH']
|
||||
output_path = os.path.realpath(output_path)
|
||||
markup = markup or settings['MARKUP']
|
||||
keep = keep or settings['KEEP_OUTPUT_DIRECTORY']
|
||||
Performs some checks on the environment before doing anything else.
|
||||
"""
|
||||
|
||||
# find the theme in pelican.theme if the given one does not exists
|
||||
if not os.path.exists(theme):
|
||||
theme_path = os.sep.join([os.path.dirname(
|
||||
os.path.abspath(__file__)), "themes/%s" % theme])
|
||||
if os.path.exists(theme_path):
|
||||
theme = theme_path
|
||||
# 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.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]):
|
||||
logger.debug("Adding current directory to system path")
|
||||
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)
|
||||
try:
|
||||
plugin.register()
|
||||
self.plugins.append(plugin)
|
||||
except Exception as 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]
|
||||
|
||||
def run(self):
|
||||
"""Run the generators and return"""
|
||||
start_time = time.time()
|
||||
|
||||
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"]
|
||||
|
||||
generators = [
|
||||
cls(
|
||||
context=context,
|
||||
settings=self.settings,
|
||||
path=self.path,
|
||||
theme=self.theme,
|
||||
output_path=self.output_path,
|
||||
)
|
||||
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)]
|
||||
):
|
||||
clean_output_dir(self.output_path, self.output_retention)
|
||||
|
||||
for p in generators:
|
||||
if hasattr(p, "generate_context"):
|
||||
p.generate_context()
|
||||
if hasattr(p, "check_disabled_readers"):
|
||||
p.check_disabled_readers()
|
||||
|
||||
# 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"):
|
||||
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))
|
||||
|
||||
pluralized_articles = maybe_pluralize(
|
||||
(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",
|
||||
)
|
||||
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",
|
||||
)
|
||||
pluralized_hidden_pages = maybe_pluralize(
|
||||
(
|
||||
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",
|
||||
)
|
||||
|
||||
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"),
|
||||
]
|
||||
|
||||
if self.settings["TEMPLATE_PAGES"]:
|
||||
discovered_generators.append((TemplatePagesGenerator, "internal"))
|
||||
|
||||
if self.settings["OUTPUT_SOURCES"]:
|
||||
discovered_generators.append((SourceFileGenerator, "internal"))
|
||||
|
||||
for receiver, values in signals.get_generators.send(self):
|
||||
if not isinstance(values, Iterable):
|
||||
values = (values,)
|
||||
for generator in values:
|
||||
if generator is None:
|
||||
continue # plugin did not return a generator
|
||||
discovered_generators.append((generator, receiver.__module__))
|
||||
|
||||
# StaticGenerator must run last, so it can identify files that
|
||||
# were skipped by the other generators, and so static files can
|
||||
# have their output paths overridden by the {attach} link syntax.
|
||||
discovered_generators.append((StaticGenerator, "internal"))
|
||||
|
||||
generators = []
|
||||
|
||||
for generator, origin in discovered_generators:
|
||||
if not isinstance(generator, type):
|
||||
logger.error("Generator %s (%s) cannot be loaded", generator, origin)
|
||||
continue
|
||||
|
||||
logger.debug("Found generator: %s (%s)", generator.__name__, origin)
|
||||
generators.append(generator)
|
||||
|
||||
return generators
|
||||
|
||||
def _get_writer(self):
|
||||
writers = [w for _, w in signals.get_writer.send(self) if isinstance(w, type)]
|
||||
num_writers = len(writers)
|
||||
|
||||
if num_writers == 0:
|
||||
return Writer(self.output_path, settings=self.settings)
|
||||
|
||||
if num_writers > 1:
|
||||
logger.warning("%s writers found, using only first one", num_writers)
|
||||
|
||||
writer = writers[0]
|
||||
|
||||
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):
|
||||
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, tuple, list)):
|
||||
setting_format = "\n{}:\n{}"
|
||||
else:
|
||||
setting_format = "\n{}: {}"
|
||||
console.print(
|
||||
setting_format.format(
|
||||
setting, pprint.pformat(settings[setting])
|
||||
)
|
||||
)
|
||||
else:
|
||||
console.print(f"\n{setting} is not a recognized setting.")
|
||||
break
|
||||
else:
|
||||
raise Exception("Impossible to find the theme %s" % theme)
|
||||
# No argument was given to --print-settings, so print all settings
|
||||
console.print(settings)
|
||||
|
||||
# get the list of files to parse
|
||||
if not path:
|
||||
raise Exception('you need to specify a path to search the docs on !')
|
||||
|
||||
return settings, path, theme, output_path, markup, keep
|
||||
parser.exit()
|
||||
|
||||
|
||||
def run_generators(generators, settings, path, theme, output_path, markup, keep):
|
||||
"""Run the generators and return"""
|
||||
|
||||
context = settings.copy()
|
||||
generators = [p(context, settings, path, theme, output_path, markup, keep)
|
||||
for p in generators]
|
||||
|
||||
for p in generators:
|
||||
if hasattr(p, 'generate_context'):
|
||||
p.generate_context()
|
||||
|
||||
# erase the directory if it is not the source
|
||||
if output_path not in os.path.realpath(path) and not keep:
|
||||
clean_output_dir(output_path)
|
||||
|
||||
writer = Writer(output_path)
|
||||
|
||||
for p in generators:
|
||||
if hasattr(p, 'generate_output'):
|
||||
p.generate_output(writer)
|
||||
class ParseOverrides(argparse.Action):
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
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)
|
||||
|
||||
|
||||
def run_pelican(settings, path, theme, output_path, markup, delete):
|
||||
"""Run pelican with the given parameters"""
|
||||
|
||||
params = init_params(settings, path, theme, output_path, markup, delete)
|
||||
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
|
||||
if params[0]['PDF_GENERATOR']: # param[0] is settings
|
||||
processors.append(PdfGenerator)
|
||||
run_generators(generators, *params)
|
||||
LOG_HANDLERS = {"plain": None, "rich": DEFAULT_LOG_HANDLER}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="""A tool to generate a
|
||||
static blog, with restructured text input files.""")
|
||||
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,
|
||||
)
|
||||
|
||||
parser.add_argument(dest='path',
|
||||
help='Path where to find the content files')
|
||||
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('-m', '--markup', default=None, dest='markup',
|
||||
help='the list of markup language to use (rst or md). Please indicate them'
|
||||
'separated by commas')
|
||||
parser.add_argument('-s', '--settings', dest='settings',
|
||||
help='the settings of the application. Default to None.')
|
||||
parser.add_argument('-k', '--keep-output-directory', dest='keep',
|
||||
action='store_true',
|
||||
help='Keep the output directory and just update all the generated files.'
|
||||
'Default is to delete the output directory.')
|
||||
parser.add_argument('--version', action='version', version=VERSION,
|
||||
help="Print the pelican version and exit")
|
||||
args = parser.parse_args()
|
||||
parser.add_argument(
|
||||
dest="path",
|
||||
nargs="?",
|
||||
help="Path where to find the content files.",
|
||||
default=None,
|
||||
)
|
||||
|
||||
# Split the markup languages only if some have been given. Otherwise, populate
|
||||
# the variable with None.
|
||||
markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else 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.",
|
||||
)
|
||||
|
||||
run_pelican(args.settings, args.path, args.theme, args.output, markup, args.keep)
|
||||
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 "
|
||||
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(
|
||||
"-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(
|
||||
"-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(
|
||||
"-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(
|
||||
"--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(
|
||||
"--ignore-cache",
|
||||
action="store_true",
|
||||
dest="ignore_cache",
|
||||
help="Ignore content cache from previous runs by not loading cache files.",
|
||||
)
|
||||
|
||||
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(
|
||||
"-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(
|
||||
"-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. 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")
|
||||
if args.bind is not None and not args.listen:
|
||||
logger.warning("--bind without --listen has no effect")
|
||||
|
||||
return args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
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))
|
||||
if 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
|
||||
if args.delete_outputdir is not None:
|
||||
config["DELETE_OUTPUT_DIRECTORY"] = args.delete_outputdir
|
||||
if args.ignore_cache:
|
||||
config["LOAD_CONTENT_CACHE"] = False
|
||||
if args.cache_path:
|
||||
config["CACHE_PATH"] = args.cache_path
|
||||
if args.relative_paths:
|
||||
config["RELATIVE_URLS"] = args.relative_paths
|
||||
if args.port is not None:
|
||||
config["PORT"] = args.port
|
||||
if args.bind is not None:
|
||||
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
|
||||
args.settings = DEFAULT_CONFIG_NAME
|
||||
|
||||
settings = read_settings(config_file, override=get_config(args))
|
||||
|
||||
cls = settings["PELICAN_CLASS"]
|
||||
if isinstance(cls, str):
|
||||
module, cls_name = cls.rsplit(".", 1)
|
||||
module = __import__(module)
|
||||
cls = getattr(module, cls_name)
|
||||
|
||||
return cls(settings), settings
|
||||
|
||||
|
||||
def autoreload(args, excqueue=None):
|
||||
console.print(
|
||||
" --- AutoReload Mode: Monitoring `content`, `theme` and"
|
||||
" `settings` for changes. ---"
|
||||
)
|
||||
pelican, settings = get_instance(args)
|
||||
settings_file = os.path.abspath(args.settings)
|
||||
while True:
|
||||
try:
|
||||
pelican.run()
|
||||
|
||||
changed_files = wait_for_changes(args.settings, settings)
|
||||
changed_files = {c[1] for c in changed_files}
|
||||
|
||||
if settings_file in changed_files:
|
||||
pelican, settings = get_instance(args)
|
||||
|
||||
console.print(
|
||||
"\n-> Modified: {}. re-generating...".format(", ".join(changed_files))
|
||||
)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
if excqueue is not None:
|
||||
excqueue.put(None)
|
||||
return
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
if args.verbosity == logging.DEBUG:
|
||||
if excqueue is not None:
|
||||
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)
|
||||
)
|
||||
|
||||
|
||||
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)
|
||||
except OSError as e:
|
||||
logging.error("Could not listen on port %s, server %s.", port, server)
|
||||
if excqueue is not None:
|
||||
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
|
||||
return
|
||||
|
||||
try:
|
||||
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:
|
||||
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
|
||||
return
|
||||
|
||||
except KeyboardInterrupt:
|
||||
httpd.socket.close()
|
||||
if excqueue is not None:
|
||||
return
|
||||
raise
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
args = parse_arguments(argv)
|
||||
logs_dedup_min_level = getattr(logging, args.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])
|
||||
|
||||
try:
|
||||
pelican, settings = get_instance(args)
|
||||
|
||||
if args.autoreload and args.listen:
|
||||
excqueue = multiprocessing.Queue()
|
||||
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,
|
||||
),
|
||||
)
|
||||
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")
|
||||
)
|
||||
else:
|
||||
with console.status("Generating..."):
|
||||
pelican.run()
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("Keyboard interrupt received. Exiting.")
|
||||
except Exception as e:
|
||||
logger.critical("%s: %s", e.__class__.__name__, e)
|
||||
|
||||
if args.verbosity == logging.DEBUG:
|
||||
console.print_exception()
|
||||
sys.exit(getattr(e, "exitcode", 1))
|
||||
|
|
|
|||
8
pelican/__main__.py
Normal file
8
pelican/__main__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
"""
|
||||
python -m pelican module entry point to run via python -m
|
||||
"""
|
||||
|
||||
from . import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
139
pelican/cache.py
Normal file
139
pelican/cache.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
import gzip
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import pickle
|
||||
|
||||
from pelican.utils import mkdir_p
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileDataCacher:
|
||||
"""Class that can cache data contained in files"""
|
||||
|
||||
def __init__(self, settings, cache_name, caching_policy, load_policy):
|
||||
"""Load the specified cache within CACHE_PATH in settings
|
||||
|
||||
only if *load_policy* is True,
|
||||
May use gzip if GZIP_CACHE ins settings is True.
|
||||
Sets caching policy according to *caching_policy*.
|
||||
"""
|
||||
self.settings = settings
|
||||
self._cache_path = os.path.join(self.settings["CACHE_PATH"], cache_name)
|
||||
self._cache_data_policy = caching_policy
|
||||
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:
|
||||
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,
|
||||
)
|
||||
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,
|
||||
)
|
||||
self._cache = {}
|
||||
else:
|
||||
self._cache = {}
|
||||
|
||||
def cache_data(self, filename, data):
|
||||
"""Cache data for given file"""
|
||||
if self._cache_data_policy:
|
||||
self._cache[filename] = data
|
||||
|
||||
def get_cached_data(self, filename, default=None):
|
||||
"""Get cached data for the given file
|
||||
|
||||
if no data is cached, return the default object
|
||||
"""
|
||||
return self._cache.get(filename, default)
|
||||
|
||||
def save_cache(self):
|
||||
"""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:
|
||||
pickle.dump(self._cache, fhandle)
|
||||
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 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":
|
||||
self._filestamp_func = os.path.getmtime
|
||||
else:
|
||||
try:
|
||||
hash_func = getattr(hashlib, method)
|
||||
|
||||
def filestamp_func(filename):
|
||||
"""return hash of file contents"""
|
||||
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)
|
||||
self._filestamp_func = None
|
||||
|
||||
def cache_data(self, filename, data):
|
||||
"""Cache stamp and data for the given file"""
|
||||
stamp = self._get_file_stamp(filename)
|
||||
super().cache_data(filename, (stamp, data))
|
||||
|
||||
def _get_file_stamp(self, filename):
|
||||
"""Check if the given file has been modified
|
||||
since the previous build.
|
||||
|
||||
depending on CHECK_MODIFIED_METHOD
|
||||
a float may be returned for 'mtime',
|
||||
a hash for a function name in the hashlib module
|
||||
or an empty bytes string otherwise
|
||||
"""
|
||||
|
||||
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 ""
|
||||
|
||||
def get_cached_data(self, filename, default=None):
|
||||
"""Get the cached data for the given filename
|
||||
if the file has not been modified.
|
||||
|
||||
If no record exists or file has been modified, return default.
|
||||
Modification is checked by comparing the cached
|
||||
and current file stamp.
|
||||
"""
|
||||
|
||||
stamp, data = super().get_cached_data(filename, (None, default))
|
||||
if stamp != self._get_file_stamp(filename):
|
||||
return default
|
||||
return data
|
||||
|
|
@ -1,59 +1,692 @@
|
|||
from pelican.utils import slugify, truncate_html_words
|
||||
import copy
|
||||
import datetime
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from html import unescape
|
||||
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
|
||||
|
||||
|
||||
class Page(object):
|
||||
"""Represents a page
|
||||
Given a content, and metadatas, create an adequate object.
|
||||
from pelican.plugins import signals
|
||||
from pelican.settings import DEFAULT_CONFIG, Settings
|
||||
|
||||
# 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__)
|
||||
|
||||
|
||||
class Content:
|
||||
"""Represents a content.
|
||||
|
||||
:param content: the string to parse, containing the original content.
|
||||
:param metadata: the metadata associated to this page (optional).
|
||||
:param settings: the settings dictionary (optional).
|
||||
:param source_path: The location of the source of this content (if any).
|
||||
:param context: The shared context between generators.
|
||||
|
||||
:param string: the string to parse, containing the original content.
|
||||
:param markup: the markup language to use while parsing.
|
||||
"""
|
||||
mandatory_properties = ('title',)
|
||||
|
||||
def __init__(self, content, metadatas={}, settings={}, filename=None):
|
||||
self.content = content
|
||||
self.status = "published" # default value
|
||||
for key, value in metadatas.items():
|
||||
setattr(self, key, value)
|
||||
default_template: Optional[str] = None
|
||||
mandatory_properties: tuple[str, ...] = ()
|
||||
|
||||
if not hasattr(self, 'author'):
|
||||
if 'AUTHOR' in settings:
|
||||
self.author = settings['AUTHOR']
|
||||
@deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0))
|
||||
def filename():
|
||||
return None
|
||||
|
||||
if filename:
|
||||
self.filename = filename
|
||||
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:
|
||||
settings = copy.deepcopy(DEFAULT_CONFIG)
|
||||
|
||||
def check_properties(self):
|
||||
"""test that each mandatory property is set."""
|
||||
self.settings = settings
|
||||
self._content = content
|
||||
if context is None:
|
||||
context = {}
|
||||
self._context = context
|
||||
self.translations = []
|
||||
|
||||
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
|
||||
setattr(self, key.lower(), value)
|
||||
|
||||
# also keep track of the metadata attributes available
|
||||
self.metadata = local_metadata
|
||||
|
||||
# default template if it's not defined in page
|
||||
self.template = self._get_template()
|
||||
|
||||
# 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"):
|
||||
self.author = self.authors[0]
|
||||
elif "AUTHOR" in settings:
|
||||
self.author = Author(settings["AUTHOR"], settings)
|
||||
|
||||
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"):
|
||||
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"):
|
||||
value = self.title
|
||||
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),
|
||||
)
|
||||
|
||||
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]
|
||||
else:
|
||||
self.date_format = settings["DEFAULT_DATE_FORMAT"]
|
||||
|
||||
if isinstance(self.date_format, tuple):
|
||||
locale_string = self.date_format[0]
|
||||
locale.setlocale(locale.LC_ALL, locale_string)
|
||||
self.date_format = self.date_format[1]
|
||||
|
||||
# manage timezone
|
||||
default_timezone = settings.get("TIMEZONE", "UTC")
|
||||
timezone = getattr(self, "timezone", default_timezone)
|
||||
self.timezone = ZoneInfo(timezone)
|
||||
|
||||
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"):
|
||||
self.modified = set_date_tzinfo(self.modified, timezone)
|
||||
self.locale_modified = self.modified.strftime(self.date_format)
|
||||
|
||||
# manage status
|
||||
if not hasattr(self, "status"):
|
||||
# Previous default of None broke comment plugins and perhaps others
|
||||
self.status = getattr(self, "default_status", "")
|
||||
|
||||
# store the summary metadata if it is set
|
||||
if "summary" in metadata:
|
||||
self._summary = metadata["summary"]
|
||||
|
||||
signals.content_object_init.send(self)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.source_path or repr(self)
|
||||
|
||||
def _has_valid_mandatory_properties(self) -> bool:
|
||||
"""Test mandatory properties are set."""
|
||||
for prop in self.mandatory_properties:
|
||||
if not hasattr(self, prop):
|
||||
raise NameError(prop)
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return '%s.html' % self.slug
|
||||
|
||||
@property
|
||||
def slug(self):
|
||||
return slugify(self.title)
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
return truncate_html_words(self.content, 50)
|
||||
|
||||
|
||||
class Article(Page):
|
||||
mandatory_properties = ('title', 'date', 'category')
|
||||
|
||||
|
||||
class Quote(Page):
|
||||
base_properties = ('author', 'date')
|
||||
|
||||
|
||||
def is_valid_content(content, f):
|
||||
try:
|
||||
content.check_properties()
|
||||
logger.error(
|
||||
"Skipping %s: could not find information about '%s'", self, prop
|
||||
)
|
||||
return False
|
||||
return True
|
||||
except NameError as e:
|
||||
print u" [info] Skipping %s: impossible to find informations about '%s'" % (f, e)
|
||||
|
||||
def _has_valid_save_as(self) -> bool:
|
||||
"""Return true if save_as doesn't write outside output path, false
|
||||
otherwise."""
|
||||
try:
|
||||
output_path = self.settings["OUTPUT_PATH"]
|
||||
except KeyError:
|
||||
# we cannot check
|
||||
return True
|
||||
|
||||
try:
|
||||
sanitised_join(output_path, self.save_as)
|
||||
except RuntimeError: # outside output_dir
|
||||
logger.error(
|
||||
"Skipping %s: file %r would be written outside output path",
|
||||
self,
|
||||
self.save_as,
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
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. (Not in %s)",
|
||||
self.status,
|
||||
self,
|
||||
self.allowed_statuses,
|
||||
)
|
||||
return False
|
||||
|
||||
# if undefined we allow all
|
||||
return True
|
||||
|
||||
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(),
|
||||
]
|
||||
)
|
||||
|
||||
@property
|
||||
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 "",
|
||||
}
|
||||
)
|
||||
return metadata
|
||||
|
||||
def _expand_settings(self, key: str, klass: Optional[str] = None) -> str:
|
||||
if not klass:
|
||||
klass = self.__class__.__name__
|
||||
fq_key = (f"{klass}_{key}").upper()
|
||||
return str(self.settings[fq_key]).format(**self.url_format)
|
||||
|
||||
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: str, m: re.Match) -> str:
|
||||
what = m.group("what")
|
||||
value = urlparse(m.group("value"))
|
||||
path = value.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
|
||||
# properly get `../a.html`. However, os.path.join() produces
|
||||
# `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"]:
|
||||
joiner = os.path.join
|
||||
else:
|
||||
joiner = urljoin
|
||||
|
||||
# However, it's not *that* simple: urljoin("blog", "index.html")
|
||||
# produces just `index.html` instead of `blog/index.html` (unlike
|
||||
# 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 += "/"
|
||||
|
||||
# XXX Put this in a different location.
|
||||
if what in {"filename", "static", "attach"}:
|
||||
|
||||
def _get_linked_content(key: str, url: ParseResult) -> Optional[Content]:
|
||||
nonlocal value
|
||||
|
||||
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( # type: ignore
|
||||
os.path.join(self.relative_dir, path)
|
||||
)
|
||||
return self._context[key].get(path, None)
|
||||
|
||||
# try path
|
||||
result = _find_path(url.path)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# try unquoted path
|
||||
result = _find_path(unquote(url.path))
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# try html unescaped url
|
||||
unescaped_url = urlparse(unescape(url.geturl()))
|
||||
result = _find_path(unescaped_url.path)
|
||||
if result is not None:
|
||||
value = unescaped_url
|
||||
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 linked_content:
|
||||
logger.warning(
|
||||
"{filename} used for linking to static"
|
||||
" content %s in %s. Use {static} instead",
|
||||
value.path,
|
||||
self.get_relative_source_path(),
|
||||
)
|
||||
return linked_content
|
||||
|
||||
return None
|
||||
|
||||
if what == "filename":
|
||||
key = "generated_content"
|
||||
else:
|
||||
key = "static_content"
|
||||
|
||||
linked_content = _get_linked_content(key, value)
|
||||
if linked_content:
|
||||
if what == "attach":
|
||||
linked_content.attach_to(self) # type: ignore
|
||||
origin = joiner(siteurl, linked_content.url)
|
||||
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":
|
||||
origin = joiner(siteurl, Category(path, self.settings).url)
|
||||
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":
|
||||
origin = joiner(siteurl, Author(path, self.settings).url)
|
||||
else:
|
||||
logger.warning(
|
||||
"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")))
|
||||
|
||||
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|content)\s*=\s*)
|
||||
|
||||
(?P<quote>["\']) # require value to be quoted
|
||||
(?P<path>{intrasite_link_regex}(?P<value>.*?)) # the url value
|
||||
(?P=quote)"""
|
||||
return re.compile(regex, re.X)
|
||||
|
||||
def _update_content(self, content: str, siteurl: str) -> str:
|
||||
"""Update the content attribute.
|
||||
|
||||
Change all the relative paths of the content to relative paths
|
||||
suitable for the output content.
|
||||
|
||||
:param content: content resource that will be passed to the templates.
|
||||
:param siteurl: siteurl which is locally generated by the writer in
|
||||
case of RELATIVE_URLS.
|
||||
"""
|
||||
if not content:
|
||||
return content
|
||||
|
||||
hrefs = self._get_intrasite_link_regex()
|
||||
return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content)
|
||||
|
||||
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"))
|
||||
path = value.path
|
||||
if what not in {"static", "attach"}:
|
||||
continue
|
||||
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", " ") # type: ignore
|
||||
static_links.add(path)
|
||||
return static_links
|
||||
|
||||
def get_siteurl(self) -> str:
|
||||
return self._context.get("localsiteurl", "")
|
||||
|
||||
@memoized
|
||||
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) -> str:
|
||||
return self.get_content(self.get_siteurl())
|
||||
|
||||
@memoized
|
||||
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"]
|
||||
|
||||
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)
|
||||
|
||||
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) -> str:
|
||||
return self.get_summary(self.get_siteurl())
|
||||
|
||||
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"
|
||||
)
|
||||
return self.summary
|
||||
|
||||
@summary.setter
|
||||
def summary(self, value: str):
|
||||
"""Dummy function"""
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, value: str) -> None:
|
||||
# TODO maybe typecheck
|
||||
self._status = value.lower()
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return self.get_url_setting("url")
|
||||
|
||||
@property
|
||||
def save_as(self) -> str:
|
||||
return self.get_url_setting("save_as")
|
||||
|
||||
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: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
"""Return the relative path (from the content path) to the given
|
||||
source_path.
|
||||
|
||||
If no source path is specified, use the source path of this
|
||||
content object.
|
||||
"""
|
||||
if not source_path:
|
||||
source_path = self.source_path
|
||||
if source_path is None:
|
||||
return None
|
||||
|
||||
return posixize_path(
|
||||
os.path.relpath(
|
||||
os.path.abspath(os.path.join(self.settings["PATH"], source_path)),
|
||||
os.path.abspath(self.settings["PATH"]),
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
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) -> 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, 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", "skip")
|
||||
default_status = "published"
|
||||
default_template = "page"
|
||||
|
||||
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", "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 self.date.tzinfo is None:
|
||||
now = datetime.datetime.now()
|
||||
else:
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
if self.date > now:
|
||||
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":
|
||||
self.date = datetime.datetime.max.replace(tzinfo=self.timezone)
|
||||
|
||||
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"
|
||||
default_template = None
|
||||
|
||||
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))
|
||||
def filepath():
|
||||
return None
|
||||
|
||||
@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))
|
||||
def dst():
|
||||
return None
|
||||
|
||||
@property
|
||||
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) -> 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: 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
|
||||
# document's source directory, preserve that relationship on output.
|
||||
# Otherwise, make it a sibling.
|
||||
|
||||
linking_source_dir = os.path.dirname(content.source_path)
|
||||
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)
|
||||
|
||||
# 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
|
||||
# whether it points to the document itself or to its parent directory.
|
||||
# (An url like 'some/content' might mean a directory named 'some'
|
||||
# with a file named 'content', or it might mean a directory named
|
||||
# 'some/content' with a file named 'index.html'.) Rather than trying
|
||||
# to figure it out by comparing the linking document's url and save_as
|
||||
# path, we simply build our new url from our new save_as path.
|
||||
|
||||
new_url = path_to_url(new_save_as)
|
||||
|
||||
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."},
|
||||
)
|
||||
|
||||
# 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 new_save_as != self.save_as or new_url != self.url:
|
||||
_log_reason("its output location was already overridden")
|
||||
return
|
||||
|
||||
# We never change an output path that has already been referenced,
|
||||
# because we don't want to break links that depend on that path.
|
||||
if self._output_location_referenced:
|
||||
if new_save_as != self.save_as or new_url != self.url:
|
||||
_log_reason("another link already referenced its location")
|
||||
return
|
||||
|
||||
self.override_save_as = new_save_as
|
||||
self.override_url = new_url
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
173
pelican/log.py
Normal file
173
pelican/log.py
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
import logging
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
|
||||
from rich.console import Console
|
||||
from rich.logging import RichHandler
|
||||
|
||||
__all__ = ["init"]
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
class LimitFilter(logging.Filter):
|
||||
"""
|
||||
Remove duplicates records, and limit the number of records in the same
|
||||
group.
|
||||
|
||||
Groups are specified by the message to use when the number of records in
|
||||
the same group hit the limit.
|
||||
E.g.: log.warning(('43 is not the answer', 'More erroneous answers'))
|
||||
"""
|
||||
|
||||
LOGS_DEDUP_MIN_LEVEL = logging.WARNING
|
||||
|
||||
_ignore = set()
|
||||
_raised_messages = set()
|
||||
_threshold = 5
|
||||
_group_count = defaultdict(int)
|
||||
|
||||
def filter(self, record):
|
||||
# don't limit log messages for anything above "warning"
|
||||
if record.levelno > self.LOGS_DEDUP_MIN_LEVEL:
|
||||
return True
|
||||
|
||||
# extract group
|
||||
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())
|
||||
if message_key in self._raised_messages:
|
||||
return False
|
||||
else:
|
||||
self._raised_messages.add(message_key)
|
||||
|
||||
# ignore LOG_FILTER records by templates or messages
|
||||
# when "debug" isn't enabled
|
||||
logger_level = logging.getLogger().getEffectiveLevel()
|
||||
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:
|
||||
return False
|
||||
|
||||
# check if we went over threshold
|
||||
if group:
|
||||
key = (record.levelno, group)
|
||||
self._group_count[key] += 1
|
||||
if self._group_count[key] == self._threshold:
|
||||
record.msg = group
|
||||
record.args = group_args
|
||||
elif self._group_count[key] > self._threshold:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class LimitLogger(logging.Logger):
|
||||
"""
|
||||
A logger which adds LimitFilter automatically
|
||||
"""
|
||||
|
||||
limit_filter = LimitFilter()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.enable_filter()
|
||||
|
||||
def disable_filter(self):
|
||||
self.removeFilter(LimitLogger.limit_filter)
|
||||
|
||||
def enable_filter(self):
|
||||
self.addFilter(LimitLogger.limit_filter)
|
||||
|
||||
|
||||
class FatalLogger(LimitLogger):
|
||||
warnings_fatal = False
|
||||
errors_fatal = False
|
||||
|
||||
def warning(self, *args, stacklevel=1, **kwargs):
|
||||
"""
|
||||
Displays a logging warning.
|
||||
|
||||
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")
|
||||
|
||||
|
||||
logging.setLoggerClass(FatalLogger)
|
||||
# force root logger to be of our preferred class
|
||||
logging.getLogger().__class__ = FatalLogger
|
||||
|
||||
DEFAULT_LOG_HANDLER = RichHandler(console=console)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
LOG_FORMAT = "%(message)s"
|
||||
logging.basicConfig(
|
||||
level=level,
|
||||
format=LOG_FORMAT,
|
||||
datefmt="[%H:%M:%S]",
|
||||
handlers=[handler] if handler else [],
|
||||
)
|
||||
|
||||
logger = logging.getLogger(name)
|
||||
|
||||
if level:
|
||||
logger.setLevel(level)
|
||||
if logs_dedup_min_level:
|
||||
LimitFilter.LOGS_DEDUP_MIN_LEVEL = logs_dedup_min_level
|
||||
|
||||
|
||||
def log_warnings():
|
||||
logging.captureWarnings(True)
|
||||
warnings.simplefilter("default", DeprecationWarning)
|
||||
init(logging.DEBUG, name="py.warnings")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init(level=logging.DEBUG, name=__name__)
|
||||
|
||||
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")
|
||||
171
pelican/paginator.py
Normal file
171
pelican/paginator.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import functools
|
||||
import logging
|
||||
import os
|
||||
from collections import namedtuple
|
||||
from math import ceil
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
PaginationRule = namedtuple( # noqa: PYI024
|
||||
"PaginationRule",
|
||||
"min_page URL SAVE_AS",
|
||||
)
|
||||
|
||||
|
||||
class Paginator:
|
||||
def __init__(self, name, url, object_list, settings, per_page=None):
|
||||
self.name = name
|
||||
self.url = url
|
||||
self.object_list = object_list
|
||||
self.settings = settings
|
||||
if per_page:
|
||||
self.per_page = per_page
|
||||
self.orphans = settings["DEFAULT_ORPHANS"]
|
||||
else:
|
||||
self.per_page = len(object_list)
|
||||
self.orphans = 0
|
||||
|
||||
self._num_pages = self._count = None
|
||||
|
||||
def page(self, number):
|
||||
"Returns a Page object for the given 1-based page number."
|
||||
bottom = (number - 1) * self.per_page
|
||||
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,
|
||||
)
|
||||
|
||||
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 = ceil(hits / (float(self.per_page) or 1))
|
||||
return self._num_pages
|
||||
|
||||
num_pages = property(_get_num_pages)
|
||||
|
||||
def _get_page_range(self):
|
||||
"""
|
||||
Returns a 1-based range of pages for iterating through within
|
||||
a template for loop.
|
||||
"""
|
||||
return list(range(1, self.num_pages + 1))
|
||||
|
||||
page_range = property(_get_page_range)
|
||||
|
||||
|
||||
class Page:
|
||||
def __init__(self, name, url, object_list, number, paginator, settings):
|
||||
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_url = url
|
||||
self.object_list = object_list
|
||||
self.number = number
|
||||
self.paginator = paginator
|
||||
self.settings = settings
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Page {self.number} of {self.paginator.num_pages}>"
|
||||
|
||||
def has_next(self):
|
||||
return self.number < self.paginator.num_pages
|
||||
|
||||
def has_previous(self):
|
||||
return self.number > 1
|
||||
|
||||
def has_other_pages(self):
|
||||
return self.has_previous() or self.has_next()
|
||||
|
||||
def next_page_number(self):
|
||||
return self.number + 1
|
||||
|
||||
def previous_page_number(self):
|
||||
return self.number - 1
|
||||
|
||||
def start_index(self):
|
||||
"""
|
||||
Returns the 1-based index of the first object on this page,
|
||||
relative to total objects in the paginator.
|
||||
"""
|
||||
# Special case, return zero if no items.
|
||||
if self.paginator.count == 0:
|
||||
return 0
|
||||
return (self.paginator.per_page * (self.number - 1)) + 1
|
||||
|
||||
def end_index(self):
|
||||
"""
|
||||
Returns the 1-based index of the last object on this page,
|
||||
relative to total objects found (hits).
|
||||
"""
|
||||
# Special case for the last page because there can be orphans.
|
||||
if self.number == self.paginator.num_pages:
|
||||
return self.paginator.count
|
||||
return self.number * self.paginator.per_page
|
||||
|
||||
def _from_settings(self, key):
|
||||
"""Returns URL information as defined in settings. Similar to
|
||||
URLWrapper._from_settings, but specialized to deal with pagination
|
||||
logic."""
|
||||
|
||||
rule = None
|
||||
|
||||
# find the last matching pagination rule
|
||||
for p in self.settings["PAGINATION_PATTERNS"]:
|
||||
if p.min_page == -1:
|
||||
if not self.has_next():
|
||||
rule = p
|
||||
break
|
||||
elif p.min_page <= self.number:
|
||||
rule = p
|
||||
|
||||
if not rule:
|
||||
return ""
|
||||
|
||||
prop_value = getattr(rule, key)
|
||||
|
||||
if not isinstance(prop_value, str):
|
||||
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,
|
||||
}
|
||||
|
||||
ret = prop_value.format(**context)
|
||||
# Remove a single leading slash, if any. This is done for backwards
|
||||
# compatibility reasons. If a leading slash is needed (for URLs
|
||||
# relative to server root or absolute URLs without the scheme such as
|
||||
# //blog.my.site/), it can be worked around by prefixing the pagination
|
||||
# pattern by an additional slash (which then gets removed, preserving
|
||||
# the other slashes). This also means the following code *can't* be
|
||||
# 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.startswith("/"):
|
||||
ret = ret[1:]
|
||||
return ret
|
||||
|
||||
url = property(functools.partial(_from_settings, key="URL"))
|
||||
save_as = property(functools.partial(_from_settings, key="SAVE_AS"))
|
||||
138
pelican/plugins/_utils.py
Normal file
138
pelican/plugins/_utils.py
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
import importlib
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import inspect
|
||||
import logging
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def iter_namespace(ns_pkg):
|
||||
# Specifying the second argument (prefix) to iter_modules makes the
|
||||
# returned name an absolute name instead of a relative one. This allows
|
||||
# import_module to work without having to do additional modification to
|
||||
# the name.
|
||||
return pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + ".")
|
||||
|
||||
|
||||
def get_namespace_plugins(ns_pkg=None):
|
||||
if ns_pkg is None:
|
||||
import pelican.plugins as ns_pkg # noqa: PLC0415
|
||||
|
||||
return {
|
||||
name: importlib.import_module(name)
|
||||
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 # 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))
|
||||
else:
|
||||
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:
|
||||
# it is in a package, try to resolve package first
|
||||
package, _, _ = plugin.rpartition(".")
|
||||
load_legacy_plugin(package, plugin_paths)
|
||||
|
||||
# Try to find plugin in PLUGIN_PATHS
|
||||
spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths)
|
||||
if spec is None:
|
||||
# If failed, try to find it in normal importable locations
|
||||
spec = importlib.util.find_spec(plugin)
|
||||
if spec is None:
|
||||
raise ImportError(f"Cannot import plugin `{plugin}`")
|
||||
else:
|
||||
# Avoid loading the same plugin twice
|
||||
if spec.name in sys.modules:
|
||||
return sys.modules[spec.name]
|
||||
# create module object from spec
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
# place it into sys.modules cache
|
||||
# necessary if module imports itself at some point (e.g. packages)
|
||||
sys.modules[spec.name] = mod
|
||||
try:
|
||||
# try to execute it inside module object
|
||||
spec.loader.exec_module(mod)
|
||||
except Exception: # problem with import
|
||||
try:
|
||||
# remove module from sys.modules since it can't be loaded
|
||||
del sys.modules[spec.name]
|
||||
except KeyError:
|
||||
pass
|
||||
raise
|
||||
|
||||
# if all went well, we have the plugin module
|
||||
return mod
|
||||
|
||||
|
||||
def load_plugins(settings):
|
||||
logger.debug("Finding namespace plugins")
|
||||
namespace_plugins = get_namespace_plugins()
|
||||
if 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 isinstance(plugin, str):
|
||||
logger.debug("Loading plugin `%s`", plugin)
|
||||
# try to find in namespace plugins
|
||||
if plugin in namespace_plugins:
|
||||
plugin = namespace_plugins[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", [])
|
||||
)
|
||||
except ImportError as e:
|
||||
logger.error("Cannot load plugin `%s`\n%s", plugin, e)
|
||||
continue
|
||||
plugins.append(plugin)
|
||||
else:
|
||||
plugins = list(namespace_plugins.values())
|
||||
|
||||
return plugins
|
||||
|
||||
|
||||
def get_plugin_name(plugin):
|
||||
"""
|
||||
Plugins can be passed as module objects, however this breaks caching as
|
||||
module objects cannot be pickled. To work around this, all plugins are
|
||||
stringified post-initialization.
|
||||
"""
|
||||
if inspect.isclass(plugin):
|
||||
return plugin.__qualname__
|
||||
|
||||
if inspect.ismodule(plugin):
|
||||
return plugin.__name__
|
||||
|
||||
return type(plugin).__qualname__
|
||||
53
pelican/plugins/signals.py
Normal file
53
pelican/plugins/signals.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
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")
|
||||
|
||||
# Reader-level signals
|
||||
|
||||
readers_init = signal("readers_init")
|
||||
|
||||
# Generator-level signals
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
# Page-level signals
|
||||
|
||||
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")
|
||||
|
||||
static_generator_preread = signal("static_generator_preread")
|
||||
static_generator_context = signal("static_generator_context")
|
||||
|
||||
content_object_init = signal("content_object_init")
|
||||
|
||||
# Writers signals
|
||||
content_written = signal("content_written")
|
||||
feed_generated = signal("feed_generated")
|
||||
feed_written = signal("feed_written")
|
||||
|
|
@ -1,70 +1,825 @@
|
|||
from docutils import core
|
||||
from markdown import Markdown
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from html import escape
|
||||
from html.parser import HTMLParser
|
||||
from io import StringIO
|
||||
|
||||
# import the directives to have pygments support
|
||||
import rstdirectives
|
||||
import docutils
|
||||
import docutils.core
|
||||
import docutils.io
|
||||
from docutils.parsers.rst.languages import get_language as get_docutils_lang
|
||||
from docutils.writers.html4css1 import HTMLTranslator, Writer
|
||||
|
||||
from pelican.utils import get_date, open
|
||||
from pelican import rstdirectives # NOQA
|
||||
from pelican.cache import FileStampDataCacher
|
||||
from pelican.contents import Author, Category, Page, SkipStub, Tag
|
||||
from pelican.plugins import signals
|
||||
from pelican.utils import file_suffix, get_date, pelican_open, posixize_path
|
||||
|
||||
try:
|
||||
from markdown import Markdown
|
||||
except ImportError:
|
||||
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.
|
||||
# This means that _filter_discardable_metadata() must be called on processed
|
||||
# metadata dicts before use, to remove the items with the special value.
|
||||
_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,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_METADATAS_FIELDS = {'tags': lambda x: x.split(', '),
|
||||
'date': lambda x: get_date(x),
|
||||
'category': lambda x: x,
|
||||
'author': lambda x: x,
|
||||
'status': lambda x:x.strip(),}
|
||||
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.
|
||||
|
||||
Regardless, all list items undergo .strip() before returning, and
|
||||
empty items are discarded.
|
||||
"""
|
||||
if isinstance(text, str):
|
||||
if ";" in text:
|
||||
text = text.split(";")
|
||||
else:
|
||||
text = text.split(",")
|
||||
|
||||
return list(OrderedDict.fromkeys([v for v in (w.strip() for w in text) if v]))
|
||||
|
||||
|
||||
class RstReader(object):
|
||||
def _process_if_nonempty(processor, name, settings):
|
||||
"""Removes extra whitespace from name and applies a metadata processor.
|
||||
If name is empty or all whitespace, returns _DISCARD instead.
|
||||
"""
|
||||
name = name.strip()
|
||||
return processor(name, settings) if name else _DISCARD
|
||||
|
||||
|
||||
def _filter_discardable_metadata(metadata):
|
||||
"""Return a copy of a dict, minus any items marked as discardable."""
|
||||
return {name: val for name, val in metadata.items() if val is not _DISCARD}
|
||||
|
||||
|
||||
class BaseReader:
|
||||
"""Base class to read files.
|
||||
|
||||
This class is used to process static files, and it can be inherited for
|
||||
other types of file. A Reader class must have the following attributes:
|
||||
|
||||
- enabled: (boolean) tell if the Reader class is enabled. It
|
||||
generally depends on the import of some dependency.
|
||||
- file_extensions: a list of file extensions that the Reader will process.
|
||||
- extensions: a list of extensions to use in the reader (typical use is
|
||||
Markdown).
|
||||
|
||||
"""
|
||||
|
||||
enabled = True
|
||||
file_extensions = ["static"]
|
||||
extensions = None
|
||||
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
|
||||
def process_metadata(self, name, value):
|
||||
if name in METADATA_PROCESSORS:
|
||||
return METADATA_PROCESSORS[name](value, self.settings)
|
||||
return value
|
||||
|
||||
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)
|
||||
|
||||
def visit_field_body(self, node):
|
||||
pass
|
||||
|
||||
def depart_field_body(self, node):
|
||||
pass
|
||||
|
||||
|
||||
def render_node_to_html(document, node, field_body_translator_class):
|
||||
visitor = field_body_translator_class(document)
|
||||
node.walkabout(visitor)
|
||||
return visitor.astext()
|
||||
|
||||
|
||||
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))
|
||||
|
||||
def depart_abbreviation(self, node):
|
||||
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", "")
|
||||
return HTMLTranslator.visit_image(self, node)
|
||||
|
||||
|
||||
class RstReader(BaseReader):
|
||||
"""Reader for reStructuredText files
|
||||
|
||||
By default the output HTML is written using
|
||||
docutils.writers.html4css1.Writer and translated using a subclass of
|
||||
docutils.writers.html4css1.HTMLTranslator. If you want to override it with
|
||||
your own writer/translator (e.g. a HTML5-based one), pass your classes to
|
||||
these two attributes. Look in the source code for details.
|
||||
|
||||
writer_class Used for writing contents
|
||||
field_body_translator_class Used for translating metadata such
|
||||
as article summary
|
||||
|
||||
"""
|
||||
|
||||
enabled = bool(docutils)
|
||||
file_extensions = ["rst"]
|
||||
|
||||
writer_class = PelicanHTMLWriter
|
||||
field_body_translator_class = _FieldBodyTranslator
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
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"
|
||||
|
||||
def _parse_metadata(self, document, source_path):
|
||||
"""Return the dict containing document metadata"""
|
||||
formatted_fields = self.settings["FORMATTED_FIELDS"]
|
||||
|
||||
def _parse_metadata(self, content):
|
||||
"""Return the dict containing metadatas"""
|
||||
output = {}
|
||||
for m in re.compile(':([a-z]+): (.*)\s', re.M).finditer(content):
|
||||
name, value = m.group(1).lower(), m.group(2)
|
||||
if name in _METADATAS_FIELDS:
|
||||
output[name] = _METADATAS_FIELDS[name](value)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
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)
|
||||
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
|
||||
)
|
||||
else:
|
||||
value = body_elem.astext()
|
||||
elif element.tagname == "authors": # author list
|
||||
name = element.tagname
|
||||
value = [element.astext() for element in element.children]
|
||||
else: # standard fields (e.g. address)
|
||||
name = element.tagname
|
||||
value = element.astext()
|
||||
name = name.lower()
|
||||
|
||||
output[name] = self.process_metadata(name, value)
|
||||
return output
|
||||
|
||||
def read(self, filename):
|
||||
"""Parse restructured text"""
|
||||
text = open(filename)
|
||||
metadatas = self._parse_metadata(text)
|
||||
extra_params = {'input_encoding': 'unicode',
|
||||
'initial_header_level': '2'}
|
||||
rendered_content = core.publish_parts(text, writer_name='html',
|
||||
settings_overrides=extra_params)
|
||||
title = rendered_content.get('title')
|
||||
content = rendered_content.get('body')
|
||||
if not metadatas.has_key('title'):
|
||||
metadatas['title'] = title
|
||||
return content, metadatas
|
||||
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")
|
||||
if user_params:
|
||||
extra_params.update(user_params)
|
||||
|
||||
class MarkdownReader(object):
|
||||
pub = docutils.core.Publisher(
|
||||
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()
|
||||
return pub
|
||||
|
||||
def read(self, filename):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
text = open(filename)
|
||||
md = Markdown(extensions = ['meta', 'codehilite'])
|
||||
content = md.convert(text)
|
||||
|
||||
metadatas = {}
|
||||
for name, value in md.Meta.items():
|
||||
if name in _METADATAS_FIELDS:
|
||||
meta = _METADATAS_FIELDS[name](value[0])
|
||||
def read(self, source_path):
|
||||
"""Parses restructured text"""
|
||||
pub = self._get_publisher(source_path)
|
||||
parts = pub.writer.parts
|
||||
content = parts.get("body")
|
||||
|
||||
metadata = self._parse_metadata(pub.document, source_path)
|
||||
metadata.setdefault("title", parts.get("title"))
|
||||
|
||||
return content, metadata
|
||||
|
||||
|
||||
class MarkdownReader(BaseReader):
|
||||
"""Reader for Markdown files"""
|
||||
|
||||
enabled = bool(Markdown)
|
||||
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")
|
||||
self._source_path = None
|
||||
|
||||
def _parse_metadata(self, meta):
|
||||
"""Return the dict containing document metadata"""
|
||||
formatted_fields = self.settings["FORMATTED_FIELDS"]
|
||||
|
||||
# prevent metadata extraction in fields
|
||||
self._md.preprocessors.deregister("meta")
|
||||
|
||||
output = {}
|
||||
for name, value in meta.items():
|
||||
name = name.lower()
|
||||
if name in formatted_fields:
|
||||
# formatted metadata is special case and join all list values
|
||||
formatted_values = "\n".join(value)
|
||||
# reset the markdown instance to clear any state
|
||||
self._md.reset()
|
||||
formatted = self._md.convert(formatted_values)
|
||||
output[name] = self.process_metadata(name, formatted)
|
||||
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,
|
||||
)
|
||||
output[name] = self.process_metadata(name, value[0])
|
||||
elif len(value) > 1:
|
||||
# handle list metadata as list of string
|
||||
output[name] = self.process_metadata(name, value)
|
||||
else:
|
||||
meta = value[0]
|
||||
metadatas[name.lower()] = meta
|
||||
return content, metadatas
|
||||
# otherwise, handle metadata as single string
|
||||
output[name] = self.process_metadata(name, value[0])
|
||||
return output
|
||||
|
||||
_EXTENSIONS = {'rst': RstReader, 'md': MarkdownReader} # supported formats
|
||||
def read(self, source_path):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
|
||||
self._source_path = source_path
|
||||
self._md = Markdown(**self.settings["MARKDOWN"])
|
||||
with pelican_open(source_path) as text:
|
||||
content = self._md.convert(text)
|
||||
|
||||
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?"
|
||||
)
|
||||
|
||||
|
||||
def read_file(filename, fmt=None):
|
||||
"""Return a reader object using the given format."""
|
||||
if not fmt:
|
||||
fmt = filename.split('.')[-1]
|
||||
if fmt not in _EXTENSIONS.keys():
|
||||
raise TypeError('Pelican does not know how to parse %s' % filename)
|
||||
reader = _EXTENSIONS[fmt]()
|
||||
return reader.read(filename)
|
||||
class HTMLReader(BaseReader):
|
||||
"""Parses HTML files as input, looking for meta, title, and body tags"""
|
||||
|
||||
file_extensions = ["htm", "html"]
|
||||
enabled = True
|
||||
|
||||
class _HTMLParser(HTMLParser):
|
||||
def __init__(self, settings, filename):
|
||||
super().__init__(convert_charrefs=False)
|
||||
self.body = ""
|
||||
self.metadata = {}
|
||||
self.settings = settings
|
||||
|
||||
self._data_buffer = ""
|
||||
|
||||
self._filename = filename
|
||||
|
||||
self._in_top_level = True
|
||||
self._in_head = False
|
||||
self._in_title = False
|
||||
self._in_body = False
|
||||
self._in_tags = False
|
||||
|
||||
def handle_starttag(self, tag, attrs):
|
||||
if tag == "head" and self._in_top_level:
|
||||
self._in_top_level = False
|
||||
self._in_head = True
|
||||
elif tag == "title" and self._in_head:
|
||||
self._in_title = True
|
||||
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._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 self._in_head:
|
||||
self._in_head = False
|
||||
self._in_top_level = True
|
||||
elif self._in_head and tag == "title":
|
||||
self._in_title = False
|
||||
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 += f"</{escape(tag)}>"
|
||||
|
||||
def handle_startendtag(self, tag, attrs):
|
||||
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 += f"<!--{data}-->"
|
||||
|
||||
def handle_data(self, data):
|
||||
self._data_buffer += data
|
||||
|
||||
def handle_entityref(self, data):
|
||||
self._data_buffer += f"&{data};"
|
||||
|
||||
def handle_charref(self, data):
|
||||
self._data_buffer += f"&#{data};"
|
||||
|
||||
def build_tag(self, tag, attrs, close_tag):
|
||||
result = f"<{escape(tag)}"
|
||||
for k, v in attrs:
|
||||
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 += f"='{escape(v, quote=False)}'"
|
||||
else:
|
||||
result += f'="{escape(v, quote=False)}"'
|
||||
if close_tag:
|
||||
return result + " />"
|
||||
return result + ">"
|
||||
|
||||
def _handle_meta_tag(self, attrs):
|
||||
name = self._attr_value(attrs, "name")
|
||||
if name is None:
|
||||
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", "")
|
||||
if not 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'"
|
||||
},
|
||||
)
|
||||
|
||||
if name == "keywords":
|
||||
name = "tags"
|
||||
|
||||
if name in self.metadata:
|
||||
# if this metadata already exists (i.e. a previous tag with the
|
||||
# same name has already been specified then either convert to
|
||||
# list or append to list
|
||||
if isinstance(self.metadata[name], list):
|
||||
self.metadata[name].append(contents)
|
||||
else:
|
||||
self.metadata[name] = [self.metadata[name], contents]
|
||||
else:
|
||||
self.metadata[name] = contents
|
||||
|
||||
@classmethod
|
||||
def _attr_value(cls, attrs, name, default=None):
|
||||
return next((x[1] for x in attrs if x[0] == name), default)
|
||||
|
||||
def read(self, filename):
|
||||
"""Parse content and metadata of HTML files"""
|
||||
with pelican_open(filename) as content:
|
||||
parser = self._HTMLParser(self.settings, filename)
|
||||
parser.feed(content)
|
||||
parser.close()
|
||||
|
||||
metadata = {}
|
||||
for k in parser.metadata:
|
||||
metadata[k] = self.process_metadata(k, parser.metadata[k])
|
||||
return parser.body, metadata
|
||||
|
||||
|
||||
class Readers(FileStampDataCacher):
|
||||
"""Interface for all readers.
|
||||
|
||||
This class contains a mapping of file extensions / Reader classes, to know
|
||||
which Reader class must be used to read a file (based on its extension).
|
||||
This is customizable both with the 'READERS' setting, and with the
|
||||
'readers_init' signall for plugins.
|
||||
|
||||
"""
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
for ext in cls.file_extensions:
|
||||
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"])
|
||||
|
||||
signals.readers_init.send(self)
|
||||
|
||||
for fmt, reader_class in self.reader_classes.items():
|
||||
if not reader_class:
|
||||
continue
|
||||
|
||||
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"]
|
||||
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()
|
||||
|
||||
@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__)
|
||||
|
||||
if not fmt:
|
||||
fmt = file_suffix(path)
|
||||
|
||||
if fmt not in self.readers:
|
||||
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)
|
||||
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,
|
||||
)
|
||||
)
|
||||
)
|
||||
reader_name = reader.__class__.__name__
|
||||
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(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"]:
|
||||
# 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":
|
||||
smartypants.Attr.default = smartypants.Attr.set2
|
||||
elif typogrify_dashes == "oldschool_inverted":
|
||||
smartypants.Attr.default = smartypants.Attr.set3
|
||||
else:
|
||||
smartypants.Attr.default = smartypants.Attr.set1
|
||||
|
||||
# Tell `smartypants` to also replace " HTML entities with
|
||||
# smart quotes. This is necessary because Docutils has already
|
||||
# replaced double quotes with said entities by the time we run
|
||||
# this filter.
|
||||
smartypants.Attr.default |= smartypants.Attr.w
|
||||
|
||||
def typogrify_wrapper(text):
|
||||
"""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"],
|
||||
**dict.fromkeys(self.settings["TYPOGRIFY_OMIT_FILTERS"], False),
|
||||
)
|
||||
except TypeError:
|
||||
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 "summary" in metadata:
|
||||
metadata["summary"] = typogrify_wrapper(metadata["summary"])
|
||||
|
||||
if context_signal:
|
||||
logger.debug(
|
||||
"Signal %s.send(%s, <metadata>)", context_signal.name, context_sender
|
||||
)
|
||||
context_signal.send(context_sender, metadata=metadata)
|
||||
|
||||
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):
|
||||
"""Find images with empty alt
|
||||
|
||||
Create warnings for all images with empty alt (up to a certain number),
|
||||
as they are really likely to be accessibility flaws.
|
||||
|
||||
"""
|
||||
imgs = re.compile(
|
||||
r"""
|
||||
(?:
|
||||
# src before alt
|
||||
<img
|
||||
[^\>]*
|
||||
src=(['"])(.*?)\1
|
||||
[^\>]*
|
||||
alt=(['"])\3
|
||||
)|(?:
|
||||
# alt before src
|
||||
<img
|
||||
[^\>]*
|
||||
alt=(['"])\4
|
||||
[^\>]*
|
||||
src=(['"])(.*?)\5
|
||||
)
|
||||
""",
|
||||
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"},
|
||||
)
|
||||
|
||||
|
||||
def default_metadata(settings=None, process=None):
|
||||
metadata = {}
|
||||
if settings:
|
||||
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 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"])
|
||||
else:
|
||||
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"]
|
||||
|
||||
# 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", {})
|
||||
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, ""))
|
||||
if source_path == path or source_path.startswith(dirpath):
|
||||
metadata.update(meta)
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
def parse_path_metadata(source_path, settings=None, process=None):
|
||||
r"""Extract a metadata dictionary from a file's path
|
||||
|
||||
>>> import pprint
|
||||
>>> settings = {
|
||||
... 'FILENAME_METADATA': r'(?P<slug>[^.]*).*',
|
||||
... 'PATH_METADATA':
|
||||
... r'(?P<category>[^/]*)/(?P<date>\d{4}-\d{2}-\d{2})/.*',
|
||||
... }
|
||||
>>> reader = BaseReader(settings=settings)
|
||||
>>> metadata = parse_path_metadata(
|
||||
... source_path='my-cat/2013-01-01/my-slug.html',
|
||||
... settings=settings,
|
||||
... process=reader.process_metadata)
|
||||
>>> pprint.pprint(metadata) # doctest: +ELLIPSIS
|
||||
{'category': <pelican.urlwrappers.Category object at ...>,
|
||||
'date': datetime.datetime(2013, 1, 1, 0, 0),
|
||||
'slug': 'my-slug'}
|
||||
"""
|
||||
metadata = {}
|
||||
dirname, basename = os.path.split(source_path)
|
||||
base, ext = os.path.splitext(basename)
|
||||
subdir = os.path.basename(dirname)
|
||||
if settings:
|
||||
checks = []
|
||||
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))
|
||||
for regexp, data in checks:
|
||||
if regexp and data:
|
||||
match = re.match(regexp, data)
|
||||
if match:
|
||||
# .items() for py3k compat.
|
||||
for k, v in match.groupdict().items():
|
||||
k = k.lower() # metadata must be lowercase
|
||||
if v is not None and k not in metadata:
|
||||
if process:
|
||||
v = process(k, v)
|
||||
metadata[k] = v
|
||||
return metadata
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
from pygments.formatters import HtmlFormatter
|
||||
from pygments import highlight
|
||||
from pygments.lexers import get_lexer_by_name, TextLexer
|
||||
import re
|
||||
|
||||
INLINESTYLES = False
|
||||
DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)
|
||||
VARIANTS = {
|
||||
'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
|
||||
}
|
||||
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
|
||||
|
||||
import pelican.settings as pys
|
||||
|
||||
|
||||
class Pygments(Directive):
|
||||
""" Source code syntax hightlighting.
|
||||
"""
|
||||
"""Source code syntax highlighting."""
|
||||
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = dict([(key, directives.flag) for key in VARIANTS])
|
||||
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,
|
||||
}
|
||||
has_content = True
|
||||
|
||||
def run(self):
|
||||
|
|
@ -28,10 +40,53 @@ class Pygments(Directive):
|
|||
except ValueError:
|
||||
# no lexer found - use the text one instead of an exception
|
||||
lexer = TextLexer()
|
||||
# take an arbitrary option if more than one is given
|
||||
formatter = self.options and VARIANTS[self.options.keys()[0]] \
|
||||
or DEFAULT
|
||||
parsed = highlight(u'\n'.join(self.content), lexer, formatter)
|
||||
return [nodes.raw('', parsed, format='html')]
|
||||
|
||||
directives.register_directive('code-block', Pygments)
|
||||
# Fetch the defaults
|
||||
if pys.PYGMENTS_RST_OPTIONS is not None:
|
||||
for k, v in pys.PYGMENTS_RST_OPTIONS.items():
|
||||
# Locally set options overrides the defaults
|
||||
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")
|
||||
else:
|
||||
self.options["linenos"] = "table"
|
||||
|
||||
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")]
|
||||
|
||||
|
||||
directives.register_directive("code-block", Pygments)
|
||||
directives.register_directive("sourcecode", Pygments)
|
||||
|
||||
|
||||
_abbr_re = re.compile(r"\((.*)\)$", re.DOTALL)
|
||||
|
||||
|
||||
class abbreviation(nodes.Inline, nodes.TextElement):
|
||||
pass
|
||||
|
||||
|
||||
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()
|
||||
expl = m.group(1)
|
||||
return [abbreviation(abbr, abbr, explanation=expl)], []
|
||||
|
||||
|
||||
roles.register_local_role("abbr", abbr_role)
|
||||
|
|
|
|||
166
pelican/server.py
Normal file
166
pelican/server.py
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import posixpath
|
||||
import ssl
|
||||
import sys
|
||||
import urllib
|
||||
from http import server
|
||||
|
||||
try:
|
||||
from magic import from_file as magic_from_file
|
||||
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,
|
||||
)
|
||||
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", "/", ""]
|
||||
|
||||
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]
|
||||
# Don't forget explicit trailing slash when normalizing. Issue17324
|
||||
trailing_slash = path.rstrip().endswith("/")
|
||||
path = urllib.parse.unquote(path)
|
||||
path = posixpath.normpath(path)
|
||||
words = path.split("/")
|
||||
words = filter(None, words)
|
||||
path = self.base_path
|
||||
for word in words:
|
||||
if os.path.dirname(word) or word in (os.curdir, os.pardir):
|
||||
# Ignore components that are not a simple file/directory name
|
||||
continue
|
||||
path = os.path.join(path, word)
|
||||
if trailing_slash:
|
||||
path += "/"
|
||||
return path
|
||||
|
||||
def do_GET(self):
|
||||
# cut off a query string
|
||||
original_path = self.path.split("?", 1)[0]
|
||||
# try to find file
|
||||
self.path = self.get_path_that_exists(original_path)
|
||||
|
||||
if not self.path:
|
||||
return
|
||||
|
||||
server.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
def get_path_that_exists(self, original_path):
|
||||
# Try to strip trailing slash
|
||||
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)
|
||||
)
|
||||
return None
|
||||
|
||||
def guess_type(self, path):
|
||||
"""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:
|
||||
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):
|
||||
server.HTTPServer.__init__(self, *args, **kwargs)
|
||||
self.RequestHandlerClass.base_path = base_path
|
||||
|
||||
|
||||
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."
|
||||
)
|
||||
args = parse_arguments()
|
||||
RootedHTTPServer.allow_reuse_address = True
|
||||
try:
|
||||
httpd = RootedHTTPServer(
|
||||
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
|
||||
)
|
||||
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.info("Serving at port %s, server %s.", args.port, args.server)
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Shutting down server.")
|
||||
httpd.socket.close()
|
||||
|
|
@ -1,33 +1,739 @@
|
|||
import copy
|
||||
import importlib.util
|
||||
import inspect
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from os.path import isabs
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Any, Optional
|
||||
|
||||
_DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
||||
"themes/notmyidea"])
|
||||
_DEFAULT_CONFIG = {'PATH': None,
|
||||
'THEME': _DEFAULT_THEME,
|
||||
'OUTPUT_PATH': 'output/',
|
||||
'MARKUP': ('rst', 'md'),
|
||||
'STATIC_PATHS': ['images',],
|
||||
'THEME_STATIC_PATHS': ['static',],
|
||||
'FEED': 'feeds/all.atom.xml',
|
||||
'CATEGORY_FEED': 'feeds/%s.atom.xml',
|
||||
'SITENAME': 'A Pelican Blog',
|
||||
'DISPLAY_PAGES_ON_MENU': True,
|
||||
'PDF_GENERATOR': False,
|
||||
'DEFAULT_CATEGORY': 'misc',
|
||||
'FALLBACK_ON_FS_DATE': True,
|
||||
'CSS_FILE': 'main.css',
|
||||
'REVERSE_ARCHIVE_ORDER': False,
|
||||
'KEEP_OUTPUT_DIRECTORY': False,
|
||||
}
|
||||
from pelican.log import LimitFilter
|
||||
from pelican.paginator import PaginationRule
|
||||
|
||||
def read_settings(filename):
|
||||
"""Load a Python file into a dictionary.
|
||||
"""
|
||||
context = _DEFAULT_CONFIG.copy()
|
||||
if filename:
|
||||
tempdict = {}
|
||||
execfile(filename, tempdict)
|
||||
for key in tempdict:
|
||||
if key.isupper():
|
||||
context[key] = tempdict[key]
|
||||
|
||||
def load_source(name: str, path: str) -> ModuleType:
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
sys.modules[name] = mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
Settings = dict[str, Any]
|
||||
|
||||
DEFAULT_THEME = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "themes", "notmyidea"
|
||||
)
|
||||
DEFAULT_CONFIG = {
|
||||
"PATH": os.curdir,
|
||||
"ARTICLE_PATHS": [""],
|
||||
"ARTICLE_EXCLUDES": [],
|
||||
"PAGE_PATHS": ["pages"],
|
||||
"PAGE_EXCLUDES": [],
|
||||
"THEME": DEFAULT_THEME,
|
||||
"OUTPUT_PATH": "output",
|
||||
"READERS": {},
|
||||
"STATIC_PATHS": ["images"],
|
||||
"STATIC_EXCLUDES": [],
|
||||
"STATIC_EXCLUDE_SOURCES": True,
|
||||
"THEME_STATIC_DIR": "theme",
|
||||
"THEME_STATIC_PATHS": [
|
||||
"static",
|
||||
],
|
||||
"FEED_ALL_ATOM": "feeds/all.atom.xml",
|
||||
"CATEGORY_FEED_ATOM": "feeds/{slug}.atom.xml",
|
||||
"AUTHOR_FEED_ATOM": "feeds/{slug}.atom.xml",
|
||||
"AUTHOR_FEED_RSS": "feeds/{slug}.rss.xml",
|
||||
"TRANSLATION_FEED_ATOM": "feeds/all-{lang}.atom.xml",
|
||||
"FEED_MAX_ITEMS": 100,
|
||||
"RSS_FEED_SUMMARY_ONLY": True,
|
||||
"FEED_APPEND_REF": False,
|
||||
"SITEURL": "",
|
||||
"SITENAME": "A Pelican Blog",
|
||||
"DISPLAY_PAGES_ON_MENU": True,
|
||||
"DISPLAY_CATEGORIES_ON_MENU": True,
|
||||
"DOCUTILS_SETTINGS": {},
|
||||
"OUTPUT_SOURCES": False,
|
||||
"OUTPUT_SOURCES_EXTENSION": ".text",
|
||||
"USE_FOLDER_AS_CATEGORY": True,
|
||||
"DEFAULT_CATEGORY": "misc",
|
||||
"WITH_FUTURE_DATES": True,
|
||||
"CSS_FILE": "main.css",
|
||||
"NEWEST_FIRST_ARCHIVES": True,
|
||||
"REVERSE_CATEGORY_ORDER": False,
|
||||
"DELETE_OUTPUT_DIRECTORY": False,
|
||||
"OUTPUT_RETENTION": [],
|
||||
"INDEX_SAVE_AS": "index.html",
|
||||
"ARTICLE_URL": "{slug}.html",
|
||||
"ARTICLE_SAVE_AS": "{slug}.html",
|
||||
"ARTICLE_ORDER_BY": "reversed-date",
|
||||
"ARTICLE_LANG_URL": "{slug}-{lang}.html",
|
||||
"ARTICLE_LANG_SAVE_AS": "{slug}-{lang}.html",
|
||||
"DRAFT_URL": "drafts/{slug}.html",
|
||||
"DRAFT_SAVE_AS": "drafts/{slug}.html",
|
||||
"DRAFT_LANG_URL": "drafts/{slug}-{lang}.html",
|
||||
"DRAFT_LANG_SAVE_AS": "drafts/{slug}-{lang}.html",
|
||||
"PAGE_URL": "pages/{slug}.html",
|
||||
"PAGE_SAVE_AS": "pages/{slug}.html",
|
||||
"PAGE_ORDER_BY": "basename",
|
||||
"PAGE_LANG_URL": "pages/{slug}-{lang}.html",
|
||||
"PAGE_LANG_SAVE_AS": "pages/{slug}-{lang}.html",
|
||||
"DRAFT_PAGE_URL": "drafts/pages/{slug}.html",
|
||||
"DRAFT_PAGE_SAVE_AS": "drafts/pages/{slug}.html",
|
||||
"DRAFT_PAGE_LANG_URL": "drafts/pages/{slug}-{lang}.html",
|
||||
"DRAFT_PAGE_LANG_SAVE_AS": "drafts/pages/{slug}-{lang}.html",
|
||||
"STATIC_URL": "{path}",
|
||||
"STATIC_SAVE_AS": "{path}",
|
||||
"STATIC_CREATE_LINKS": False,
|
||||
"STATIC_CHECK_IF_MODIFIED": False,
|
||||
"CATEGORY_URL": "category/{slug}.html",
|
||||
"CATEGORY_SAVE_AS": "category/{slug}.html",
|
||||
"TAG_URL": "tag/{slug}.html",
|
||||
"TAG_SAVE_AS": "tag/{slug}.html",
|
||||
"AUTHOR_URL": "author/{slug}.html",
|
||||
"AUTHOR_SAVE_AS": "author/{slug}.html",
|
||||
"PAGINATION_PATTERNS": [
|
||||
(1, "{name}{extension}", "{name}{extension}"),
|
||||
(2, "{name}{number}{extension}", "{name}{number}{extension}"),
|
||||
],
|
||||
"YEAR_ARCHIVE_URL": "",
|
||||
"YEAR_ARCHIVE_SAVE_AS": "",
|
||||
"MONTH_ARCHIVE_URL": "",
|
||||
"MONTH_ARCHIVE_SAVE_AS": "",
|
||||
"DAY_ARCHIVE_URL": "",
|
||||
"DAY_ARCHIVE_SAVE_AS": "",
|
||||
"RELATIVE_URLS": False,
|
||||
"DEFAULT_LANG": "en",
|
||||
"ARTICLE_TRANSLATION_ID": "slug",
|
||||
"PAGE_TRANSLATION_ID": "slug",
|
||||
"DIRECT_TEMPLATES": ["index", "tags", "categories", "authors", "archives"],
|
||||
"THEME_TEMPLATES_OVERRIDES": [],
|
||||
"PAGINATED_TEMPLATES": {
|
||||
"index": None,
|
||||
"tag": None,
|
||||
"category": None,
|
||||
"author": None,
|
||||
},
|
||||
"PELICAN_CLASS": "pelican.Pelican",
|
||||
"DEFAULT_DATE_FORMAT": "%a %d %B %Y",
|
||||
"DATE_FORMATS": {},
|
||||
"MARKDOWN": {
|
||||
"extension_configs": {
|
||||
"markdown.extensions.codehilite": {"css_class": "highlight"},
|
||||
"markdown.extensions.extra": {},
|
||||
"markdown.extensions.meta": {},
|
||||
},
|
||||
"output_format": "html5",
|
||||
},
|
||||
"JINJA_FILTERS": {},
|
||||
"JINJA_GLOBALS": {},
|
||||
"JINJA_TESTS": {},
|
||||
"JINJA_ENVIRONMENT": {
|
||||
"trim_blocks": True,
|
||||
"lstrip_blocks": True,
|
||||
"extensions": [],
|
||||
},
|
||||
"LOG_FILTER": [],
|
||||
"LOCALE": [""], # defaults to user locale
|
||||
"DEFAULT_PAGINATION": False,
|
||||
"DEFAULT_ORPHANS": 0,
|
||||
"DEFAULT_METADATA": {},
|
||||
"FILENAME_METADATA": r"(?P<date>\d{4}-\d{2}-\d{2}).*",
|
||||
"PATH_METADATA": r"",
|
||||
"EXTRA_PATH_METADATA": {},
|
||||
"ARTICLE_PERMALINK_STRUCTURE": "",
|
||||
"TYPOGRIFY": False,
|
||||
"TYPOGRIFY_IGNORE_TAGS": [],
|
||||
"TYPOGRIFY_OMIT_FILTERS": [],
|
||||
"TYPOGRIFY_DASHES": "default",
|
||||
"SUMMARY_END_SUFFIX": "…",
|
||||
"SUMMARY_MAX_LENGTH": 50,
|
||||
"PLUGIN_PATHS": [],
|
||||
"PLUGINS": None,
|
||||
"PYGMENTS_RST_OPTIONS": {},
|
||||
"TEMPLATE_PAGES": {},
|
||||
"TEMPLATE_EXTENSIONS": [".html"],
|
||||
"IGNORE_FILES": ["**/.*"],
|
||||
"SLUG_REGEX_SUBSTITUTIONS": [
|
||||
(r"[^\w\s-]", ""), # remove non-alphabetical/whitespace/'-' chars
|
||||
(r"(?u)\A\s*", ""), # strip leading whitespace
|
||||
(r"(?u)\s*\Z", ""), # strip trailing whitespace
|
||||
(r"[-\s]+", "-"), # reduce multiple whitespace or '-' to single '-'
|
||||
],
|
||||
"INTRASITE_LINK_REGEX": "[{|](?P<what>.*?)[|}]",
|
||||
"SLUGIFY_SOURCE": "title",
|
||||
"SLUGIFY_USE_UNICODE": False,
|
||||
"SLUGIFY_PRESERVE_CASE": False,
|
||||
"CACHE_CONTENT": False,
|
||||
"CONTENT_CACHING_LAYER": "reader",
|
||||
"CACHE_PATH": "cache",
|
||||
"GZIP_CACHE": True,
|
||||
"CHECK_MODIFIED_METHOD": "mtime",
|
||||
"LOAD_CONTENT_CACHE": False,
|
||||
"FORMATTED_FIELDS": ["summary"],
|
||||
"PORT": 8000,
|
||||
"BIND": "127.0.0.1",
|
||||
}
|
||||
|
||||
PYGMENTS_RST_OPTIONS = None
|
||||
|
||||
|
||||
def read_settings(
|
||||
path: Optional[str] = None, override: Optional[Settings] = None
|
||||
) -> Settings:
|
||||
settings = override or {}
|
||||
|
||||
if path:
|
||||
settings = dict(get_settings_from_file(path), **settings)
|
||||
|
||||
if settings:
|
||||
settings = handle_deprecated_settings(settings)
|
||||
|
||||
if path:
|
||||
# Make relative paths absolute
|
||||
def getabs(maybe_relative, base_path=path):
|
||||
if isabs(maybe_relative):
|
||||
return maybe_relative
|
||||
return os.path.abspath(
|
||||
os.path.normpath(
|
||||
os.path.join(os.path.dirname(base_path), maybe_relative)
|
||||
)
|
||||
)
|
||||
|
||||
for p in ["PATH", "OUTPUT_PATH", "THEME", "CACHE_PATH"]:
|
||||
if settings.get(p) is not None:
|
||||
absp = getabs(settings[p])
|
||||
# THEME may be a name rather than a path
|
||||
if p != "THEME" or os.path.exists(absp):
|
||||
settings[p] = absp
|
||||
|
||||
if settings.get("PLUGIN_PATHS") is not None:
|
||||
settings["PLUGIN_PATHS"] = [
|
||||
getabs(pluginpath) for pluginpath in settings["PLUGIN_PATHS"]
|
||||
]
|
||||
|
||||
settings = dict(copy.deepcopy(DEFAULT_CONFIG), **settings)
|
||||
settings = configure_settings(settings)
|
||||
|
||||
# This is because there doesn't seem to be a way to pass extra
|
||||
# parameters to docutils directive handlers, so we have to have a
|
||||
# variable here that we'll import from within Pygments.run (see
|
||||
# rstdirectives.py) to see what the user defaults were.
|
||||
global PYGMENTS_RST_OPTIONS # noqa: PLW0603
|
||||
PYGMENTS_RST_OPTIONS = settings.get("PYGMENTS_RST_OPTIONS", None)
|
||||
return settings
|
||||
|
||||
|
||||
def get_settings_from_module(module: Optional[ModuleType] = None) -> Settings:
|
||||
"""Loads settings from a module, returns a dictionary."""
|
||||
|
||||
context = {}
|
||||
if module is not None:
|
||||
context.update((k, v) for k, v in inspect.getmembers(module) if k.isupper())
|
||||
return context
|
||||
|
||||
|
||||
def get_settings_from_file(path: str) -> Settings:
|
||||
"""Loads settings from a file path, returning a dict."""
|
||||
|
||||
name, ext = os.path.splitext(os.path.basename(path))
|
||||
module = load_source(name, path)
|
||||
return get_settings_from_module(module)
|
||||
|
||||
|
||||
def get_jinja_environment(settings: Settings) -> Settings:
|
||||
"""Sets the environment for Jinja"""
|
||||
|
||||
jinja_env = settings.setdefault(
|
||||
"JINJA_ENVIRONMENT", DEFAULT_CONFIG["JINJA_ENVIRONMENT"]
|
||||
)
|
||||
|
||||
# Make sure we include the defaults if the user has set env variables
|
||||
for key, value in DEFAULT_CONFIG["JINJA_ENVIRONMENT"].items():
|
||||
if key not in jinja_env:
|
||||
jinja_env[key] = value
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def _printf_s_to_format_field(printf_string: str, format_field: str) -> str:
|
||||
"""Tries to replace %s with {format_field} in the provided printf_string.
|
||||
Raises ValueError in case of failure.
|
||||
"""
|
||||
TEST_STRING = "PELICAN_PRINTF_S_DEPRECATION"
|
||||
expected = printf_string % TEST_STRING
|
||||
|
||||
result = printf_string.replace("{", "{{").replace("}", "}}") % f"{{{format_field}}}"
|
||||
if result.format(**{format_field: TEST_STRING}) != expected:
|
||||
raise ValueError(f"Failed to safely replace %s with {{{format_field}}}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def handle_deprecated_settings(settings: Settings) -> Settings:
|
||||
"""Converts deprecated settings and issues warnings. Issues an exception
|
||||
if both old and new setting is specified.
|
||||
"""
|
||||
|
||||
# PLUGIN_PATH -> PLUGIN_PATHS
|
||||
if "PLUGIN_PATH" in settings:
|
||||
logger.warning(
|
||||
"PLUGIN_PATH setting has been replaced by "
|
||||
"PLUGIN_PATHS, moving it to the new setting name."
|
||||
)
|
||||
settings["PLUGIN_PATHS"] = settings["PLUGIN_PATH"]
|
||||
del settings["PLUGIN_PATH"]
|
||||
|
||||
# PLUGIN_PATHS: str -> [str]
|
||||
if isinstance(settings.get("PLUGIN_PATHS"), str):
|
||||
logger.warning(
|
||||
"Defining PLUGIN_PATHS setting as string "
|
||||
"has been deprecated (should be a list)"
|
||||
)
|
||||
settings["PLUGIN_PATHS"] = [settings["PLUGIN_PATHS"]]
|
||||
|
||||
# JINJA_EXTENSIONS -> JINJA_ENVIRONMENT > extensions
|
||||
if "JINJA_EXTENSIONS" in settings:
|
||||
logger.warning(
|
||||
"JINJA_EXTENSIONS setting has been deprecated, "
|
||||
"moving it to JINJA_ENVIRONMENT setting."
|
||||
)
|
||||
settings["JINJA_ENVIRONMENT"]["extensions"] = settings["JINJA_EXTENSIONS"]
|
||||
del settings["JINJA_EXTENSIONS"]
|
||||
|
||||
# {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS
|
||||
for key in ["ARTICLE", "PAGE"]:
|
||||
old_key = key + "_DIR"
|
||||
new_key = key + "_PATHS"
|
||||
if old_key in settings:
|
||||
logger.warning(
|
||||
"Deprecated setting %s, moving it to %s list", old_key, new_key
|
||||
)
|
||||
settings[new_key] = [settings[old_key]] # also make a list
|
||||
del settings[old_key]
|
||||
|
||||
# EXTRA_TEMPLATES_PATHS -> THEME_TEMPLATES_OVERRIDES
|
||||
if "EXTRA_TEMPLATES_PATHS" in settings:
|
||||
logger.warning(
|
||||
"EXTRA_TEMPLATES_PATHS is deprecated use THEME_TEMPLATES_OVERRIDES instead."
|
||||
)
|
||||
if settings.get("THEME_TEMPLATES_OVERRIDES"):
|
||||
raise Exception(
|
||||
"Setting both EXTRA_TEMPLATES_PATHS and "
|
||||
"THEME_TEMPLATES_OVERRIDES is not permitted. Please move to "
|
||||
"only setting THEME_TEMPLATES_OVERRIDES."
|
||||
)
|
||||
settings["THEME_TEMPLATES_OVERRIDES"] = settings["EXTRA_TEMPLATES_PATHS"]
|
||||
del settings["EXTRA_TEMPLATES_PATHS"]
|
||||
|
||||
# MD_EXTENSIONS -> MARKDOWN
|
||||
if "MD_EXTENSIONS" in settings:
|
||||
logger.warning(
|
||||
"MD_EXTENSIONS is deprecated use MARKDOWN "
|
||||
"instead. Falling back to the default."
|
||||
)
|
||||
settings["MARKDOWN"] = DEFAULT_CONFIG["MARKDOWN"]
|
||||
|
||||
# LESS_GENERATOR -> Webassets plugin
|
||||
# FILES_TO_COPY -> STATIC_PATHS, EXTRA_PATH_METADATA
|
||||
for old, new, doc in [
|
||||
("LESS_GENERATOR", "the Webassets plugin", None),
|
||||
(
|
||||
"FILES_TO_COPY",
|
||||
"STATIC_PATHS and EXTRA_PATH_METADATA",
|
||||
"https://github.com/getpelican/pelican/"
|
||||
"blob/main/docs/settings.rst#path-metadata",
|
||||
),
|
||||
]:
|
||||
if old in settings:
|
||||
message = f"The {old} setting has been removed in favor of {new}"
|
||||
if doc:
|
||||
message += f", see {doc} for details"
|
||||
logger.warning(message)
|
||||
|
||||
# PAGINATED_DIRECT_TEMPLATES -> PAGINATED_TEMPLATES
|
||||
if "PAGINATED_DIRECT_TEMPLATES" in settings:
|
||||
message = "The {} setting has been removed in favor of {}".format(
|
||||
"PAGINATED_DIRECT_TEMPLATES", "PAGINATED_TEMPLATES"
|
||||
)
|
||||
logger.warning(message)
|
||||
|
||||
# set PAGINATED_TEMPLATES
|
||||
if "PAGINATED_TEMPLATES" not in settings:
|
||||
settings["PAGINATED_TEMPLATES"] = {
|
||||
"tag": None,
|
||||
"category": None,
|
||||
"author": None,
|
||||
}
|
||||
|
||||
for t in settings["PAGINATED_DIRECT_TEMPLATES"]:
|
||||
if t not in settings["PAGINATED_TEMPLATES"]:
|
||||
settings["PAGINATED_TEMPLATES"][t] = None
|
||||
del settings["PAGINATED_DIRECT_TEMPLATES"]
|
||||
|
||||
# {SLUG,CATEGORY,TAG,AUTHOR}_SUBSTITUTIONS ->
|
||||
# {SLUG,CATEGORY,TAG,AUTHOR}_REGEX_SUBSTITUTIONS
|
||||
url_settings_url = "http://docs.getpelican.com/en/latest/settings.html#url-settings"
|
||||
flavours = {"SLUG", "CATEGORY", "TAG", "AUTHOR"}
|
||||
old_values = {
|
||||
f: settings[f + "_SUBSTITUTIONS"]
|
||||
for f in flavours
|
||||
if f + "_SUBSTITUTIONS" in settings
|
||||
}
|
||||
new_values = {
|
||||
f: settings[f + "_REGEX_SUBSTITUTIONS"]
|
||||
for f in flavours
|
||||
if f + "_REGEX_SUBSTITUTIONS" in settings
|
||||
}
|
||||
if old_values and new_values:
|
||||
raise Exception(
|
||||
"Setting both {new_key} and {old_key} (or variants thereof) is "
|
||||
"not permitted. Please move to only setting {new_key}.".format(
|
||||
old_key="SLUG_SUBSTITUTIONS", new_key="SLUG_REGEX_SUBSTITUTIONS"
|
||||
)
|
||||
)
|
||||
if old_values:
|
||||
message = (
|
||||
"{} and variants thereof are deprecated and will be "
|
||||
"removed in the future. Please use {} and variants thereof "
|
||||
"instead. Check {}.".format(
|
||||
"SLUG_SUBSTITUTIONS", "SLUG_REGEX_SUBSTITUTIONS", url_settings_url
|
||||
)
|
||||
)
|
||||
logger.warning(message)
|
||||
if old_values.get("SLUG"):
|
||||
for f in ("CATEGORY", "TAG"):
|
||||
if old_values.get(f):
|
||||
old_values[f] = old_values["SLUG"] + old_values[f]
|
||||
old_values["AUTHOR"] = old_values.get("AUTHOR", [])
|
||||
for f in flavours:
|
||||
if old_values.get(f) is not None:
|
||||
regex_subs = []
|
||||
# by default will replace non-alphanum characters
|
||||
replace = True
|
||||
for tpl in old_values[f]:
|
||||
try:
|
||||
src, dst, skip = tpl
|
||||
if skip:
|
||||
replace = False
|
||||
except ValueError:
|
||||
src, dst = tpl
|
||||
regex_subs.append((re.escape(src), dst.replace("\\", r"\\")))
|
||||
|
||||
if replace:
|
||||
regex_subs += [
|
||||
(r"[^\w\s-]", ""),
|
||||
(r"(?u)\A\s*", ""),
|
||||
(r"(?u)\s*\Z", ""),
|
||||
(r"[-\s]+", "-"),
|
||||
]
|
||||
else:
|
||||
regex_subs += [
|
||||
(r"(?u)\A\s*", ""),
|
||||
(r"(?u)\s*\Z", ""),
|
||||
]
|
||||
settings[f + "_REGEX_SUBSTITUTIONS"] = regex_subs
|
||||
settings.pop(f + "_SUBSTITUTIONS", None)
|
||||
|
||||
# `%s` -> '{slug}` or `{lang}` in FEED settings
|
||||
for key in ["TRANSLATION_FEED_ATOM", "TRANSLATION_FEED_RSS"]:
|
||||
if (
|
||||
settings.get(key)
|
||||
and not isinstance(settings[key], Path)
|
||||
and "%s" in settings[key]
|
||||
):
|
||||
logger.warning("%%s usage in %s is deprecated, use {lang} instead.", key)
|
||||
try:
|
||||
settings[key] = _printf_s_to_format_field(settings[key], "lang")
|
||||
except ValueError:
|
||||
logger.warning(
|
||||
"Failed to convert %%s to {lang} for %s. Falling back to default.",
|
||||
key,
|
||||
)
|
||||
settings[key] = DEFAULT_CONFIG[key]
|
||||
for key in [
|
||||
"AUTHOR_FEED_ATOM",
|
||||
"AUTHOR_FEED_RSS",
|
||||
"CATEGORY_FEED_ATOM",
|
||||
"CATEGORY_FEED_RSS",
|
||||
"TAG_FEED_ATOM",
|
||||
"TAG_FEED_RSS",
|
||||
]:
|
||||
if (
|
||||
settings.get(key)
|
||||
and not isinstance(settings[key], Path)
|
||||
and "%s" in settings[key]
|
||||
):
|
||||
logger.warning("%%s usage in %s is deprecated, use {slug} instead.", key)
|
||||
try:
|
||||
settings[key] = _printf_s_to_format_field(settings[key], "slug")
|
||||
except ValueError:
|
||||
logger.warning(
|
||||
"Failed to convert %%s to {slug} for %s. Falling back to default.",
|
||||
key,
|
||||
)
|
||||
settings[key] = DEFAULT_CONFIG[key]
|
||||
|
||||
# CLEAN_URLS
|
||||
if settings.get("CLEAN_URLS", False):
|
||||
logger.warning(
|
||||
"Found deprecated `CLEAN_URLS` in settings."
|
||||
" Modifying the following settings for the"
|
||||
" same behaviour."
|
||||
)
|
||||
|
||||
settings["ARTICLE_URL"] = "{slug}/"
|
||||
settings["ARTICLE_LANG_URL"] = "{slug}-{lang}/"
|
||||
settings["PAGE_URL"] = "pages/{slug}/"
|
||||
settings["PAGE_LANG_URL"] = "pages/{slug}-{lang}/"
|
||||
|
||||
for setting in ("ARTICLE_URL", "ARTICLE_LANG_URL", "PAGE_URL", "PAGE_LANG_URL"):
|
||||
logger.warning("%s = '%s'", setting, settings[setting])
|
||||
|
||||
# AUTORELOAD_IGNORE_CACHE -> --ignore-cache
|
||||
if settings.get("AUTORELOAD_IGNORE_CACHE"):
|
||||
logger.warning(
|
||||
"Found deprecated `AUTORELOAD_IGNORE_CACHE` in "
|
||||
"settings. Use --ignore-cache instead."
|
||||
)
|
||||
settings.pop("AUTORELOAD_IGNORE_CACHE")
|
||||
|
||||
# ARTICLE_PERMALINK_STRUCTURE
|
||||
if settings.get("ARTICLE_PERMALINK_STRUCTURE", False):
|
||||
logger.warning(
|
||||
"Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in"
|
||||
" settings. Modifying the following settings for"
|
||||
" the same behaviour."
|
||||
)
|
||||
|
||||
structure = settings["ARTICLE_PERMALINK_STRUCTURE"]
|
||||
|
||||
# Convert %(variable) into {variable}.
|
||||
structure = re.sub(r"%\((\w+)\)s", r"{\g<1>}", structure)
|
||||
|
||||
# Convert %x into {date:%x} for strftime
|
||||
structure = re.sub(r"(%[A-z])", r"{date:\g<1>}", structure)
|
||||
|
||||
# Strip a / prefix
|
||||
structure = re.sub("^/", "", structure)
|
||||
|
||||
for setting in (
|
||||
"ARTICLE_URL",
|
||||
"ARTICLE_LANG_URL",
|
||||
"PAGE_URL",
|
||||
"PAGE_LANG_URL",
|
||||
"DRAFT_URL",
|
||||
"DRAFT_LANG_URL",
|
||||
"ARTICLE_SAVE_AS",
|
||||
"ARTICLE_LANG_SAVE_AS",
|
||||
"DRAFT_SAVE_AS",
|
||||
"DRAFT_LANG_SAVE_AS",
|
||||
"PAGE_SAVE_AS",
|
||||
"PAGE_LANG_SAVE_AS",
|
||||
):
|
||||
settings[setting] = os.path.join(structure, settings[setting])
|
||||
logger.warning("%s = '%s'", setting, settings[setting])
|
||||
|
||||
# {,TAG,CATEGORY,TRANSLATION}_FEED -> {,TAG,CATEGORY,TRANSLATION}_FEED_ATOM
|
||||
for new, old in [
|
||||
("FEED", "FEED_ATOM"),
|
||||
("TAG_FEED", "TAG_FEED_ATOM"),
|
||||
("CATEGORY_FEED", "CATEGORY_FEED_ATOM"),
|
||||
("TRANSLATION_FEED", "TRANSLATION_FEED_ATOM"),
|
||||
]:
|
||||
if settings.get(new, False):
|
||||
logger.warning(
|
||||
"Found deprecated `%(new)s` in settings. Modify %(new)s "
|
||||
"to %(old)s in your settings and theme for the same "
|
||||
"behavior. Temporarily setting %(old)s for backwards "
|
||||
"compatibility.",
|
||||
{"new": new, "old": old},
|
||||
)
|
||||
settings[old] = settings[new]
|
||||
|
||||
# Warn if removed WRITE_SELECTED is present
|
||||
if "WRITE_SELECTED" in settings:
|
||||
logger.warning(
|
||||
"WRITE_SELECTED is present in settings but this functionality was removed. "
|
||||
"It will have no effect."
|
||||
)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def configure_settings(settings: Settings) -> Settings:
|
||||
"""Provide optimizations, error checking, and warnings for the given
|
||||
settings.
|
||||
Also, specify the log messages to be ignored.
|
||||
"""
|
||||
if "PATH" not in settings or not os.path.isdir(settings["PATH"]):
|
||||
raise Exception(
|
||||
"You need to specify a path containing the content"
|
||||
" (see pelican --help for more information)"
|
||||
)
|
||||
|
||||
# specify the log messages to be ignored
|
||||
log_filter = settings.get("LOG_FILTER", DEFAULT_CONFIG["LOG_FILTER"])
|
||||
LimitFilter._ignore.update(set(log_filter))
|
||||
|
||||
# lookup the theme in "pelican/themes" if the given one doesn't exist
|
||||
if not os.path.isdir(settings["THEME"]):
|
||||
theme_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "themes", settings["THEME"]
|
||||
)
|
||||
if os.path.exists(theme_path):
|
||||
settings["THEME"] = theme_path
|
||||
else:
|
||||
raise Exception("Could not find the theme {}".format(settings["THEME"]))
|
||||
|
||||
# standardize strings to lowercase strings
|
||||
for key in ["DEFAULT_LANG"]:
|
||||
if key in settings:
|
||||
settings[key] = settings[key].lower()
|
||||
|
||||
# set defaults for Jinja environment
|
||||
settings = get_jinja_environment(settings)
|
||||
|
||||
# standardize strings to lists
|
||||
for key in ["LOCALE"]:
|
||||
if key in settings and isinstance(settings[key], str):
|
||||
settings[key] = [settings[key]]
|
||||
|
||||
# check settings that must be a particular type
|
||||
for key, types in [
|
||||
("OUTPUT_SOURCES_EXTENSION", str),
|
||||
("FILENAME_METADATA", str),
|
||||
]:
|
||||
if key in settings and not isinstance(settings[key], types):
|
||||
value = settings.pop(key)
|
||||
logger.warning(
|
||||
"Detected misconfigured %s (%s), falling back to the default (%s)",
|
||||
key,
|
||||
value,
|
||||
DEFAULT_CONFIG[key],
|
||||
)
|
||||
|
||||
# try to set the different locales, fallback on the default.
|
||||
locales = settings.get("LOCALE", DEFAULT_CONFIG["LOCALE"])
|
||||
|
||||
for locale_ in locales:
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, str(locale_))
|
||||
break # break if it is successful
|
||||
except locale.Error:
|
||||
pass
|
||||
else:
|
||||
logger.warning(
|
||||
"Locale could not be set. Check the LOCALE setting, ensuring it "
|
||||
"is valid and available on your system."
|
||||
)
|
||||
|
||||
if "SITEURL" in settings:
|
||||
# If SITEURL has a trailing slash, remove it and provide a warning
|
||||
siteurl = settings["SITEURL"]
|
||||
if siteurl.endswith("/"):
|
||||
settings["SITEURL"] = siteurl[:-1]
|
||||
logger.warning("Removed extraneous trailing slash from SITEURL.")
|
||||
# If SITEURL is defined but FEED_DOMAIN isn't,
|
||||
# set FEED_DOMAIN to SITEURL
|
||||
if "FEED_DOMAIN" not in settings:
|
||||
settings["FEED_DOMAIN"] = settings["SITEURL"]
|
||||
|
||||
# check content caching layer and warn of incompatibilities
|
||||
if (
|
||||
settings.get("CACHE_CONTENT", False)
|
||||
and settings.get("CONTENT_CACHING_LAYER", "") == "generator"
|
||||
and not settings.get("WITH_FUTURE_DATES", True)
|
||||
):
|
||||
logger.warning(
|
||||
"WITH_FUTURE_DATES conflicts with CONTENT_CACHING_LAYER "
|
||||
"set to 'generator', use 'reader' layer instead"
|
||||
)
|
||||
|
||||
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
|
||||
feed_keys = [
|
||||
"FEED_ATOM",
|
||||
"FEED_RSS",
|
||||
"FEED_ALL_ATOM",
|
||||
"FEED_ALL_RSS",
|
||||
"CATEGORY_FEED_ATOM",
|
||||
"CATEGORY_FEED_RSS",
|
||||
"AUTHOR_FEED_ATOM",
|
||||
"AUTHOR_FEED_RSS",
|
||||
"TAG_FEED_ATOM",
|
||||
"TAG_FEED_RSS",
|
||||
"TRANSLATION_FEED_ATOM",
|
||||
"TRANSLATION_FEED_RSS",
|
||||
]
|
||||
|
||||
if any(settings.get(k) for k in feed_keys):
|
||||
if not settings.get("SITEURL"):
|
||||
logger.warning(
|
||||
"Feeds generated without SITEURL set properly may not be valid"
|
||||
)
|
||||
|
||||
if "TIMEZONE" not in settings:
|
||||
logger.warning(
|
||||
"No timezone information specified in the settings. Assuming"
|
||||
" your timezone is UTC for feed generation. Check "
|
||||
"https://docs.getpelican.com/en/latest/settings.html#TIMEZONE "
|
||||
"for more information"
|
||||
)
|
||||
|
||||
# fix up pagination rules
|
||||
pagination_rules = [
|
||||
PaginationRule(*r)
|
||||
for r in settings.get(
|
||||
"PAGINATION_PATTERNS",
|
||||
DEFAULT_CONFIG["PAGINATION_PATTERNS"],
|
||||
)
|
||||
]
|
||||
settings["PAGINATION_PATTERNS"] = sorted(
|
||||
pagination_rules,
|
||||
key=lambda r: r[0],
|
||||
)
|
||||
|
||||
# Save people from accidentally setting a string rather than a list
|
||||
path_keys = (
|
||||
"ARTICLE_EXCLUDES",
|
||||
"DEFAULT_METADATA",
|
||||
"DIRECT_TEMPLATES",
|
||||
"THEME_TEMPLATES_OVERRIDES",
|
||||
"FILES_TO_COPY",
|
||||
"IGNORE_FILES",
|
||||
"PAGINATED_DIRECT_TEMPLATES",
|
||||
"PLUGINS",
|
||||
"STATIC_EXCLUDES",
|
||||
"STATIC_PATHS",
|
||||
"THEME_STATIC_PATHS",
|
||||
"ARTICLE_PATHS",
|
||||
"PAGE_PATHS",
|
||||
)
|
||||
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
||||
if isinstance(settings[PATH_KEY], str):
|
||||
logger.warning(
|
||||
"Detected misconfiguration with %s setting "
|
||||
"(must be a list), falling back to the default",
|
||||
PATH_KEY,
|
||||
)
|
||||
settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY]
|
||||
|
||||
# Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES
|
||||
mutually_exclusive = ("ARTICLE", "PAGE")
|
||||
for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]:
|
||||
try:
|
||||
includes = settings[type_1 + "_PATHS"]
|
||||
excludes = settings[type_2 + "_EXCLUDES"]
|
||||
for path in includes:
|
||||
if path not in excludes:
|
||||
excludes.append(path)
|
||||
except KeyError:
|
||||
continue # setting not specified, nothing to do
|
||||
|
||||
return settings
|
||||
|
|
|
|||
4
pelican/signals.py
Normal file
4
pelican/signals.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
raise ImportError(
|
||||
"Importing from `pelican.signals` is deprecated. "
|
||||
"Use `from pelican import signals` or `import pelican.plugins.signals` instead."
|
||||
)
|
||||
8
pelican/tests/TestPages/bad_page.rst
Normal file
8
pelican/tests/TestPages/bad_page.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
This is a test bad page
|
||||
#######################
|
||||
|
||||
:status: invalid
|
||||
|
||||
The quick brown fox jumped over the lazy dog's back.
|
||||
|
||||
The status here is invalid, the page should not render.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue