Best-effort UI translation (EN ⇄ EL) applied only to visible text nodes. Goals: - Avoid breaking attributes/URLs (e.g., logo src) by never doing whole-document replaces. - Keep specific labels as requested: * Theme button text must stay exactly: 'Theme' * Languag
(resp)
| 2974 | |
| 2975 | out = txt |
| 2976 | |
| 2977 | if lang == "el": |
| 2978 | # Only bother if it looks like English text |
| 2979 | if any("a" <= ch.lower() <= "z" for ch in out): |
| 2980 | out = _apply_phrase_map(out, "el") |
| 2981 | else: |
| 2982 | # lang == "en" |
| 2983 | if any("\u0370" <= ch <= "\u03FF" for ch in out): |
| 2984 | out = _apply_phrase_map(out, "en") |
| 2985 | |
| 2986 | return ">" + out + "<" |
| 2987 | |
| 2988 | return _TEXT_NODE_RE.sub(repl, body) |
| 2989 | |
| 2990 | # --- Attribute translation (title/placeholder/aria-label) --------------------- |
| 2991 | # The HTML text-node translator does not touch attributes. That caused mixed EN/EL |
| 2992 | # tooltips/placeholders (e.g., delivery ticks) in Greek mode. |
| 2993 | _ATTR_RE = re.compile(r'\b(title|aria-label|placeholder|data-bs-original-title|data-bs-title|data-open|data-closed|alt)="([^"]*)"') |
| 2994 | |
| 2995 | def _translate_common_attributes(body: str, lang: str) -> str: |
| 2996 | """Translate common UI attributes in rendered HTML (best-effort). |
| 2997 | |
| 2998 | We only touch a small, safe set of attributes: |
| 2999 | - title |
| 3000 | - aria-label |
| 3001 | - placeholder |
| 3002 | |
| 3003 | We intentionally skip values that contain 'ButSystem' to keep |
| 3004 | the brand label unchanged. |
| 3005 | """ |
| 3006 | def _attr_repl(m): |
| 3007 | attr = m.group(1) |
| 3008 | val = m.group(2) |
| 3009 | |
| 3010 | # Skip empty / template-like |
| 3011 | if not val or "{{" in val or "{%" in val: |
| 3012 | return m.group(0) |
| 3013 | |
| 3014 | # Keep brand label |
| 3015 | if "ButSystem" in val: |
| 3016 | return m.group(0) |
| 3017 | |
| 3018 | out = val |
| 3019 | if lang == "el": |
| 3020 | if any("a" <= ch.lower() <= "z" for ch in out): |
| 3021 | out = _apply_phrase_map(out, "el") |
| 3022 | else: |
| 3023 | if any("\u0370" <= ch <= "\u03FF" for ch in out): |
| 3024 | out = _apply_phrase_map(out, "en") |
| 3025 | |
| 3026 | return f'{attr}="{out}"' |
| 3027 | |
| 3028 | return _ATTR_RE.sub(_attr_repl, body) |
| 3029 | |
| 3030 | # ----------------------------------------------------------------------------- |
| 3031 | |
| 3032 | def get_lang() -> str: |
| 3033 | """get_lang. |
nothing calls this directly
no test coverage detected