mkdocs-document-dates 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +157 -88
- mkdocs_document_dates/styles.py +28 -0
- {mkdocs_document_dates-0.3.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.3.0.dist-info/RECORD +0 -8
- {mkdocs_document_dates-0.3.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/LICENSE +0 -0
- {mkdocs_document_dates-0.3.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/WHEEL +0 -0
- {mkdocs_document_dates-0.3.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/entry_points.txt +0 -0
- {mkdocs_document_dates-0.3.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,92 +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
|
-
file_path = page.file.abs_src_path
|
95
|
-
|
96
|
-
# 检查是否在排除列表中
|
97
|
-
for exclude_pattern in self.config['exclude']:
|
98
|
-
if Path(file_path).match(exclude_pattern):
|
99
|
-
return markdown
|
81
|
+
file_path = Path(page.file.abs_src_path)
|
100
82
|
|
101
|
-
|
102
|
-
|
83
|
+
if self._is_excluded(file_path, Path(config['docs_dir'])):
|
84
|
+
return markdown
|
103
85
|
|
104
|
-
|
105
|
-
|
106
|
-
if 'created_date' in meta:
|
107
|
-
try:
|
108
|
-
date_str = str(meta['created_date']).strip("'\"") # 移除可能存在的引号
|
109
|
-
created = datetime.fromisoformat(date_str)
|
110
|
-
except (ValueError, TypeError):
|
111
|
-
# 如果解析失败,保持原有的文件系统日期
|
112
|
-
pass
|
113
|
-
|
114
|
-
if 'modified_date' in meta:
|
115
|
-
try:
|
116
|
-
date_str = str(meta['modified_date']).strip("'\"") # 移除可能存在的引号
|
117
|
-
modified = datetime.fromisoformat(date_str)
|
118
|
-
except (ValueError, TypeError):
|
119
|
-
# 如果解析失败,保持原有的文件系统日期
|
120
|
-
pass
|
86
|
+
created, modified = self._get_file_dates(file_path)
|
87
|
+
created, modified = self._process_meta_dates(page.meta, created, modified)
|
121
88
|
|
122
|
-
|
123
|
-
|
124
|
-
|
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))
|
126
|
+
|
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
|
125
136
|
|
126
|
-
def
|
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):
|
127
148
|
"""获取文件的创建时间和修改时间"""
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
137
160
|
created = datetime.fromtimestamp(stat.st_ctime)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
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()
|
143
176
|
|
144
|
-
|
177
|
+
# 获取翻译字典
|
178
|
+
locale = self.config['locale']
|
179
|
+
if locale not in self.translations:
|
180
|
+
locale = 'en'
|
181
|
+
t = self.translations[locale]
|
182
|
+
|
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))
|
145
212
|
|
146
|
-
def
|
147
|
-
|
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':
|
148
218
|
return date.strftime(f"{self.config['date_format']} {self.config['time_format']}")
|
149
|
-
return date.strftime(self.config['date_format'])
|
150
|
-
|
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=uxjid20k8O3PnOdCV0FMxnE6iLp_J3aPJ3RIsNQcUUE,5397
|
3
|
-
mkdocs_document_dates-0.3.0.dist-info/LICENSE,sha256=1YKfCs5WKSk-bON8a68WZE5to1B2klCrHBYiuaVCThM,514
|
4
|
-
mkdocs_document_dates-0.3.0.dist-info/METADATA,sha256=E2lIEIgHJ0Kw9ZaavKM-Fqrv-AIm9Gsz10nFsbuNb8o,3252
|
5
|
-
mkdocs_document_dates-0.3.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
6
|
-
mkdocs_document_dates-0.3.0.dist-info/entry_points.txt,sha256=gI-OFLGjDG6-oLEfyevl3Gwwj2GcqVFQeX3bvL1IF8o,83
|
7
|
-
mkdocs_document_dates-0.3.0.dist-info/top_level.txt,sha256=yWkKQdNuAJJVqUQ9uLa5xD4x_Gux4IfOUpy8Ryagdwc,22
|
8
|
-
mkdocs_document_dates-0.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{mkdocs_document_dates-0.3.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{mkdocs_document_dates-0.3.0.dist-info → mkdocs_document_dates-0.5.0.dist-info}/top_level.txt
RENAMED
File without changes
|