staran 1.0.7__py3-none-any.whl → 1.0.8__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.
- staran/date/__init__.py +62 -2
- staran/date/core.py +364 -1
- staran/date/examples/v108_features_demo.py +257 -0
- staran/date/i18n.py +376 -0
- staran/date/lunar.py +320 -0
- staran/date/tests/test_v108_features.py +400 -0
- {staran-1.0.7.dist-info → staran-1.0.8.dist-info}/METADATA +79 -14
- {staran-1.0.7.dist-info → staran-1.0.8.dist-info}/RECORD +11 -7
- {staran-1.0.7.dist-info → staran-1.0.8.dist-info}/WHEEL +0 -0
- {staran-1.0.7.dist-info → staran-1.0.8.dist-info}/licenses/LICENSE +0 -0
- {staran-1.0.7.dist-info → staran-1.0.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
Staran v1.0.8 新功能演示
|
6
|
+
=======================
|
7
|
+
|
8
|
+
演示农历支持和多语言功能的使用方法。
|
9
|
+
"""
|
10
|
+
|
11
|
+
import sys
|
12
|
+
import os
|
13
|
+
|
14
|
+
# 添加项目根目录到路径
|
15
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
16
|
+
|
17
|
+
from staran.date import Date, from_lunar, set_language, get_language
|
18
|
+
from staran.date.lunar import LunarDate
|
19
|
+
from staran.date.i18n import Language
|
20
|
+
|
21
|
+
def demo_lunar_features():
|
22
|
+
"""演示农历功能"""
|
23
|
+
print("🌙 农历功能演示")
|
24
|
+
print("=" * 50)
|
25
|
+
|
26
|
+
# 1. 从农历日期创建公历日期
|
27
|
+
print("1. 从农历日期创建公历日期")
|
28
|
+
lunar_new_year = Date.from_lunar(2025, 1, 1) # 农历2025年正月初一
|
29
|
+
print(f" 农历2025年正月初一 → {lunar_new_year.format_iso()}")
|
30
|
+
|
31
|
+
mid_autumn = Date.from_lunar(2025, 8, 15) # 农历中秋节
|
32
|
+
print(f" 农历2025年八月十五 → {mid_autumn.format_iso()}")
|
33
|
+
|
34
|
+
# 2. 从农历字符串创建
|
35
|
+
print("\n2. 从农历字符串创建")
|
36
|
+
date_from_str = Date.from_lunar_string("20250315") # 农历三月十五
|
37
|
+
print(f" '20250315' → {date_from_str.format_iso()}")
|
38
|
+
|
39
|
+
# 闰月示例(假设2025年有闰月)
|
40
|
+
try:
|
41
|
+
leap_date = Date.from_lunar_string("2025闰0415") # 农历闰四月十五
|
42
|
+
print(f" '2025闰0415' → {leap_date.format_iso()}")
|
43
|
+
except:
|
44
|
+
print(f" 闰月示例跳过(2025年可能无闰四月)")
|
45
|
+
|
46
|
+
# 3. 公历转农历
|
47
|
+
print("\n3. 公历转农历")
|
48
|
+
solar_date = Date("20250415")
|
49
|
+
lunar = solar_date.to_lunar()
|
50
|
+
print(f" {solar_date.format_iso()} → {lunar.format_chinese()}")
|
51
|
+
print(f" 紧凑格式: {lunar.format_compact()}")
|
52
|
+
print(f" 天干地支: {lunar.get_ganzhi_year()}")
|
53
|
+
print(f" 生肖: {lunar.get_zodiac()}")
|
54
|
+
|
55
|
+
# 4. 农历格式化
|
56
|
+
print("\n4. 农历格式化")
|
57
|
+
test_date = Date("20250129") # 接近春节的日期
|
58
|
+
print(f" 基本格式: {test_date.format_lunar()}")
|
59
|
+
print(f" 包含生肖: {test_date.format_lunar(include_zodiac=True)}")
|
60
|
+
print(f" 紧凑格式: {test_date.format_lunar_compact()}")
|
61
|
+
|
62
|
+
# 5. 农历判断
|
63
|
+
print("\n5. 农历判断")
|
64
|
+
spring_festival = Date.from_lunar(2025, 1, 1)
|
65
|
+
print(f" 农历正月初一:")
|
66
|
+
print(f" 是否农历新年: {spring_festival.is_lunar_new_year()}")
|
67
|
+
print(f" 是否农历月初: {spring_festival.is_lunar_month_start()}")
|
68
|
+
print(f" 是否农历月中: {spring_festival.is_lunar_month_mid()}")
|
69
|
+
|
70
|
+
lantern_festival = Date.from_lunar(2025, 1, 15)
|
71
|
+
print(f" 农历正月十五:")
|
72
|
+
print(f" 是否农历新年: {lantern_festival.is_lunar_new_year()}")
|
73
|
+
print(f" 是否农历月中: {lantern_festival.is_lunar_month_mid()}")
|
74
|
+
|
75
|
+
# 6. 农历比较
|
76
|
+
print("\n6. 农历比较")
|
77
|
+
date1 = Date.from_lunar(2025, 1, 1)
|
78
|
+
date2 = Date.from_lunar(2025, 1, 15)
|
79
|
+
print(f" {date1.format_lunar()} vs {date2.format_lunar()}")
|
80
|
+
print(f" 比较结果: {date1.compare_lunar(date2)}") # -1: 前者小于后者
|
81
|
+
print(f" 是否同月: {date1.is_same_lunar_month(date2)}")
|
82
|
+
print(f" 是否同日: {date1.is_same_lunar_day(date2)}")
|
83
|
+
|
84
|
+
|
85
|
+
def demo_multilanguage_features():
|
86
|
+
"""演示多语言功能"""
|
87
|
+
print("\n\n🌍 多语言功能演示")
|
88
|
+
print("=" * 50)
|
89
|
+
|
90
|
+
# 测试日期
|
91
|
+
test_date = Date("20250415") # 2025年4月15日,星期二
|
92
|
+
|
93
|
+
print(f"测试日期: {test_date.format_iso()}")
|
94
|
+
|
95
|
+
# 1. 全局语言设置
|
96
|
+
print("\n1. 全局语言设置")
|
97
|
+
print(f" 当前语言: {get_language()}")
|
98
|
+
print(f" 支持的语言: {Date.get_supported_languages()}")
|
99
|
+
|
100
|
+
# 2. 中文简体
|
101
|
+
print("\n2. 中文简体 (zh_CN)")
|
102
|
+
set_language('zh_CN')
|
103
|
+
print(f" 本地化格式: {test_date.format_localized()}")
|
104
|
+
print(f" 星期格式: {test_date.format_weekday_localized()}")
|
105
|
+
print(f" 月份格式: {test_date.format_month_localized()}")
|
106
|
+
print(f" 季度格式: {test_date.format_quarter_localized()}")
|
107
|
+
print(f" 相对时间: {test_date.format_relative_localized()}")
|
108
|
+
|
109
|
+
# 3. 中文繁体
|
110
|
+
print("\n3. 中文繁体 (zh_TW)")
|
111
|
+
set_language('zh_TW')
|
112
|
+
print(f" 本地化格式: {test_date.format_localized()}")
|
113
|
+
print(f" 星期格式: {test_date.format_weekday_localized()}")
|
114
|
+
print(f" 相对时间: {test_date.format_relative_localized()}")
|
115
|
+
|
116
|
+
# 4. 日语
|
117
|
+
print("\n4. 日语 (ja_JP)")
|
118
|
+
set_language('ja_JP')
|
119
|
+
print(f" 本地化格式: {test_date.format_localized()}")
|
120
|
+
print(f" 星期格式: {test_date.format_weekday_localized()}")
|
121
|
+
print(f" 星期短格式: {test_date.format_weekday_localized(short=True)}")
|
122
|
+
print(f" 月份格式: {test_date.format_month_localized()}")
|
123
|
+
print(f" 相对时间: {test_date.format_relative_localized()}")
|
124
|
+
|
125
|
+
# 5. 英语
|
126
|
+
print("\n5. 英语 (en_US)")
|
127
|
+
set_language('en_US')
|
128
|
+
print(f" 本地化格式: {test_date.format_localized()}")
|
129
|
+
print(f" 星期格式: {test_date.format_weekday_localized()}")
|
130
|
+
print(f" 月份格式: {test_date.format_month_localized()}")
|
131
|
+
print(f" 季度格式: {test_date.format_quarter_localized()}")
|
132
|
+
print(f" 相对时间: {test_date.format_relative_localized()}")
|
133
|
+
|
134
|
+
# 6. 单次覆盖演示
|
135
|
+
print("\n6. 单次语言覆盖")
|
136
|
+
set_language('zh_CN') # 设置全局为中文
|
137
|
+
print(f" 全局中文: {test_date.format_weekday_localized()}")
|
138
|
+
print(f" 单次英语: {test_date.format_weekday_localized(language_code='en_US')}")
|
139
|
+
print(f" 仍是中文: {test_date.format_weekday_localized()}")
|
140
|
+
|
141
|
+
# 7. 相对时间多语言演示
|
142
|
+
print("\n7. 相对时间多语言演示")
|
143
|
+
today = Date.today()
|
144
|
+
tomorrow = today.add_days(1)
|
145
|
+
yesterday = today.add_days(-1)
|
146
|
+
next_week = today.add_days(7)
|
147
|
+
|
148
|
+
languages = ['zh_CN', 'zh_TW', 'ja_JP', 'en_US']
|
149
|
+
|
150
|
+
for lang in languages:
|
151
|
+
set_language(lang)
|
152
|
+
lang_name = Date.get_supported_languages()[lang]
|
153
|
+
print(f" {lang_name}:")
|
154
|
+
print(f" 今天: {today.format_relative_localized()}")
|
155
|
+
print(f" 明天: {tomorrow.format_relative_localized()}")
|
156
|
+
print(f" 昨天: {yesterday.format_relative_localized()}")
|
157
|
+
print(f" 下周: {next_week.format_relative_localized()}")
|
158
|
+
|
159
|
+
|
160
|
+
def demo_combined_features():
|
161
|
+
"""演示农历和多语言组合功能"""
|
162
|
+
print("\n\n🔄 农历 + 多语言组合演示")
|
163
|
+
print("=" * 50)
|
164
|
+
|
165
|
+
# 中国传统节日
|
166
|
+
spring_festival = Date.from_lunar(2025, 1, 1) # 春节
|
167
|
+
mid_autumn = Date.from_lunar(2025, 8, 15) # 中秋
|
168
|
+
|
169
|
+
festivals = [
|
170
|
+
(spring_festival, "春节(农历正月初一)"),
|
171
|
+
(mid_autumn, "中秋节(农历八月十五)")
|
172
|
+
]
|
173
|
+
|
174
|
+
languages = ['zh_CN', 'zh_TW', 'ja_JP', 'en_US']
|
175
|
+
|
176
|
+
for date, festival_name in festivals:
|
177
|
+
print(f"\n{festival_name}")
|
178
|
+
print(f"公历日期: {date.format_iso()}")
|
179
|
+
|
180
|
+
for lang in languages:
|
181
|
+
set_language(lang)
|
182
|
+
lang_name = Date.get_supported_languages()[lang]
|
183
|
+
print(f" {lang_name}:")
|
184
|
+
print(f" 本地化: {date.format_localized()}")
|
185
|
+
print(f" 星期: {date.format_weekday_localized()}")
|
186
|
+
print(f" 农历: {date.format_lunar()}")
|
187
|
+
|
188
|
+
|
189
|
+
def demo_performance():
|
190
|
+
"""演示性能"""
|
191
|
+
print("\n\n⚡ 性能演示")
|
192
|
+
print("=" * 50)
|
193
|
+
|
194
|
+
import time
|
195
|
+
|
196
|
+
# 农历转换性能
|
197
|
+
start_time = time.time()
|
198
|
+
dates = []
|
199
|
+
for i in range(100):
|
200
|
+
date = Date.from_lunar(2025, 1, i % 29 + 1)
|
201
|
+
dates.append(date)
|
202
|
+
lunar_time = time.time() - start_time
|
203
|
+
print(f"创建100个农历日期: {lunar_time:.4f}秒")
|
204
|
+
|
205
|
+
# 格式化性能
|
206
|
+
start_time = time.time()
|
207
|
+
test_date = Date("20250415")
|
208
|
+
for i in range(1000):
|
209
|
+
formatted = test_date.format_localized()
|
210
|
+
format_time = time.time() - start_time
|
211
|
+
print(f"格式化1000次: {format_time:.4f}秒")
|
212
|
+
|
213
|
+
# 语言切换性能
|
214
|
+
start_time = time.time()
|
215
|
+
languages = ['zh_CN', 'zh_TW', 'ja_JP', 'en_US']
|
216
|
+
for i in range(100):
|
217
|
+
set_language(languages[i % 4])
|
218
|
+
switch_time = time.time() - start_time
|
219
|
+
print(f"语言切换100次: {switch_time:.4f}秒")
|
220
|
+
|
221
|
+
|
222
|
+
if __name__ == "__main__":
|
223
|
+
print("🚀 Staran v1.0.8 新功能完整演示")
|
224
|
+
print("=" * 60)
|
225
|
+
|
226
|
+
try:
|
227
|
+
# 演示农历功能
|
228
|
+
demo_lunar_features()
|
229
|
+
|
230
|
+
# 演示多语言功能
|
231
|
+
demo_multilanguage_features()
|
232
|
+
|
233
|
+
# 演示组合功能
|
234
|
+
demo_combined_features()
|
235
|
+
|
236
|
+
# 演示性能
|
237
|
+
demo_performance()
|
238
|
+
|
239
|
+
print("\n\n✅ 演示完成!")
|
240
|
+
print("=" * 60)
|
241
|
+
print("🌟 主要新功能:")
|
242
|
+
print(" • 农历与公历互转")
|
243
|
+
print(" • 农历日期格式化")
|
244
|
+
print(" • 农历日期比较和判断")
|
245
|
+
print(" • 中简、中繁、日、英四种语言支持")
|
246
|
+
print(" • 全局语言设置")
|
247
|
+
print(" • 单次使用语言覆盖")
|
248
|
+
print(" • 多语言本地化格式")
|
249
|
+
print(" • 120+ API方法,保持向后兼容")
|
250
|
+
|
251
|
+
except Exception as e:
|
252
|
+
print(f"\n❌ 演示过程中出现错误: {e}")
|
253
|
+
import traceback
|
254
|
+
traceback.print_exc()
|
255
|
+
|
256
|
+
# 恢复默认语言
|
257
|
+
set_language('zh_CN')
|
staran/date/i18n.py
ADDED
@@ -0,0 +1,376 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
多语言配置模块
|
6
|
+
=============
|
7
|
+
|
8
|
+
提供中简、中繁、日、英四种语言的配置支持,
|
9
|
+
支持全局语言设置和单次使用覆盖。
|
10
|
+
"""
|
11
|
+
|
12
|
+
from typing import Dict, Any, Optional
|
13
|
+
import threading
|
14
|
+
|
15
|
+
|
16
|
+
class Language:
|
17
|
+
"""语言配置类
|
18
|
+
|
19
|
+
支持中简、中繁、日、英四种语言的本地化配置。
|
20
|
+
配置一次后全局生效,也支持单次使用时覆盖。
|
21
|
+
"""
|
22
|
+
|
23
|
+
# 支持的语言代码
|
24
|
+
SUPPORTED_LANGUAGES = ['zh_CN', 'zh_TW', 'ja_JP', 'en_US']
|
25
|
+
|
26
|
+
# 语言配置数据
|
27
|
+
_LANGUAGE_DATA = {
|
28
|
+
'zh_CN': { # 中文简体
|
29
|
+
'name': '中文简体',
|
30
|
+
'weekdays': ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
|
31
|
+
'weekdays_short': ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
32
|
+
'months': ['一月', '二月', '三月', '四月', '五月', '六月',
|
33
|
+
'七月', '八月', '九月', '十月', '十一月', '十二月'],
|
34
|
+
'months_short': ['1月', '2月', '3月', '4月', '5月', '6月',
|
35
|
+
'7月', '8月', '9月', '10月', '11月', '12月'],
|
36
|
+
'date_formats': {
|
37
|
+
'full': '{year}年{month:02d}月{day:02d}日',
|
38
|
+
'short': '{year}/{month:02d}/{day:02d}',
|
39
|
+
'year_month': '{year}年{month:02d}月',
|
40
|
+
'month_day': '{month:02d}月{day:02d}日'
|
41
|
+
},
|
42
|
+
'relative_time': {
|
43
|
+
'today': '今天',
|
44
|
+
'tomorrow': '明天',
|
45
|
+
'yesterday': '昨天',
|
46
|
+
'days_ago': '{days}天前',
|
47
|
+
'days_later': '{days}天后',
|
48
|
+
'weeks_ago': '{weeks}周前',
|
49
|
+
'weeks_later': '{weeks}周后',
|
50
|
+
'months_ago': '{months}个月前',
|
51
|
+
'months_later': '{months}个月后',
|
52
|
+
'years_ago': '{years}年前',
|
53
|
+
'years_later': '{years}年后'
|
54
|
+
},
|
55
|
+
'quarters': ['第一季度', '第二季度', '第三季度', '第四季度'],
|
56
|
+
'quarters_short': ['Q1', 'Q2', 'Q3', 'Q4'],
|
57
|
+
'lunar': {
|
58
|
+
'prefix': '农历',
|
59
|
+
'leap_month': '闰{month}月',
|
60
|
+
'ganzhi_year': '{ganzhi}年',
|
61
|
+
'zodiac_year': '{zodiac}年'
|
62
|
+
},
|
63
|
+
'business_terms': {
|
64
|
+
'business_day': '工作日',
|
65
|
+
'weekend': '周末',
|
66
|
+
'holiday': '节假日',
|
67
|
+
'workday': '工作日'
|
68
|
+
}
|
69
|
+
},
|
70
|
+
'zh_TW': { # 中文繁体
|
71
|
+
'name': '中文繁體',
|
72
|
+
'weekdays': ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
|
73
|
+
'weekdays_short': ['週一', '週二', '週三', '週四', '週五', '週六', '週日'],
|
74
|
+
'months': ['一月', '二月', '三月', '四月', '五月', '六月',
|
75
|
+
'七月', '八月', '九月', '十月', '十一月', '十二月'],
|
76
|
+
'months_short': ['1月', '2月', '3月', '4月', '5月', '6月',
|
77
|
+
'7月', '8月', '9月', '10月', '11月', '12月'],
|
78
|
+
'date_formats': {
|
79
|
+
'full': '{year}年{month:02d}月{day:02d}日',
|
80
|
+
'short': '{year}/{month:02d}/{day:02d}',
|
81
|
+
'year_month': '{year}年{month:02d}月',
|
82
|
+
'month_day': '{month:02d}月{day:02d}日'
|
83
|
+
},
|
84
|
+
'relative_time': {
|
85
|
+
'today': '今天',
|
86
|
+
'tomorrow': '明天',
|
87
|
+
'yesterday': '昨天',
|
88
|
+
'days_ago': '{days}天前',
|
89
|
+
'days_later': '{days}天後',
|
90
|
+
'weeks_ago': '{weeks}週前',
|
91
|
+
'weeks_later': '{weeks}週後',
|
92
|
+
'months_ago': '{months}個月前',
|
93
|
+
'months_later': '{months}個月後',
|
94
|
+
'years_ago': '{years}年前',
|
95
|
+
'years_later': '{years}年後'
|
96
|
+
},
|
97
|
+
'quarters': ['第一季度', '第二季度', '第三季度', '第四季度'],
|
98
|
+
'quarters_short': ['Q1', 'Q2', 'Q3', 'Q4'],
|
99
|
+
'lunar': {
|
100
|
+
'prefix': '農曆',
|
101
|
+
'leap_month': '閏{month}月',
|
102
|
+
'ganzhi_year': '{ganzhi}年',
|
103
|
+
'zodiac_year': '{zodiac}年'
|
104
|
+
},
|
105
|
+
'business_terms': {
|
106
|
+
'business_day': '工作日',
|
107
|
+
'weekend': '週末',
|
108
|
+
'holiday': '節假日',
|
109
|
+
'workday': '工作日'
|
110
|
+
}
|
111
|
+
},
|
112
|
+
'ja_JP': { # 日语
|
113
|
+
'name': '日本語',
|
114
|
+
'weekdays': ['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'],
|
115
|
+
'weekdays_short': ['月', '火', '水', '木', '金', '土', '日'],
|
116
|
+
'months': ['1月', '2月', '3月', '4月', '5月', '6月',
|
117
|
+
'7月', '8月', '9月', '10月', '11月', '12月'],
|
118
|
+
'months_short': ['1月', '2月', '3月', '4月', '5月', '6月',
|
119
|
+
'7月', '8月', '9月', '10月', '11月', '12月'],
|
120
|
+
'date_formats': {
|
121
|
+
'full': '{year}年{month:02d}月{day:02d}日',
|
122
|
+
'short': '{year}/{month:02d}/{day:02d}',
|
123
|
+
'year_month': '{year}年{month:02d}月',
|
124
|
+
'month_day': '{month:02d}月{day:02d}日'
|
125
|
+
},
|
126
|
+
'relative_time': {
|
127
|
+
'today': '今日',
|
128
|
+
'tomorrow': '明日',
|
129
|
+
'yesterday': '昨日',
|
130
|
+
'days_ago': '{days}日前',
|
131
|
+
'days_later': '{days}日後',
|
132
|
+
'weeks_ago': '{weeks}週間前',
|
133
|
+
'weeks_later': '{weeks}週間後',
|
134
|
+
'months_ago': '{months}ヶ月前',
|
135
|
+
'months_later': '{months}ヶ月後',
|
136
|
+
'years_ago': '{years}年前',
|
137
|
+
'years_later': '{years}年後'
|
138
|
+
},
|
139
|
+
'quarters': ['第1四半期', '第2四半期', '第3四半期', '第4四半期'],
|
140
|
+
'quarters_short': ['Q1', 'Q2', 'Q3', 'Q4'],
|
141
|
+
'lunar': {
|
142
|
+
'prefix': '旧暦',
|
143
|
+
'leap_month': '閏{month}月',
|
144
|
+
'ganzhi_year': '{ganzhi}年',
|
145
|
+
'zodiac_year': '{zodiac}年'
|
146
|
+
},
|
147
|
+
'business_terms': {
|
148
|
+
'business_day': '営業日',
|
149
|
+
'weekend': '週末',
|
150
|
+
'holiday': '祝日',
|
151
|
+
'workday': '平日'
|
152
|
+
}
|
153
|
+
},
|
154
|
+
'en_US': { # 英语
|
155
|
+
'name': 'English',
|
156
|
+
'weekdays': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
157
|
+
'weekdays_short': ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
158
|
+
'months': ['January', 'February', 'March', 'April', 'May', 'June',
|
159
|
+
'July', 'August', 'September', 'October', 'November', 'December'],
|
160
|
+
'months_short': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
161
|
+
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
162
|
+
'date_formats': {
|
163
|
+
'full': '{month:02d}/{day:02d}/{year}',
|
164
|
+
'short': '{month:02d}/{day:02d}/{year}',
|
165
|
+
'year_month': '{month:02d}/{year}',
|
166
|
+
'month_day': '{month:02d}/{day:02d}'
|
167
|
+
},
|
168
|
+
'relative_time': {
|
169
|
+
'today': 'today',
|
170
|
+
'tomorrow': 'tomorrow',
|
171
|
+
'yesterday': 'yesterday',
|
172
|
+
'days_ago': '{days} days ago',
|
173
|
+
'days_later': 'in {days} days',
|
174
|
+
'weeks_ago': '{weeks} weeks ago',
|
175
|
+
'weeks_later': 'in {weeks} weeks',
|
176
|
+
'months_ago': '{months} months ago',
|
177
|
+
'months_later': 'in {months} months',
|
178
|
+
'years_ago': '{years} years ago',
|
179
|
+
'years_later': 'in {years} years'
|
180
|
+
},
|
181
|
+
'quarters': ['1st Quarter', '2nd Quarter', '3rd Quarter', '4th Quarter'],
|
182
|
+
'quarters_short': ['Q1', 'Q2', 'Q3', 'Q4'],
|
183
|
+
'lunar': {
|
184
|
+
'prefix': 'Lunar',
|
185
|
+
'leap_month': 'Leap {month}',
|
186
|
+
'ganzhi_year': '{ganzhi} Year',
|
187
|
+
'zodiac_year': 'Year of {zodiac}'
|
188
|
+
},
|
189
|
+
'business_terms': {
|
190
|
+
'business_day': 'business day',
|
191
|
+
'weekend': 'weekend',
|
192
|
+
'holiday': 'holiday',
|
193
|
+
'workday': 'workday'
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
# 全局语言设置
|
199
|
+
_global_language = 'zh_CN' # 默认中文简体
|
200
|
+
_lock = threading.Lock()
|
201
|
+
|
202
|
+
@classmethod
|
203
|
+
def set_global_language(cls, language_code: str) -> None:
|
204
|
+
"""设置全局语言
|
205
|
+
|
206
|
+
Args:
|
207
|
+
language_code: 语言代码 (zh_CN, zh_TW, ja_JP, en_US)
|
208
|
+
|
209
|
+
Raises:
|
210
|
+
ValueError: 不支持的语言代码
|
211
|
+
"""
|
212
|
+
if language_code not in cls.SUPPORTED_LANGUAGES:
|
213
|
+
raise ValueError(f"不支持的语言代码: {language_code}。支持的语言: {cls.SUPPORTED_LANGUAGES}")
|
214
|
+
|
215
|
+
with cls._lock:
|
216
|
+
cls._global_language = language_code
|
217
|
+
|
218
|
+
@classmethod
|
219
|
+
def get_global_language(cls) -> str:
|
220
|
+
"""获取当前全局语言设置"""
|
221
|
+
return cls._global_language
|
222
|
+
|
223
|
+
@classmethod
|
224
|
+
def get_language_data(cls, language_code: Optional[str] = None) -> Dict[str, Any]:
|
225
|
+
"""获取语言数据
|
226
|
+
|
227
|
+
Args:
|
228
|
+
language_code: 语言代码,如果为None则使用全局设置
|
229
|
+
|
230
|
+
Returns:
|
231
|
+
语言数据字典
|
232
|
+
|
233
|
+
Raises:
|
234
|
+
ValueError: 不支持的语言代码
|
235
|
+
"""
|
236
|
+
if language_code is None:
|
237
|
+
language_code = cls._global_language
|
238
|
+
|
239
|
+
if language_code not in cls.SUPPORTED_LANGUAGES:
|
240
|
+
raise ValueError(f"不支持的语言代码: {language_code}")
|
241
|
+
|
242
|
+
return cls._LANGUAGE_DATA[language_code].copy()
|
243
|
+
|
244
|
+
@classmethod
|
245
|
+
def get_weekday_name(cls, weekday_index: int, short: bool = False,
|
246
|
+
language_code: Optional[str] = None) -> str:
|
247
|
+
"""获取星期几的名称
|
248
|
+
|
249
|
+
Args:
|
250
|
+
weekday_index: 星期几索引 (0=星期一, 6=星期日)
|
251
|
+
short: 是否使用短名称
|
252
|
+
language_code: 语言代码
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
星期几的名称
|
256
|
+
"""
|
257
|
+
data = cls.get_language_data(language_code)
|
258
|
+
weekdays = data['weekdays_short'] if short else data['weekdays']
|
259
|
+
return weekdays[weekday_index % 7]
|
260
|
+
|
261
|
+
@classmethod
|
262
|
+
def get_month_name(cls, month: int, short: bool = False,
|
263
|
+
language_code: Optional[str] = None) -> str:
|
264
|
+
"""获取月份名称
|
265
|
+
|
266
|
+
Args:
|
267
|
+
month: 月份 (1-12)
|
268
|
+
short: 是否使用短名称
|
269
|
+
language_code: 语言代码
|
270
|
+
|
271
|
+
Returns:
|
272
|
+
月份名称
|
273
|
+
"""
|
274
|
+
data = cls.get_language_data(language_code)
|
275
|
+
months = data['months_short'] if short else data['months']
|
276
|
+
return months[month - 1]
|
277
|
+
|
278
|
+
@classmethod
|
279
|
+
def get_quarter_name(cls, quarter: int, short: bool = False,
|
280
|
+
language_code: Optional[str] = None) -> str:
|
281
|
+
"""获取季度名称
|
282
|
+
|
283
|
+
Args:
|
284
|
+
quarter: 季度 (1-4)
|
285
|
+
short: 是否使用短名称
|
286
|
+
language_code: 语言代码
|
287
|
+
|
288
|
+
Returns:
|
289
|
+
季度名称
|
290
|
+
"""
|
291
|
+
data = cls.get_language_data(language_code)
|
292
|
+
quarters = data['quarters_short'] if short else data['quarters']
|
293
|
+
return quarters[quarter - 1]
|
294
|
+
|
295
|
+
@classmethod
|
296
|
+
def format_date(cls, year: int, month: int, day: int, format_type: str = 'full',
|
297
|
+
language_code: Optional[str] = None) -> str:
|
298
|
+
"""格式化日期
|
299
|
+
|
300
|
+
Args:
|
301
|
+
year: 年份
|
302
|
+
month: 月份
|
303
|
+
day: 日期
|
304
|
+
format_type: 格式类型 (full, short, year_month, month_day)
|
305
|
+
language_code: 语言代码
|
306
|
+
|
307
|
+
Returns:
|
308
|
+
格式化后的日期字符串
|
309
|
+
"""
|
310
|
+
data = cls.get_language_data(language_code)
|
311
|
+
date_format = data['date_formats'].get(format_type, data['date_formats']['full'])
|
312
|
+
return date_format.format(year=year, month=month, day=day)
|
313
|
+
|
314
|
+
@classmethod
|
315
|
+
def format_relative_time(cls, relative_type: str, value: int = 0,
|
316
|
+
language_code: Optional[str] = None) -> str:
|
317
|
+
"""格式化相对时间
|
318
|
+
|
319
|
+
Args:
|
320
|
+
relative_type: 相对时间类型 (today, tomorrow, yesterday, days_ago等)
|
321
|
+
value: 数值 (如天数、周数等)
|
322
|
+
language_code: 语言代码
|
323
|
+
|
324
|
+
Returns:
|
325
|
+
格式化后的相对时间字符串
|
326
|
+
"""
|
327
|
+
data = cls.get_language_data(language_code)
|
328
|
+
relative_format = data['relative_time'].get(relative_type, relative_type)
|
329
|
+
|
330
|
+
if '{' in relative_format:
|
331
|
+
# 处理需要替换值的格式
|
332
|
+
if 'days' in relative_type:
|
333
|
+
return relative_format.format(days=value)
|
334
|
+
elif 'weeks' in relative_type:
|
335
|
+
return relative_format.format(weeks=value)
|
336
|
+
elif 'months' in relative_type:
|
337
|
+
return relative_format.format(months=value)
|
338
|
+
elif 'years' in relative_type:
|
339
|
+
return relative_format.format(years=value)
|
340
|
+
|
341
|
+
return relative_format
|
342
|
+
|
343
|
+
@classmethod
|
344
|
+
def get_business_term(cls, term: str, language_code: Optional[str] = None) -> str:
|
345
|
+
"""获取商务术语
|
346
|
+
|
347
|
+
Args:
|
348
|
+
term: 术语名称 (business_day, weekend, holiday, workday)
|
349
|
+
language_code: 语言代码
|
350
|
+
|
351
|
+
Returns:
|
352
|
+
本地化的术语
|
353
|
+
"""
|
354
|
+
data = cls.get_language_data(language_code)
|
355
|
+
return data['business_terms'].get(term, term)
|
356
|
+
|
357
|
+
@classmethod
|
358
|
+
def get_supported_languages(cls) -> Dict[str, str]:
|
359
|
+
"""获取支持的语言列表
|
360
|
+
|
361
|
+
Returns:
|
362
|
+
语言代码到语言名称的映射
|
363
|
+
"""
|
364
|
+
return {code: cls._LANGUAGE_DATA[code]['name'] for code in cls.SUPPORTED_LANGUAGES}
|
365
|
+
|
366
|
+
@classmethod
|
367
|
+
def is_supported_language(cls, language_code: str) -> bool:
|
368
|
+
"""检查是否支持指定语言
|
369
|
+
|
370
|
+
Args:
|
371
|
+
language_code: 语言代码
|
372
|
+
|
373
|
+
Returns:
|
374
|
+
是否支持
|
375
|
+
"""
|
376
|
+
return language_code in cls.SUPPORTED_LANGUAGES
|