1313
1414PROJECT_ROOT = Path (__file__ ).resolve ().parents [1 ]
1515DEFAULT_OUTPUT_DIR = PROJECT_ROOT / "data" / "output"
16+ DEFAULT_NOTIFY_LANG = "en"
17+ SUPPORTED_NOTIFY_LANGS = {"en" , "zh" }
18+
19+ _TEXTS = {
20+ "en" : {
21+ "title" : "CryptoLivePoolPipelines monthly release" ,
22+ "status" : "status" ,
23+ "status_ok" : "ok" ,
24+ "status_warning" : "warning" ,
25+ "as_of_date" : "as_of_date" ,
26+ "official" : "official" ,
27+ "shadow" : "shadow" ,
28+ "shadow_not_generated" : "not_generated_in_this_run" ,
29+ "manifest" : "manifest" ,
30+ "present" : "present" ,
31+ "missing" : "missing" ,
32+ "validation" : "validation" ,
33+ "warnings" : "warnings" ,
34+ "none" : "none" ,
35+ },
36+ "zh" : {
37+ "title" : "CryptoLivePoolPipelines 月度发布" ,
38+ "status" : "状态" ,
39+ "status_ok" : "正常" ,
40+ "status_warning" : "警告" ,
41+ "as_of_date" : "日期" ,
42+ "official" : "官方池" ,
43+ "shadow" : "影子池" ,
44+ "shadow_not_generated" : "本轮未生成" ,
45+ "manifest" : "发布清单" ,
46+ "present" : "已存在" ,
47+ "missing" : "缺失" ,
48+ "validation" : "校验" ,
49+ "warnings" : "告警" ,
50+ "none" : "无" ,
51+ },
52+ }
53+
54+
55+ def get_notify_lang (value : str | None = None ) -> str :
56+ raw = str (value if value is not None else os .getenv ("NOTIFY_LANG" , DEFAULT_NOTIFY_LANG )).strip ().lower ()
57+ if raw in SUPPORTED_NOTIFY_LANGS :
58+ return raw
59+ return DEFAULT_NOTIFY_LANG
60+
61+
62+ def text (lang : str , key : str ) -> str :
63+ active_lang = lang if lang in SUPPORTED_NOTIFY_LANGS else DEFAULT_NOTIFY_LANG
64+ return _TEXTS .get (active_lang , _TEXTS [DEFAULT_NOTIFY_LANG ]).get (key , _TEXTS [DEFAULT_NOTIFY_LANG ].get (key , key ))
1665
1766
1867def parse_args () -> argparse .Namespace :
@@ -34,6 +83,11 @@ def parse_args() -> argparse.Namespace:
3483 default = "" ,
3584 help = "Optional path to write the rendered message for bundle packaging." ,
3685 )
86+ parser .add_argument (
87+ "--lang" ,
88+ default = "" ,
89+ help = "Notification language override. Supported values: en, zh. Defaults to NOTIFY_LANG or en." ,
90+ )
3791 return parser .parse_args ()
3892
3993
@@ -146,42 +200,44 @@ def build_health_payload(output_dir: Path | str) -> dict[str, Any]:
146200 }
147201
148202
149- def format_message (payload : dict [str , Any ]) -> str :
203+ def format_message (payload : dict [str , Any ], * , lang : str | None = None ) -> str :
204+ active_lang = get_notify_lang (lang )
150205 official = payload ["official_baseline" ]
151206 manifest = payload ["manifest" ]
152207 validation = payload ["validation" ]
153208 shadow = payload ["shadow_tracks" ]
154209 shadow_line = (
155- " shadow: "
210+ f" { text ( active_lang , ' shadow' ) } : "
156211 f"official_baseline last={ shadow ['official_baseline' ]['last_as_of_date' ]} "
157212 f"releases={ shadow ['official_baseline' ]['release_count' ]} ; "
158213 f"challenger_topk_60 last={ shadow ['challenger_topk_60' ]['last_as_of_date' ]} "
159214 f"releases={ shadow ['challenger_topk_60' ]['release_count' ]} "
160215 if shadow ["official_baseline" ]["available" ] or shadow ["challenger_topk_60" ]["available" ]
161- else " shadow: not_generated_in_this_run "
216+ else f" { text ( active_lang , ' shadow' ) } : { text ( active_lang , 'shadow_not_generated' ) } "
162217 )
218+ status_key = "status_ok" if payload ["status" ] == "ok" else "status_warning"
163219 lines = [
164- "CryptoLivePoolPipelines monthly release" ,
165- f"status: { payload [ 'status' ] } " ,
166- f"as_of_date: { payload ['as_of_date' ]} " ,
220+ text ( active_lang , "title" ) ,
221+ f"{ text ( active_lang , 'status' ) } : { text ( active_lang , status_key ) } " ,
222+ f"{ text ( active_lang , ' as_of_date' ) } : { payload ['as_of_date' ]} " ,
167223 (
168- " official: "
224+ f" { text ( active_lang , ' official' ) } : "
169225 f"profile={ official ['profile' ]} "
170226 f"version={ official ['version' ]} "
171227 f"mode={ official ['mode' ]} "
172228 f"pool_size={ official ['pool_size' ]} "
173229 ),
174230 shadow_line ,
175- f"manifest: { 'present' if manifest ['present' ] else 'missing' } dry_run={ manifest ['dry_run' ]} " ,
231+ f"{ text ( active_lang , ' manifest' ) } : { text ( active_lang , 'present' ) if manifest ['present' ] else text ( active_lang , 'missing' ) } dry_run={ manifest ['dry_run' ]} " ,
176232 ]
177233 if validation ["ok" ] is not None :
178234 lines .append (
179- f"validation: ok={ validation ['ok' ]} manifest_present={ validation ['manifest_present' ]} age_days={ validation ['age_days' ]} "
235+ f"{ text ( active_lang , ' validation' ) } : ok={ validation ['ok' ]} manifest_present={ validation ['manifest_present' ]} age_days={ validation ['age_days' ]} "
180236 )
181237 if payload ["warnings" ]:
182- lines .append (" warnings: " + " | " .join (payload ["warnings" ][:4 ]))
238+ lines .append (f" { text ( active_lang , ' warnings' ) } : " + " | " .join (payload ["warnings" ][:4 ]))
183239 else :
184- lines .append (" warnings: none" )
240+ lines .append (f" { text ( active_lang , ' warnings' ) } : { text ( active_lang , ' none' ) } " )
185241 return "\n " .join (lines )
186242
187243
@@ -201,7 +257,7 @@ def send_telegram_message(token: str, chat_id: str, message: str) -> None:
201257def main () -> None :
202258 args = parse_args ()
203259 payload = build_health_payload (args .output_dir )
204- message = format_message (payload )
260+ message = format_message (payload , lang = getattr ( args , "lang" , "" ) )
205261 print (message )
206262 if args .output_path :
207263 output_path = Path (args .output_path )
0 commit comments