""" Tests that EN and DE locale files are consistent. """ from padelnomics.i18n import _CALC_ITEM_NAMES, _TRANSLATIONS, SUPPORTED_LANGS # Keys with identical EN/DE values are acceptable — financial abbreviations, # month abbreviations, English brand names used in German, and UI chrome # that intentionally stays English in DE (Dashboard, Admin, Feedback). _IDENTICAL_VALUE_ALLOWLIST = { # Financial / technical abbreviations (same in DE) "card_cash_on_cash", "card_irr", "card_moic", "card_rev_pah", "th_dscr", "th_ebitda", "wf_moic", "wiz_capex", "wiz_irr", # Month abbreviations (same in DE: Jan, Feb, Apr, Jun, Jul, Aug, Sep, Nov) "month_jan", "month_feb", "month_apr", "month_jun", "month_jul", "month_aug", "month_sep", "month_nov", # Indoor / Outdoor (English terms used in DE) "label_indoor", "label_outdoor", "toggle_indoor", "toggle_outdoor", "features_card_3_h2", "landing_feature_3_h3", "q1_facility_indoor", "q1_facility_outdoor", "q1_facility_both", # Revenue streams and product labels (English terms used in DE) "stream_coaching", "stream_fb", "pill_light_led_standard", "q1_lighting_led_std", # Plan names (brand names, same in DE) "sup_basic_name", "sup_growth_name", "sup_pro_name", "suppliers_basic_name", "suppliers_growth_name", "suppliers_pro_name", "dir_card_featured", "dir_card_growth", "dir_cat_software", # Supplier boost option names "sup_boost_logo", "sup_boost_sticky", "sup_boosts_h3", # Comparison table headers that use English terms in DE "sup_cmp_th_ads", "sup_cmp_th_us", # Problem section heading — "Google Ads" is a brand name "sup_prob_ads_h3", "suppliers_problem_2_h3", # Budget/lead labels that are English in DE "sup_lead_budget", "suppliers_leads_budget", # UI chrome that stays English in DE "nav_admin", "nav_dashboard", "nav_feedback", # Country names that are the same "country_uk", "country_us", "dir_country_CN", "dir_country_PT", "dir_country_TH", # Optional annotation "q9_company_note", # Dashboard chrome that stays English in DE (brand term) "dash_page_title", "dash_h1", "dash_name_label", # Supplier dashboard — analytics brand name "sd_ov_via_umami", # Lead heat filter labels (English terms used in DE) "sd_leads_filter_hot", "sd_leads_filter_warm", "sd_leads_filter_cool", # "Budget", "Name", "Phase", "Investor" — same in both languages "sd_leads_budget", "sd_card_budget", "sd_unlocked_label_budget", "sd_unlocked_label_name", "sd_unlocked_label_phase", "sd_stakeholder_investor", # Email lead forward labels — "Phase" and "Name" are identical in DE "email_lead_forward_lbl_phase", "email_lead_forward_lbl_name", # Listing form labels that are English brand terms / same in DE "sd_lst_logo", "sd_lst_website", # Boost option name — "Logo" is the same in DE "sd_boost_logo_name", # Business plan — Indoor/Outdoor same in DE, financial abbreviations "bp_indoor", "bp_outdoor", "bp_lbl_ebitda", "bp_lbl_irr", "bp_lbl_moic", "bp_lbl_opex", # Market Score — branded term kept in English in DE "footer_market_score", # Market Score chip labels — branded product names, same in DE "mscore_reife_chip", "mscore_potenzial_chip", } def test_en_de_key_parity(): """EN and DE must have identical key sets.""" en_keys = set(_TRANSLATIONS["en"].keys()) de_keys = set(_TRANSLATIONS["de"].keys()) en_only = en_keys - de_keys de_only = de_keys - en_keys assert not en_only, f"Keys in EN but not DE: {sorted(en_only)}" assert not de_only, f"Keys in DE but not EN: {sorted(de_only)}" def test_all_values_non_empty(): """No translation value should be an empty string.""" for lang in SUPPORTED_LANGS: for key, value in _TRANSLATIONS[lang].items(): assert value, f"Empty value for key {key!r} in lang {lang!r}" def test_no_untranslated_copy_paste(): """No key should have an identical EN and DE value (catches missed translations). Some keys are exempt — see _IDENTICAL_VALUE_ALLOWLIST. """ en = _TRANSLATIONS["en"] de = _TRANSLATIONS["de"] violations = [] for key in en: if key in _IDENTICAL_VALUE_ALLOWLIST: continue if en[key] == de[key]: violations.append((key, en[key])) assert not violations, ( "Keys with identical EN/DE values (likely untranslated): " + ", ".join(f"{k!r}={v!r}" for k, v in violations[:10]) + (f" ... and {len(violations) - 10} more" if len(violations) > 10 else "") ) def test_calc_item_names_key_parity(): """EN and DE calc item names must have identical key sets.""" en_keys = set(_CALC_ITEM_NAMES["en"].keys()) de_keys = set(_CALC_ITEM_NAMES["de"].keys()) assert en_keys == de_keys, ( f"Calc item key mismatch — " f"EN-only: {sorted(en_keys - de_keys)}, DE-only: {sorted(de_keys - en_keys)}" ) def test_calc_item_names_non_empty(): """No calc item name should be empty.""" for lang in SUPPORTED_LANGS: for key, value in _CALC_ITEM_NAMES[lang].items(): assert value, f"Empty calc item name for key {key!r} in lang {lang!r}"