"""Reader-only applicability notes; never changes dasha calculations or periods. ``language="en"`` renders the same table from the same packet with the static English wording below; the default ``"zh"`` output is unchanged. """ BOUNDARY = "第二时间轴,仅供交叉核对,不单独生成应期" MISSING = "缺少本次计算的结构化适用性证据,无法确认各辅助时间轴是否适用;不补算、不补写日期。" REASON_LABELS = { "patyayini_dasha_missing": "本次计算未提供帕特雅伊尼年运周期,暂不能用于时间核对。", "The Shodashottari hora-plus-paksha applicability gate is not met.": "未满足该大运对时辰分区与月相组合的适用条件。", "This profile requires Navamsa Lagna in Taurus or Libra.": "该大运要求九分盘上升落在金牛座或天秤座,本次未满足。", "Dwisaptatisama requires Lagna lord in the 1st or 7th house.": "该大运要求上升主星位于第一宫或第七宫,本次未满足。", "Panchottari requires a Cancer Ascendant that is also Cancer in Dwadasamsa.": "该大运要求本命及十二分盘上升均为巨蟹座,本次未满足。", "Satabdika requires a vargottama Ascendant (same Rasi and Navamsa sign).": "该大运要求本命及九分盘上升同星座,本次未满足。", "Chaturshitisama requires the 10th lord to occupy the 10th house.": "该大运要求第十宫主星位于第十宫,本次未满足。", "Shastihayani requires Sun in the Lagna sign.": "该大运要求太阳位于上升星座,本次未满足。", } REASON_LABELS_EN = { "patyayini_dasha_missing": "This calculation did not provide the Patyayini annual periods, so they cannot be used for timing checks yet.", "The Shodashottari hora-plus-paksha applicability gate is not met.": "The Hora and lunar-fortnight (Paksha) condition for this dasha is not met.", "This profile requires Navamsa Lagna in Taurus or Libra.": "This dasha requires the Navamsa Lagna in Taurus or Libra; not met here.", "Dwisaptatisama requires Lagna lord in the 1st or 7th house.": "This dasha requires the Lagna lord in the 1st or 7th house; not met here.", "Panchottari requires a Cancer Ascendant that is also Cancer in Dwadasamsa.": "This dasha requires a Cancer Lagna in both the birth chart and the Dwadasamsa; not met here.", "Satabdika requires a vargottama Ascendant (same Rasi and Navamsa sign).": "This dasha requires a Vargottama Lagna (same sign in Rasi and Navamsa); not met here.", "Chaturshitisama requires the 10th lord to occupy the 10th house.": "This dasha requires the 10th lord in the 10th house; not met here.", "Shastihayani requires Sun in the Lagna sign.": "This dasha requires the Sun in the Lagna sign; not met here.", } _TEXT = { "zh": { "boundary": BOUNDARY, "missing": MISSING, "ashtottari": "月宿与月相组合未满足该大运的适用条件,不绕过判定。", "unknown_reason": "计算返回了限制原因,但暂无可核对的详细说明;不据此补写适用条件或日期。", "heading": "## 辅助时间轴适用性(参数敏感)", "table_head": ["| 大运族 | 是否适用 / 原因 | 使用边界 |", "| --- | --- | --- |"], "not_applicable": "本次不适用,不绕过原适用条件,不补写日期。", "unavailable": "本次不可用:本地计算尚未提供可用周期,不能据此判断时间。", "has_periods": "本次已返回周期,可作交叉核对;这不代表已完成多引擎验证。", "unverified": "本次适用性尚未核实,缺少可核对周期,不补写日期。", "applicable_true": " 原适用性判定:适用。", "reasons_prefix": " 原因:", "reasons_joiner": ";", }, "en": { "boundary": "Secondary timeline for cross-checking only; does not set event timing on its own", "missing": "This calculation carries no structured applicability evidence, so it cannot confirm whether each auxiliary timeline applies; no periods or dates are filled in.", "ashtottari": "The Moon's nakshatra and lunar phase do not meet this dasha's applicability condition; the rule is not bypassed.", "unknown_reason": "The calculation returned a restriction without a checkable explanation; no condition or date is inferred from it.", "heading": "## Auxiliary Dasha Applicability (reference only)", "table_head": ["| Dasha system | Applicable? / Reason | Use |", "| --- | --- | --- |"], "not_applicable": "Not applicable for this chart; the original condition is not bypassed and no dates are filled in.", "unavailable": "Unavailable: the local calculation has not produced usable periods, so it cannot be used for timing.", "has_periods": "Periods were returned and can be used for cross-checking; this does not mean multi-engine verification is complete.", "unverified": "Applicability not yet verified and no checkable periods are available; no dates are filled in.", "applicable_true": " Original applicability verdict: applicable.", "reasons_prefix": " Reason: ", "reasons_joiner": "; ", }, } def _language(value): return "en" if value == "en" else "zh" def _reader_reason(value, language="zh"): labels = REASON_LABELS_EN if language == "en" else REASON_LABELS if value in labels: return labels[value] if value.startswith("Moon Nakshatra '") and "does not qualify for Ashtottari Dasha under " in value: return _TEXT[language]["ashtottari"] return _TEXT[language]["unknown_reason"] def _has_periods(key, raw, source): fields = ("periods", "major") + (("mahadasha_sequence", "dense_boundaries") if key == "narayana" else ()) return any(isinstance(data.get(field), (list, dict)) and bool(data[field]) for data in (raw, source) for field in fields) def _cell(value, language="zh"): text = str(value).replace("\r", " ").replace("\n", " ") if language == "en": return text.replace("|", "/").replace("<", "‹").replace(">", "›") return text.replace("|", "/").replace("<", "<").replace(">", ">") def render_dasha_applicability(packet, language="zh"): language = _language(language) text = _TEXT[language] timing = packet.get("worksheets", {}).get("timing_and_predictive_systems", {}) master = timing.get("dasha_master_pack", {}) families = master.get("families", {}) lines = ["", text["heading"], ""] if not isinstance(families, dict) or not families: return "\n".join(lines + [text["missing"], ""]) families = dict(families) annual = timing.get("annual_tajika_pack", {}) for key, value in annual.items(): if key.endswith("_dasha"): families.setdefault(key.removesuffix("_dasha"), value) lines += text["table_head"] for key in sorted(families): if key == "vimshottari": continue raw = families[key] if isinstance(families[key], dict) else {} source_key = "kalachakra_dasha" if key == "kala_chakra" else f"{key}_dasha" source = timing.get(source_key, {}) source = source if isinstance(source, dict) else {} status = raw.get("status", raw.get("execution_status")) applicable = source.get("applicable", raw.get("applicable")) if applicable is False or status == "not_applicable": reason = text["not_applicable"] elif status in {"blocked", "missing_in_local", "unavailable"}: reason = text["unavailable"] elif _has_periods(key, raw, source): reason = text["has_periods"] else: reason = text["unverified"] if applicable is True: reason += text["applicable_true"] reasons = list(dict.fromkeys(_reader_reason(str(value), language) for value in (raw.get("reason"), source.get("reason")) if value)) if reasons: reason += text["reasons_prefix"] + text["reasons_joiner"].join(reasons) name = "Kala Chakra" if key == "kala_chakra" else key.replace("_", "-").title() lines.append(f"| {_cell(name, language)} | {_cell(reason, language)} | {text['boundary']} |") return "\n".join(lines) + "\n"