Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/quant_platform_kit/common/notification_localization.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@
NotificationReplacement = tuple[str, str]


PRICE_SOURCE_LABELS: dict[str, tuple[str, str]] = {
"longbridge_candlesticks": ("LongBridge 日线K线", "LongBridge daily candlesticks"),
"schwab_daily_history_with_live_quote_overlay": (
"Schwab 日线历史 + 实时报价覆盖",
"Schwab daily history + live quote overlay",
),
"firstrade_ohlc_with_live_quote_overlay": (
"Firstrade OHLC + 实时报价覆盖",
"Firstrade OHLC + live quote overlay",
),
"market_quote": ("实时行情报价", "market quote"),
"mixed_market_quote_snapshot_close": (
"实时行情报价 + 快照收盘价回补",
"market quote + snapshot close fallback",
),
"mixed_market_quote_historical_close": (
"实时行情报价 + 历史收盘价回补",
"market quote + historical close fallback",
),
"snapshot_close": ("快照收盘价", "snapshot close"),
"historical_close": ("历史收盘价", "historical close"),
"market_data": ("市场数据", "market data"),
}


COMMON_ZH_NOTIFICATION_REPLACEMENTS: tuple[NotificationReplacement, ...] = (
("feature snapshot guard blocked execution", "特征快照校验阻止执行"),
("feature snapshot required", "需要特征快照"),
Expand Down Expand Up @@ -83,6 +108,41 @@ def translator_uses_zh(translator: NotificationTranslator) -> bool:
return any("\u4e00" <= ch <= "\u9fff" for ch in sample)


def locale_uses_zh(locale: str | None) -> bool:
return str(locale or "").strip().lower().startswith("zh")


def localize_price_source_label(
value: object,
*,
translator: NotificationTranslator | None = None,
locale: str | None = None,
) -> str:
source = str(value or "").strip()
use_zh = translator_uses_zh(translator) if translator is not None else locale_uses_zh(locale)
unknown = "未知" if use_zh else "unknown"
if not source:
return unknown
label = PRICE_SOURCE_LABELS.get(source)
if label is not None:
return label[0] if use_zh else label[1]
return source.replace("_", " ")


def localize_quote_overlay_state(
value: object,
*,
translator: NotificationTranslator | None = None,
locale: str | None = None,
) -> str:
use_zh = translator_uses_zh(translator) if translator is not None else locale_uses_zh(locale)
if value is True:
return "是" if use_zh else "yes"
if value is False:
return "否" if use_zh else "no"
return "未知" if use_zh else "unknown"


def localize_notification_text(
text: object,
*,
Expand Down
23 changes: 23 additions & 0 deletions tests/test_notification_localization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from quant_platform_kit.common.notification_localization import (
COMMON_ZH_NOTIFICATION_REPLACEMENTS,
localize_price_source_label,
localize_quote_overlay_state,
localize_notification_text,
translator_uses_zh,
)
Expand Down Expand Up @@ -56,6 +58,27 @@ def test_localize_notification_text_applies_extra_replacements_after_common_set(
def test_common_replacements_include_reason_label(self):
self.assertIn(("reason=", "原因="), COMMON_ZH_NOTIFICATION_REPLACEMENTS)

def test_localize_price_source_label_supports_broker_sources(self):
self.assertEqual(
localize_price_source_label(
"schwab_daily_history_with_live_quote_overlay",
translator=_translator_factory("无需交易"),
),
"Schwab 日线历史 + 实时报价覆盖",
)
self.assertEqual(
localize_price_source_label(
"longbridge_candlesticks",
translator=_translator_factory("No trades"),
),
"LongBridge daily candlesticks",
)

def test_localize_quote_overlay_state_supports_locale_without_translator(self):
self.assertEqual(localize_quote_overlay_state(True, locale="zh-CN"), "是")
self.assertEqual(localize_quote_overlay_state(False, locale="en-US"), "no")
self.assertEqual(localize_quote_overlay_state(None, locale="zh"), "未知")


if __name__ == "__main__":
unittest.main()