mkdocs-document-dates 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- mkdocs_document_dates/lang/__init__.py +23 -0
- mkdocs_document_dates/lang/ar.py +18 -0
- mkdocs_document_dates/lang/de.py +18 -0
- mkdocs_document_dates/lang/en.py +18 -0
- mkdocs_document_dates/lang/es.py +18 -0
- mkdocs_document_dates/lang/fr.py +18 -0
- mkdocs_document_dates/lang/ja.py +18 -0
- mkdocs_document_dates/lang/ko.py +18 -0
- mkdocs_document_dates/lang/ru.py +18 -0
- mkdocs_document_dates/lang/zh.py +18 -0
- mkdocs_document_dates/lang/zh_tw.py +18 -0
- mkdocs_document_dates/plugin.py +156 -112
- mkdocs_document_dates/styles.py +28 -0
- {mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/METADATA +32 -28
- mkdocs_document_dates-0.5.0.dist-info/RECORD +20 -0
- mkdocs_document_dates-0.4.0.dist-info/RECORD +0 -8
- {mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/LICENSE +0 -0
- {mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/WHEEL +0 -0
- {mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/entry_points.txt +0 -0
- {mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
import importlib.util
|
3
|
+
|
4
|
+
def load_translations():
|
5
|
+
"""加载所有可用的翻译"""
|
6
|
+
translations = {}
|
7
|
+
translations_dir = Path(__file__).parent
|
8
|
+
|
9
|
+
for lang_file in translations_dir.glob('*.py'):
|
10
|
+
if lang_file.stem == '__init__':
|
11
|
+
continue
|
12
|
+
|
13
|
+
spec = importlib.util.spec_from_file_location(
|
14
|
+
f"translations.{lang_file.stem}",
|
15
|
+
lang_file
|
16
|
+
)
|
17
|
+
module = importlib.util.module_from_spec(spec)
|
18
|
+
spec.loader.exec_module(module)
|
19
|
+
|
20
|
+
if hasattr(module, 'translations'):
|
21
|
+
translations[lang_file.stem] = module.translations
|
22
|
+
|
23
|
+
return translations
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'الآن',
|
3
|
+
'seconds_ago': 'منذ {} ثانية',
|
4
|
+
'minute_ago': 'منذ دقيقة',
|
5
|
+
'minutes_ago': 'منذ {} دقيقة',
|
6
|
+
'hour_ago': 'منذ ساعة',
|
7
|
+
'hours_ago': 'منذ {} ساعة',
|
8
|
+
'day_ago': 'منذ يوم',
|
9
|
+
'days_ago': 'منذ {} يوم',
|
10
|
+
'week_ago': 'منذ أسبوع',
|
11
|
+
'weeks_ago': 'منذ {} أسبوع',
|
12
|
+
'month_ago': 'منذ شهر',
|
13
|
+
'months_ago': 'منذ {} شهر',
|
14
|
+
'year_ago': 'منذ سنة',
|
15
|
+
'years_ago': 'منذ {} سنة',
|
16
|
+
'created_time': 'تاريخ الإنشاء',
|
17
|
+
'modified_time': 'تاريخ التعديل',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'gerade jetzt',
|
3
|
+
'seconds_ago': 'vor {} Sekunden',
|
4
|
+
'minute_ago': 'vor einer Minute',
|
5
|
+
'minutes_ago': 'vor {} Minuten',
|
6
|
+
'hour_ago': 'vor einer Stunde',
|
7
|
+
'hours_ago': 'vor {} Stunden',
|
8
|
+
'day_ago': 'vor einem Tag',
|
9
|
+
'days_ago': 'vor {} Tagen',
|
10
|
+
'week_ago': 'vor einer Woche',
|
11
|
+
'weeks_ago': 'vor {} Wochen',
|
12
|
+
'month_ago': 'vor einem Monat',
|
13
|
+
'months_ago': 'vor {} Monaten',
|
14
|
+
'year_ago': 'vor einem Jahr',
|
15
|
+
'years_ago': 'vor {} Jahren',
|
16
|
+
'created_time': 'Erstellungszeit',
|
17
|
+
'modified_time': 'Änderungszeit',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'just now',
|
3
|
+
'seconds_ago': '{} seconds ago',
|
4
|
+
'minute_ago': '1 minute ago',
|
5
|
+
'minutes_ago': '{} minutes ago',
|
6
|
+
'hour_ago': '1 hour ago',
|
7
|
+
'hours_ago': '{} hours ago',
|
8
|
+
'day_ago': '1 day ago',
|
9
|
+
'days_ago': '{} days ago',
|
10
|
+
'week_ago': '1 week ago',
|
11
|
+
'weeks_ago': '{} weeks ago',
|
12
|
+
'month_ago': '1 month ago',
|
13
|
+
'months_ago': '{} months ago',
|
14
|
+
'year_ago': '1 year ago',
|
15
|
+
'years_ago': '{} years ago',
|
16
|
+
'created_time': 'Created Time',
|
17
|
+
'modified_time': 'Last Update',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'justo ahora',
|
3
|
+
'seconds_ago': 'hace {} segundos',
|
4
|
+
'minute_ago': 'hace un minuto',
|
5
|
+
'minutes_ago': 'hace {} minutos',
|
6
|
+
'hour_ago': 'hace una hora',
|
7
|
+
'hours_ago': 'hace {} horas',
|
8
|
+
'day_ago': 'hace un día',
|
9
|
+
'days_ago': 'hace {} días',
|
10
|
+
'week_ago': 'hace una semana',
|
11
|
+
'weeks_ago': 'hace {} semanas',
|
12
|
+
'month_ago': 'hace un mes',
|
13
|
+
'months_ago': 'hace {} meses',
|
14
|
+
'year_ago': 'hace un año',
|
15
|
+
'years_ago': 'hace {} años',
|
16
|
+
'created_time': 'Fecha de creación',
|
17
|
+
'modified_time': 'Fecha de modificación',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'à l\'instant',
|
3
|
+
'seconds_ago': 'il y a {} secondes',
|
4
|
+
'minute_ago': 'il y a une minute',
|
5
|
+
'minutes_ago': 'il y a {} minutes',
|
6
|
+
'hour_ago': 'il y a une heure',
|
7
|
+
'hours_ago': 'il y a {} heures',
|
8
|
+
'day_ago': 'il y a un jour',
|
9
|
+
'days_ago': 'il y a {} jours',
|
10
|
+
'week_ago': 'il y a une semaine',
|
11
|
+
'weeks_ago': 'il y a {} semaines',
|
12
|
+
'month_ago': 'il y a un mois',
|
13
|
+
'months_ago': 'il y a {} mois',
|
14
|
+
'year_ago': 'il y a un an',
|
15
|
+
'years_ago': 'il y a {} ans',
|
16
|
+
'created_time': 'Date de création',
|
17
|
+
'modified_time': 'Date de modification',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'たった今',
|
3
|
+
'seconds_ago': '{} 秒前',
|
4
|
+
'minute_ago': '1 分前',
|
5
|
+
'minutes_ago': '{} 分前',
|
6
|
+
'hour_ago': '1 時間前',
|
7
|
+
'hours_ago': '{} 時間前',
|
8
|
+
'day_ago': '1 日前',
|
9
|
+
'days_ago': '{} 日前',
|
10
|
+
'week_ago': '1 週間前',
|
11
|
+
'weeks_ago': '{} 週間前',
|
12
|
+
'month_ago': '1 ヶ月前',
|
13
|
+
'months_ago': '{} ヶ月前',
|
14
|
+
'year_ago': '1 年前',
|
15
|
+
'years_ago': '{} 年前',
|
16
|
+
'created_time': '作成日時',
|
17
|
+
'modified_time': '更新日時',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': '방금',
|
3
|
+
'seconds_ago': '{} 초 전',
|
4
|
+
'minute_ago': '1 분 전',
|
5
|
+
'minutes_ago': '{} 분 전',
|
6
|
+
'hour_ago': '1 시간 전',
|
7
|
+
'hours_ago': '{} 시간 전',
|
8
|
+
'day_ago': '1 일 전',
|
9
|
+
'days_ago': '{} 일 전',
|
10
|
+
'week_ago': '1 주 전',
|
11
|
+
'weeks_ago': '{} 주 전',
|
12
|
+
'month_ago': '1 개월 전',
|
13
|
+
'months_ago': '{} 개월 전',
|
14
|
+
'year_ago': '1 년 전',
|
15
|
+
'years_ago': '{} 년 전',
|
16
|
+
'created_time': '작성일',
|
17
|
+
'modified_time': '수정일',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': 'только что',
|
3
|
+
'seconds_ago': '{} секунд назад',
|
4
|
+
'minute_ago': 'минуту назад',
|
5
|
+
'minutes_ago': '{} минут назад',
|
6
|
+
'hour_ago': 'час назад',
|
7
|
+
'hours_ago': '{} часов назад',
|
8
|
+
'day_ago': 'день назад',
|
9
|
+
'days_ago': '{} дней назад',
|
10
|
+
'week_ago': 'неделю назад',
|
11
|
+
'weeks_ago': '{} недель назад',
|
12
|
+
'month_ago': 'месяц назад',
|
13
|
+
'months_ago': '{} месяцев назад',
|
14
|
+
'year_ago': 'год назад',
|
15
|
+
'years_ago': '{} лет назад',
|
16
|
+
'created_time': 'Дата создания',
|
17
|
+
'modified_time': 'Дата изменения',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': '刚刚',
|
3
|
+
'seconds_ago': '{} 秒前',
|
4
|
+
'minute_ago': '1 分钟前',
|
5
|
+
'minutes_ago': '{} 分钟前',
|
6
|
+
'hour_ago': '1 小时前',
|
7
|
+
'hours_ago': '{} 小时前',
|
8
|
+
'day_ago': '1 天前',
|
9
|
+
'days_ago': '{} 天前',
|
10
|
+
'week_ago': '1 周前',
|
11
|
+
'weeks_ago': '{} 周前',
|
12
|
+
'month_ago': '1 个月前',
|
13
|
+
'months_ago': '{} 个月前',
|
14
|
+
'year_ago': '1 年前',
|
15
|
+
'years_ago': '{} 年前',
|
16
|
+
'created_time': '创建时间',
|
17
|
+
'modified_time': '最后更新',
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
translations = {
|
2
|
+
'just_now': '剛剛',
|
3
|
+
'seconds_ago': '{} 秒前',
|
4
|
+
'minute_ago': '1 分鐘前',
|
5
|
+
'minutes_ago': '{} 分鐘前',
|
6
|
+
'hour_ago': '1 小時前',
|
7
|
+
'hours_ago': '{} 小時前',
|
8
|
+
'day_ago': '1 天前',
|
9
|
+
'days_ago': '{} 天前',
|
10
|
+
'week_ago': '1 週前',
|
11
|
+
'weeks_ago': '{} 週前',
|
12
|
+
'month_ago': '1 個月前',
|
13
|
+
'months_ago': '{} 個月前',
|
14
|
+
'year_ago': '1 年前',
|
15
|
+
'years_ago': '{} 年前',
|
16
|
+
'created_time': '建立時間',
|
17
|
+
'modified_time': '修改時間',
|
18
|
+
}
|
mkdocs_document_dates/plugin.py
CHANGED
@@ -4,11 +4,14 @@ from datetime import datetime
|
|
4
4
|
from pathlib import Path
|
5
5
|
from mkdocs.plugins import BasePlugin
|
6
6
|
from mkdocs.config import config_options
|
7
|
+
from .lang import load_translations
|
8
|
+
from .styles import DOCUMENT_DATES_CSS
|
7
9
|
|
8
10
|
class DocumentDatesPlugin(BasePlugin):
|
9
11
|
config_scheme = (
|
12
|
+
('type', config_options.Type(str, default='date')),
|
13
|
+
('locale', config_options.Type(str, default='en')),
|
10
14
|
('date_format', config_options.Type(str, default='%Y-%m-%d')),
|
11
|
-
('show_time', config_options.Type(bool, default=False)),
|
12
15
|
('time_format', config_options.Type(str, default='%H:%M:%S')),
|
13
16
|
('position', config_options.Type(str, default='bottom')),
|
14
17
|
('exclude', config_options.Type(list, default=[])),
|
@@ -16,35 +19,11 @@ class DocumentDatesPlugin(BasePlugin):
|
|
16
19
|
|
17
20
|
def __init__(self):
|
18
21
|
super().__init__()
|
22
|
+
self.translations = load_translations()
|
19
23
|
|
20
|
-
def
|
24
|
+
def _get_css_content(self):
|
21
25
|
"""返回插件的 CSS 样式"""
|
22
|
-
return
|
23
|
-
.document-dates-plugin {
|
24
|
-
color: #8e8e8e;
|
25
|
-
font-size: 0.75rem;
|
26
|
-
padding: 0.2rem 0;
|
27
|
-
opacity: 0.8;
|
28
|
-
display: flex;
|
29
|
-
gap: 1.5rem;
|
30
|
-
align-items: center;
|
31
|
-
margin-bottom: 0.3rem;
|
32
|
-
}
|
33
|
-
.document-dates-plugin span {
|
34
|
-
display: inline-flex;
|
35
|
-
align-items: center;
|
36
|
-
gap: 0.3rem;
|
37
|
-
}
|
38
|
-
.document-dates-plugin .material-icons {
|
39
|
-
font-size: 0.9rem;
|
40
|
-
opacity: 0.7;
|
41
|
-
}
|
42
|
-
.document-dates-plugin-wrapper {
|
43
|
-
margin: 0.3rem 0 1rem 0;
|
44
|
-
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
45
|
-
padding-bottom: 0.5rem;
|
46
|
-
}
|
47
|
-
"""
|
26
|
+
return DOCUMENT_DATES_CSS
|
48
27
|
|
49
28
|
def on_config(self, config):
|
50
29
|
"""配置插件并添加必要的 CSS"""
|
@@ -59,117 +38,182 @@ class DocumentDatesPlugin(BasePlugin):
|
|
59
38
|
# 添加自定义 CSS
|
60
39
|
css_file = Path(config['docs_dir']) / 'assets' / 'document_dates.css'
|
61
40
|
css_file.parent.mkdir(parents=True, exist_ok=True)
|
62
|
-
css_file.write_text(self.
|
41
|
+
css_file.write_text(self._get_css_content())
|
63
42
|
config['extra_css'].append('assets/document_dates.css')
|
64
43
|
|
65
44
|
return config
|
66
45
|
|
67
|
-
def
|
46
|
+
def _get_date_info(self, created, modified):
|
68
47
|
"""格式化日期信息的 HTML"""
|
48
|
+
# 获取翻译字典
|
49
|
+
locale = self.config['locale']
|
50
|
+
if locale not in self.translations:
|
51
|
+
locale = 'en'
|
52
|
+
t = self.translations[locale]
|
53
|
+
|
69
54
|
return (
|
70
|
-
f"\n\n"
|
71
55
|
f"<div class='document-dates-plugin-wrapper'>"
|
72
56
|
f"<div class='document-dates-plugin'>"
|
73
|
-
f"<span><span class='material-icons'>add_circle</span>"
|
74
|
-
f"{self.
|
75
|
-
f"<span><span class='material-icons'>update</span>"
|
76
|
-
f"{self.
|
57
|
+
f"<span title='{t['created_time']}'><span class='material-icons'>add_circle</span>"
|
58
|
+
f"{self._get_formatted_date(created)}</span>"
|
59
|
+
f"<span title='{t['modified_time']}'><span class='material-icons'>update</span>"
|
60
|
+
f"{self._get_formatted_date(modified)}</span>"
|
61
|
+
f"</div>"
|
77
62
|
f"</div>"
|
78
|
-
f"</div>\n"
|
79
63
|
)
|
80
64
|
|
81
|
-
def
|
65
|
+
def _insert_date_info(self, markdown, date_info):
|
82
66
|
"""根据配置将日期信息插入到合适的位置"""
|
67
|
+
if not markdown.strip():
|
68
|
+
return markdown
|
69
|
+
|
83
70
|
if self.config['position'] == 'top':
|
84
|
-
lines = markdown.
|
71
|
+
lines = markdown.splitlines()
|
85
72
|
for i, line in enumerate(lines):
|
86
73
|
if line.startswith('#'):
|
87
74
|
lines.insert(i + 1, date_info)
|
88
75
|
return '\n'.join(lines)
|
89
|
-
return date_info
|
90
|
-
return markdown
|
76
|
+
return f"{date_info}\n{markdown}"
|
77
|
+
return f"{markdown}\n\n{date_info}"
|
91
78
|
|
92
79
|
def on_page_markdown(self, markdown, page, config, files):
|
93
80
|
"""处理页面内容,添加日期信息"""
|
94
81
|
file_path = Path(page.file.abs_src_path)
|
95
|
-
docs_dir = Path(config['docs_dir'])
|
96
82
|
|
97
|
-
|
98
|
-
|
99
|
-
# 处理目录递归排除(如 private/*)
|
100
|
-
if exclude_pattern.endswith('/*'):
|
101
|
-
base_dir = exclude_pattern[:-2] # 移除 /*
|
102
|
-
try:
|
103
|
-
# 检查当前文件是否在指定目录或其子目录中
|
104
|
-
rel_path = file_path.relative_to(docs_dir)
|
105
|
-
if str(rel_path).startswith(f"{base_dir}/"):
|
106
|
-
return markdown
|
107
|
-
except ValueError:
|
108
|
-
continue
|
109
|
-
|
110
|
-
# 处理特定目录下的特定类型文件(如 drafts/*.md)
|
111
|
-
elif '/*.' in exclude_pattern:
|
112
|
-
dir_part, ext_part = exclude_pattern.split('/*.')
|
113
|
-
if (file_path.parent.name == dir_part and
|
114
|
-
file_path.suffix == f".{ext_part}"):
|
115
|
-
return markdown
|
116
|
-
|
117
|
-
# 处理特定后缀文件(如 *.tmp)
|
118
|
-
elif exclude_pattern.startswith('*.'):
|
119
|
-
if file_path.suffix == f".{exclude_pattern[2:]}":
|
120
|
-
return markdown
|
121
|
-
|
122
|
-
# 处理精确文件匹配(如 temp.md)
|
123
|
-
elif file_path.name == exclude_pattern:
|
124
|
-
return markdown
|
83
|
+
if self._is_excluded(file_path, Path(config['docs_dir'])):
|
84
|
+
return markdown
|
125
85
|
|
126
|
-
|
127
|
-
created, modified = self.
|
86
|
+
created, modified = self._get_file_dates(file_path)
|
87
|
+
created, modified = self._process_meta_dates(page.meta, created, modified)
|
128
88
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
89
|
+
date_info = self._get_date_info(created, modified)
|
90
|
+
return self._insert_date_info(markdown, date_info)
|
91
|
+
|
92
|
+
def _is_excluded(self, file_path: Path, docs_dir: Path) -> bool:
|
93
|
+
"""检查文件是否在排除列表中"""
|
94
|
+
for pattern in self.config['exclude']:
|
95
|
+
if self._matches_exclude_pattern(file_path, docs_dir, pattern):
|
96
|
+
return True
|
97
|
+
return False
|
98
|
+
|
99
|
+
def _matches_exclude_pattern(self, file_path: Path, docs_dir: Path, pattern: str) -> bool:
|
100
|
+
"""检查文件是否匹配排除模式
|
101
|
+
支持三种匹配模式:
|
102
|
+
1. 具体文件路径:支持多级目录,如 'private/temp.md'
|
103
|
+
2. 目录下所有文件:使用 '*' 通配符,如 'private/*',匹配包含子目录的所有文件
|
104
|
+
3. 指定目录下特定类型文件:如 'private/*.md',仅匹配当前目录下的特定类型文件
|
105
|
+
"""
|
106
|
+
try:
|
107
|
+
# 获取相对于 docs_dir 的路径
|
108
|
+
rel_path = file_path.relative_to(docs_dir)
|
109
|
+
pattern_path = Path(pattern)
|
110
|
+
|
111
|
+
# 情况1:匹配具体文件路径
|
112
|
+
if '*' not in pattern:
|
113
|
+
return str(rel_path) == pattern
|
114
|
+
|
115
|
+
# 情况2:匹配目录下所有文件(包含子目录)
|
116
|
+
if pattern.endswith('/*'):
|
117
|
+
base_dir = pattern[:-2]
|
118
|
+
return str(rel_path).startswith(f"{base_dir}/")
|
119
|
+
|
120
|
+
# 情况3:匹配指定目录下的特定类型文件(不包含子目录)
|
121
|
+
if '*.' in pattern:
|
122
|
+
pattern_dir = pattern_path.parent
|
123
|
+
pattern_suffix = pattern_path.name[1:] # 去掉 * 号
|
124
|
+
return (rel_path.parent == Path(pattern_dir) and
|
125
|
+
rel_path.name.endswith(pattern_suffix))
|
150
126
|
|
151
|
-
|
127
|
+
return False
|
128
|
+
except ValueError:
|
129
|
+
return False
|
130
|
+
|
131
|
+
def _process_meta_dates(self, meta: dict, created: datetime, modified: datetime) -> tuple[datetime, datetime]:
|
132
|
+
"""处理 frontmatter 中的日期"""
|
133
|
+
result_created = self._parse_meta_date(meta.get('created_date'), created)
|
134
|
+
result_modified = self._parse_meta_date(meta.get('modified_date'), modified)
|
135
|
+
return result_created, result_modified
|
136
|
+
|
137
|
+
def _parse_meta_date(self, date_str: str | None, default_date: datetime) -> datetime:
|
138
|
+
"""解析 meta 中的日期字符串"""
|
139
|
+
if not date_str:
|
140
|
+
return default_date
|
141
|
+
|
142
|
+
try:
|
143
|
+
return datetime.fromisoformat(str(date_str).strip("'\""))
|
144
|
+
except (ValueError, TypeError):
|
145
|
+
return default_date
|
146
|
+
|
147
|
+
def _get_file_dates(self, file_path):
|
152
148
|
"""获取文件的创建时间和修改时间"""
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
149
|
+
try:
|
150
|
+
stat = os.stat(file_path)
|
151
|
+
modified = datetime.fromtimestamp(stat.st_mtime)
|
152
|
+
|
153
|
+
system = platform.system().lower()
|
154
|
+
if system == 'darwin': # macOS
|
155
|
+
try:
|
156
|
+
created = datetime.fromtimestamp(stat.st_birthtime)
|
157
|
+
except AttributeError:
|
158
|
+
created = datetime.fromtimestamp(stat.st_ctime)
|
159
|
+
elif system == 'windows': # Windows
|
162
160
|
created = datetime.fromtimestamp(stat.st_ctime)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
created
|
161
|
+
else: # Linux 和其他系统
|
162
|
+
# Linux 没有可靠的创建时间,使用修改时间作为创建时间
|
163
|
+
created = modified
|
164
|
+
|
165
|
+
return created, modified
|
166
|
+
except (OSError, ValueError) as e:
|
167
|
+
# 添加错误处理,确保即使文件访问出错也能正常工作
|
168
|
+
current_time = datetime.now()
|
169
|
+
return current_time, current_time
|
170
|
+
|
171
|
+
def _get_timeago(self, date):
|
172
|
+
"""将日期格式化为 timeago 格式"""
|
173
|
+
now = datetime.now()
|
174
|
+
diff = now - date
|
175
|
+
seconds = diff.total_seconds()
|
176
|
+
|
177
|
+
# 获取翻译字典
|
178
|
+
locale = self.config['locale']
|
179
|
+
if locale not in self.translations:
|
180
|
+
locale = 'en'
|
181
|
+
t = self.translations[locale]
|
168
182
|
|
169
|
-
|
183
|
+
# 时间间隔判断
|
184
|
+
if seconds < 10:
|
185
|
+
return t['just_now']
|
186
|
+
elif seconds < 60:
|
187
|
+
return t['seconds_ago'].format(int(seconds))
|
188
|
+
elif seconds < 120:
|
189
|
+
return t['minute_ago']
|
190
|
+
elif seconds < 3600:
|
191
|
+
return t['minutes_ago'].format(int(seconds / 60))
|
192
|
+
elif seconds < 7200:
|
193
|
+
return t['hour_ago']
|
194
|
+
elif seconds < 86400:
|
195
|
+
return t['hours_ago'].format(int(seconds / 3600))
|
196
|
+
elif seconds < 172800:
|
197
|
+
return t['day_ago']
|
198
|
+
elif seconds < 604800:
|
199
|
+
return t['days_ago'].format(int(seconds / 86400))
|
200
|
+
elif seconds < 1209600:
|
201
|
+
return t['week_ago']
|
202
|
+
elif seconds < 2592000:
|
203
|
+
return t['weeks_ago'].format(int(seconds / 604800))
|
204
|
+
elif seconds < 5184000:
|
205
|
+
return t['month_ago']
|
206
|
+
elif seconds < 31536000:
|
207
|
+
return t['months_ago'].format(int(seconds / 2592000))
|
208
|
+
elif seconds < 63072000:
|
209
|
+
return t['year_ago']
|
210
|
+
else:
|
211
|
+
return t['years_ago'].format(int(seconds / 31536000))
|
170
212
|
|
171
|
-
def
|
172
|
-
|
213
|
+
def _get_formatted_date(self, date):
|
214
|
+
"""格式化日期,支持 timeago、date 和 datetime 格式"""
|
215
|
+
if self.config['type'] == 'timeago':
|
216
|
+
return self._get_timeago(date)
|
217
|
+
elif self.config['type'] == 'datetime':
|
173
218
|
return date.strftime(f"{self.config['date_format']} {self.config['time_format']}")
|
174
|
-
return date.strftime(self.config['date_format'])
|
175
|
-
|
219
|
+
return date.strftime(self.config['date_format'])
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""CSS 样式定义"""
|
2
|
+
|
3
|
+
DOCUMENT_DATES_CSS = """
|
4
|
+
.document-dates-plugin {
|
5
|
+
color: #8e8e8e;
|
6
|
+
font-size: 0.75rem;
|
7
|
+
padding: 0.2rem 0;
|
8
|
+
opacity: 0.8;
|
9
|
+
display: flex;
|
10
|
+
gap: 1.5rem;
|
11
|
+
align-items: center;
|
12
|
+
margin-bottom: 0.3rem;
|
13
|
+
}
|
14
|
+
.document-dates-plugin span {
|
15
|
+
display: inline-flex;
|
16
|
+
align-items: center;
|
17
|
+
gap: 0.3rem;
|
18
|
+
}
|
19
|
+
.document-dates-plugin .material-icons {
|
20
|
+
font-size: 0.9rem;
|
21
|
+
opacity: 0.7;
|
22
|
+
}
|
23
|
+
.document-dates-plugin-wrapper {
|
24
|
+
margin: 0.3rem 0 1rem 0;
|
25
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
26
|
+
padding-bottom: 0.5rem;
|
27
|
+
}
|
28
|
+
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: mkdocs-document-dates
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: A MkDocs plugin for displaying accurate document creation and last modification dates.
|
5
5
|
Home-page: https://github.com/jaywhj/mkdocs-document-dates
|
6
6
|
Author: Aaron Wang
|
@@ -31,15 +31,15 @@ A MkDocs plugin for displaying **accurate** document creation and last modificat
|
|
31
31
|
## Features
|
32
32
|
|
33
33
|
- Automatically displays document creation and last modification times
|
34
|
-
- Supports manual date specification in `Front Matter`
|
35
34
|
- No Git dependency, uses filesystem timestamps directly
|
35
|
+
- Supports manual date specification in `Front Matter`
|
36
36
|
- Cross-platform support (Windows, macOS, Linux)
|
37
|
-
- Configurable date and time
|
37
|
+
- Configurable time display formats (supports date, time, and relative time)
|
38
38
|
- Flexible display position (top or bottom)
|
39
39
|
- File exclusion rules support
|
40
|
-
- Material Design icons
|
41
|
-
- Elegant styling
|
40
|
+
- Material Design icons, Elegant styling
|
42
41
|
- Lightweight with no extra dependencies
|
42
|
+
- Multi-language support
|
43
43
|
|
44
44
|
## Installation
|
45
45
|
|
@@ -49,7 +49,7 @@ pip install mkdocs-document-dates
|
|
49
49
|
|
50
50
|
## Configuration
|
51
51
|
|
52
|
-
|
52
|
+
Just add the plugin to your mkdocs.yml:
|
53
53
|
|
54
54
|
```yaml
|
55
55
|
plugins:
|
@@ -61,15 +61,15 @@ Or, customize the configuration:
|
|
61
61
|
```yaml
|
62
62
|
plugins:
|
63
63
|
- document-dates:
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
-
|
71
|
-
-
|
72
|
-
-
|
64
|
+
type: date # Date type: date | datetime | timeago, default: date
|
65
|
+
locale: en # Localization: zh zh_tw en es fr de ar ja ko ru, default: en
|
66
|
+
date_format: '%Y-%m-%d' # Date format
|
67
|
+
time_format: '%H:%M:%S' # Time format
|
68
|
+
position: bottom # Display position: top (after title) | bottom (end of document), default: bottom
|
69
|
+
exclude: # List of file patterns to exclude
|
70
|
+
- temp.md # Exclude specific file
|
71
|
+
- private/* # Exclude all files in private directory, including subdirectories
|
72
|
+
- drafts/*.md # Exclude all markdown files in the current directory drafts, but not subdirectories
|
73
73
|
```
|
74
74
|
|
75
75
|
## Manual Date Specification
|
@@ -85,20 +85,24 @@ modified_date: 2023-12-31
|
|
85
85
|
# Document Title
|
86
86
|
```
|
87
87
|
|
88
|
+
|
89
|
+
|
88
90
|
## Configuration Options
|
89
91
|
|
90
|
-
- `
|
91
|
-
-
|
92
|
-
- `
|
93
|
-
-
|
94
|
-
|
95
|
-
- `
|
96
|
-
|
97
|
-
-
|
98
|
-
|
99
|
-
|
100
|
-
- `
|
101
|
-
-
|
92
|
+
- `type` : Date type (default: `date` )
|
93
|
+
- `date` : Display date only
|
94
|
+
- `datetime` : Display date and time
|
95
|
+
- `timeago` : Display relative time (e.g., 2 minutes ago)
|
96
|
+
- `locale` : Localization (default: `en` )
|
97
|
+
- Supports: `zh zh_tw en es fr de ar ja ko ru`
|
98
|
+
- `date_format` : Date format (default: `%Y-%m-%d`)
|
99
|
+
- Supports all Python datetime format strings, e.g., %Y-%m-%d, %b %d, %Y, etc.
|
100
|
+
- `time_format` : Time format (default: `%H:%M:%S`)
|
101
|
+
- `position` : Display position (default: `bottom`)
|
102
|
+
- `top` : Display after the first heading
|
103
|
+
- `bottom` : Display at the end of the document
|
104
|
+
- `exclude` : File exclusion list (default: [] )
|
105
|
+
- Supports glob patterns, e.g., ["private/\*", "temp.md", "drafts/\*.md"]
|
102
106
|
|
103
107
|
## Notes
|
104
108
|
|
@@ -106,5 +110,5 @@ modified_date: 2023-12-31
|
|
106
110
|
- Windows: Uses file creation time
|
107
111
|
- macOS: Uses file creation time (birthtime)
|
108
112
|
- Linux: Uses modification time as creation time due to system limitations
|
109
|
-
- For accurate creation times, it's recommended to
|
113
|
+
- For accurate creation times, it's recommended to specify dates manually in Front Matter
|
110
114
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
mkdocs_document_dates/__init__.py,sha256=yom7psmObebsZY0AwCN1PjlGUwPkny2r6NyzoO0cudg,58
|
2
|
+
mkdocs_document_dates/plugin.py,sha256=jg8GPUPrtmU4THH45TmXEtT06GoHnrrS6l5UAjFf_hk,8893
|
3
|
+
mkdocs_document_dates/styles.py,sha256=ujhlKgDWsOo5sHiYtf3XekuGg4C5Yjol8RzP3W9Wzjo,578
|
4
|
+
mkdocs_document_dates/lang/__init__.py,sha256=M1BLjCOA3HHKeAitk45YAgzxxNpnxFUvVAk6-FO_QSA,690
|
5
|
+
mkdocs_document_dates/lang/ar.py,sha256=BsZlxz54U_spOZ5SBiKt73ywoLKbR54cZNkKAs86OxM,632
|
6
|
+
mkdocs_document_dates/lang/de.py,sha256=B0Ffrn4lVSvcxFpGho7SiMm16GXYEmpjcVAR-k4UgSI,585
|
7
|
+
mkdocs_document_dates/lang/en.py,sha256=V6WYglXO56Vn9o96Fjny-LQ2BPOPwplxrNQBI4l6dq4,541
|
8
|
+
mkdocs_document_dates/lang/es.py,sha256=BwussbHS_Lnok6YY64JAsurksdl9GfamV8YEyaecPQY,586
|
9
|
+
mkdocs_document_dates/lang/fr.py,sha256=QRHqbX2qE7yy1v4UrZcOKv8gMbm4v1b32sKVejJmf4g,612
|
10
|
+
mkdocs_document_dates/lang/ja.py,sha256=Jqd3bcmyXCv-w-5eq3MSelOqImdJT_mCfCpyfeG3jiw,525
|
11
|
+
mkdocs_document_dates/lang/ko.py,sha256=GwY6yrKYAOj6S6feq9yqNxr2XpyGHC0XeenO541vmdM,520
|
12
|
+
mkdocs_document_dates/lang/ru.py,sha256=fK5s4mQKCoP6KI3jf6eqqmqB3YVn39q81U7Cw1QWNNg,721
|
13
|
+
mkdocs_document_dates/lang/zh.py,sha256=OrLElrSTZhHSwxBzuUtUj7NpQb7wm0s83viimpk2ynM,519
|
14
|
+
mkdocs_document_dates/lang/zh_tw.py,sha256=t3qu-a7UOzgcmYDkLFiosJZCcpfMU4xiKTJfu1ZHoHA,519
|
15
|
+
mkdocs_document_dates-0.5.0.dist-info/LICENSE,sha256=1YKfCs5WKSk-bON8a68WZE5to1B2klCrHBYiuaVCThM,514
|
16
|
+
mkdocs_document_dates-0.5.0.dist-info/METADATA,sha256=61z9w1Y7N1Ko1uotNJX6JXVhxPAscXe25fnIVHQKA8g,3569
|
17
|
+
mkdocs_document_dates-0.5.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
+
mkdocs_document_dates-0.5.0.dist-info/entry_points.txt,sha256=gI-OFLGjDG6-oLEfyevl3Gwwj2GcqVFQeX3bvL1IF8o,83
|
19
|
+
mkdocs_document_dates-0.5.0.dist-info/top_level.txt,sha256=yWkKQdNuAJJVqUQ9uLa5xD4x_Gux4IfOUpy8Ryagdwc,22
|
20
|
+
mkdocs_document_dates-0.5.0.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
mkdocs_document_dates/__init__.py,sha256=yom7psmObebsZY0AwCN1PjlGUwPkny2r6NyzoO0cudg,58
|
2
|
-
mkdocs_document_dates/plugin.py,sha256=zn9BfgqR3peyH33uY8Jwx1BDFT9fuMQgPsT5Y-0xo-Y,6584
|
3
|
-
mkdocs_document_dates-0.4.0.dist-info/LICENSE,sha256=1YKfCs5WKSk-bON8a68WZE5to1B2klCrHBYiuaVCThM,514
|
4
|
-
mkdocs_document_dates-0.4.0.dist-info/METADATA,sha256=4_lWCetVk8oxW6Acp7JEi7WG5GVTI7AffuHzCBgPNhw,3278
|
5
|
-
mkdocs_document_dates-0.4.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
6
|
-
mkdocs_document_dates-0.4.0.dist-info/entry_points.txt,sha256=gI-OFLGjDG6-oLEfyevl3Gwwj2GcqVFQeX3bvL1IF8o,83
|
7
|
-
mkdocs_document_dates-0.4.0.dist-info/top_level.txt,sha256=yWkKQdNuAJJVqUQ9uLa5xD4x_Gux4IfOUpy8Ryagdwc,22
|
8
|
-
mkdocs_document_dates-0.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{mkdocs_document_dates-0.4.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/top_level.txt
RENAMED
File without changes
|